diff --git a/DEPS b/DEPS
index 7d3adeff..f41dacaa 100644
--- a/DEPS
+++ b/DEPS
@@ -305,11 +305,11 @@
   # 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': 'e49995f780d7d67f9fc46b290e83d3a6485cb6c8',
+  'src_internal_revision': '2571356975131fd1444e99fc272b03ed4e92ea8e',
   # 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': '93e2cb6281cb04bcc3d30bdb36af9b259b322480',
+  'skia_revision': 'b842026480e0d5e5547e5d6359a6a44e5692aff1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -317,7 +317,7 @@
   # 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': '538129c6b3c17dc864101c7a4af4b74b00706f82',
+  'angle_revision': 'f6b74ac4a5d4c6ff43f9da1fa7ded6c5d1a4cceb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -377,7 +377,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
-  'crossbench_revision': '4dbf27cac51cdece9e1e2915dfad799f7a16e839',
+  'crossbench_revision': '7fad92a8c43e08847134eef473d56fa7044fc989',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
@@ -421,7 +421,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'da556b4eb39e603729869c3eedbedd8643e1518e',
+  'dawn_revision': 'd7279f397e6c79fd4b1c1c3fdf5b524991dd7a71',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -445,7 +445,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': 'c432b1a49a597356e2bbe93e63de7a25db01cc7a',
+  'jetstream_main_revision': 'a26d33b5df562cbab0887e1ec5d05950aeb3e76a',
   # 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.
@@ -1190,7 +1190,7 @@
       'packages': [
           {
               'package': 'chromium/chrome/android/orderfiles/arm',
-              'version': 'gSKKtpM6dqrexRGIiJLuVu-wasC-2IwHtMaVdZOstPsC',
+              'version': '3K3js4lNdnQtPQ0-xMCB7N_yGuhbw3P-C6J-A-QpYnkC',
           },
       ],
       'condition': 'checkout_android',
@@ -1201,7 +1201,7 @@
       'packages': [
           {
               'package': 'chromium/chrome/android/orderfiles/arm64',
-              'version': '5zIItb1qq8vGT1q_VYw7H2sXNuhteTIzoJZbAPehGhkC',
+              'version': 'k_D-5FfDR12EBjkomCM-nNOgkvUmFQzfs9qwiBRzVeIC',
           },
       ],
       'condition': 'checkout_android',
@@ -1223,7 +1223,7 @@
       'packages': [
           {
               'package': 'chromium/android_webview/tools/orderfiles/arm64',
-              'version': 'uUdsv-WfW_kO-oO5KHLYqJZo9RzJTuzgqJ_8Q1haP50C',
+              'version': 'OEKDsmaCX-X2zuorG55w6gPc5QnuAw1TyPEHtRN9BXgC',
           },
       ],
       'condition': 'checkout_android',
@@ -1608,7 +1608,7 @@
     'packages': [
       {
         'package': 'chromium/chrome/test/data/variations/cipd',
-        'version': '57swhAIsKWt3DrGG0yq3HH5azkHUtzXNWaRJ9aFCVtUC',
+        'version': 'lP9zv07ziLDitmV5B7usZoVOQFNAsHyqGY9sZKSZRkAC',
       },
     ],
     'dep_type': 'cipd',
@@ -1619,7 +1619,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '8c25644608a17fa7f7a4ff87f9b99e9f2b5b1953',
+    '39126c5ac8a45b997af69d2be128b80acb112d5d',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1719,7 +1719,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'f4JcOA4ipRRxZERfj-2B0SbI6tsQe626K53YPBsQpEEC',
+          'version': '25iSyr6f9m25hpVJaG6JnXFF-_-9EHmn6GZmD8M9GyoC',
       },
     ],
     'condition': 'checkout_android and non_git_source',
@@ -1746,7 +1746,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/android_build_tools/aapt2',
-              'version': 'vtRNH1sTb9tAlXaPkdqGIH_MDSnuH2GrlWFtT1MhadUC',
+              'version': 'XqcH9BN43Trcigbh3gSdKc-5OAI-r7MV7wIs5fRXxFMC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -1812,7 +1812,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/lint',
-               'version': '8LWaxlDPUdoe_fYqlHBXPmwm6aQsqP8Mi4kxGFFmfmkC',
+               'version': '3QcVzxF6pQW8pak81zGzUciRaonUh1NpS3UBjZZfVTsC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -1823,7 +1823,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/manifest_merger',
-               'version': 'n1GI7ejyMFXpOv359jDyoMovbtfsy1R4zjVCEDPp8CQC',
+               'version': '4cITVa3bS61rDFtbh_QoflvqlRrM-KrtViIyD4QEgjYC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -2055,7 +2055,7 @@
     Var('chromium_git') + '/chromium/web-tests.git' + '@' + Var('crossbench_web_tests_revision'),
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9fd9d31f9441c754dd8860bfea7ca1be7833eaae',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'e4185d003f9c08cb49edcb593212481db59d9a54',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -2605,7 +2605,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '04a02eb5f60c25daf3a07fbfa3aefeef366760d3',
+    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '69bd8a4b80aca14a9f07b5443572bb34150e496c',
 
   'src/base/tracing/test/data': {
     'bucket': 'perfetto',
@@ -2924,7 +2924,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@7d9b006a1969c0b9f713373084935addfdd8d994',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@edacf5135c8db8f952c32279bc4a0afcb5bde5a7',
   'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@a57276bf558f5cf94d3a9854ebdf5a2236849a5a',
   'src/third_party/spirv-cross/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Cross@b8fcf307f1f347089e3c46eb4451d27f32ebc8d3',
   'src/third_party/spirv-headers/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Headers@01e0577914a75a2569c846778c2f93aa8e6feddd',
@@ -2933,7 +2933,7 @@
   'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@ae0461b671558197a9a50e5fcfcc3b2d3f406b42',
   'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@5568ce14705e512113df5b459fc86d857b3d7789',
   'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@4d0b838ffcf1ef81151f0e7e11fad1d9ff859813',
-  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@dc5dea72aba1c3d1e27a4db2bb68acb0f62d336a',
+  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@cc388e801f874ed61e6c78bb1403d24e011255ab',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'cb0597213b0fcb999caa9ed08c2f88dc45eb7d50',
@@ -2976,7 +2976,7 @@
     Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'),
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '49ed5557b49af2b6d7729b8cbfab1900384abf1e',
+    Var('webrtc_git') + '/src.git' + '@' + '39e1a7ca166e88e458205d295b52e2360e86d400',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -3098,7 +3098,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/boca_receiver_app/app',
-        'version': 'A2d7FZFA_M7uUg8mxX1d9DWp_csjT3uEawlJsK9Lo5oC',
+        'version': '9Da-gPQit0F2FRzvv1g7mZyEo1zJsLboydvl3a8cKtwC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3109,7 +3109,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/boca_app/app',
-        'version': 'X0vnC6qhmR756D0OPZKXy9A6--P00MLhP4jSHAHlWJAC',
+        'version': 'BrD-zgFoMBAIsuVl47czpcuFsRSiu_Q-JOjmvnAh4a0C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3164,7 +3164,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'XYnlsWtxI7M348jswIiBX8RR17wcsk-UijVKfn1QkBwC',
+        'version': 'XPU-v2QkbAlBRQ7GKOm4fLnf05icvgzWbRDMEKYMlLoC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3191,7 +3191,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/autorolled',
-              'version': 'qR7IS1-GYP447dHXzKIWvUwI0SEpNGfKzlU-3AJSoU8C',
+              'version': 'X9D-ObbadP8UmRikGrTiAE7AgxKmxBUgUQSmQ97aGrcC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -3685,7 +3685,7 @@
 
   'src/components/optimization_guide/internal': {
       'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' +
-        '121111e1da731354279a3a26eba358d38f4a34f9',
+        '20c4cc39d64f47cd19ec46b550ec6cbbf0951ed7',
       'condition': 'checkout_src_internal',
   },
 
@@ -3757,7 +3757,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        '77b7d99bb2c3d0809ca87fd517282901bc017060',
+        '484637bf993d755b82ff1501b415a4abb8eb6fe7',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 553dba06..74b6b7c 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -125,9 +125,8 @@
     # Explanation as a sequence of strings. Each string in the sequence will be
     # printed on its own line.
     explanation: Tuple[str, ...]
-    # Whether or not to treat this ban as a fatal error. If unspecified,
-    # defaults to true.
-    treat_as_error: Optional[bool] = None
+    # Whether or not to treat this ban as a fatal error.
+    treat_as_error: bool = False
     # Paths that should be excluded from the ban check. Each string is a regular
     # expression that will be matched against the path of the file being checked
     # relative to the root of the source tree.
@@ -142,6 +141,7 @@
         'import java.net.URI;',
         ('Use org.chromium.url.GURL instead of java.net.URI, where possible.',
          ),
+        True,
         excluded_paths=(
             (r'net/android/javatests/src/org/chromium/net/'
              r'AndroidProxySelectorTest\.java'),
@@ -154,11 +154,13 @@
         ('Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
          'RequiresApi ensures that any calls are guarded by the appropriate '
          'SDK_INT check. See https://crbug.com/1116486.', ),
+        True
     ),
     BanRule(
         'import androidx.test.rule.ActivityTestRule;',
         ('Do not use ActivityTestRule, use '
          'org.chromium.base.test.BaseActivityTestRule instead.', ),
+        True,
         excluded_paths=('components/cronet/', ),
     ),
     BanRule(
@@ -166,6 +168,13 @@
         ('Do not use VectorDrawableCompat, use getResources().getDrawable() '
          'to avoid extra indirections. Please also add trace event as the call '
          'might take more than 20 ms to complete.', ),
+        True,
+    ),
+    BanRule(
+        'import java.util.Optional',
+        ('Prefer @Nullable over Optional/OptionalInt/OptionalDouble/etc. See '
+         '//styleguide/java/java.md',),
+        False,
     ),
 )
 
@@ -2891,8 +2900,8 @@
     return result
 
 
-def CheckNoBannedFunctions(input_api, output_api):
-    """Make sure that banned functions are not used."""
+def CheckNoBannedPatterns(input_api, output_api):
+    """Make sure that banned patterns are not used."""
     results = []
 
     def IsExcludedFile(affected_file, excluded_paths):
@@ -2934,22 +2943,22 @@
                         start_line=line_num,
                         end_line=line_num,
                     ))
-            if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
+            if ban_rule.treat_as_error:
                 results.append(
-                    output_api.PresubmitError('A banned function was used.\n' +
+                    output_api.PresubmitError('A banned pattern was used.\n' +
                                               '\n'.join(message),
                                               locations=result_loc))
 
             else:
                 results.append(
                     output_api.PresubmitPromptWarning(
-                        'A banned function was used.\n' + '\n'.join(message),
+                        'A banned pattern was used.\n' + '\n'.join(message),
                         locations=result_loc))
 
     file_filter = lambda f: f.LocalPath().endswith(('.java'))
     for f in input_api.AffectedFiles(file_filter=file_filter):
         for line_num, line in f.ChangedContents():
-            for ban_rule in _BANNED_JAVA_FUNCTIONS:
+            for ban_rule in _BANNED_JAVA_FUNCTIONS + _BANNED_JAVA_IMPORTS:
                 CheckForMatch(f, line_num, line, ban_rule)
 
     file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
@@ -3011,32 +3020,8 @@
     return results
 
 
-def _CheckAndroidNoBannedImports(input_api, output_api):
-    """Make sure that banned java imports are not used."""
-    errors = []
-
-    file_filter = lambda f: f.LocalPath().endswith(('.java'))
-    for f in input_api.AffectedFiles(file_filter=file_filter):
-        for line_num, line in f.ChangedContents():
-            for ban_rule in _BANNED_JAVA_IMPORTS:
-                # Consider merging this into the above function. There is no
-                # real difference anymore other than helping with a little
-                # bit of boilerplate text. Doing so means things like
-                # `treat_as_error` will also be uniformly handled.
-                problems = _GetMessageForMatchingType(input_api, f, line_num,
-                                                      line, ban_rule)
-                if problems:
-                    errors.extend(problems)
-    result = []
-    if (errors):
-        result.append(
-            output_api.PresubmitError('Banned imports were used.\n' +
-                                      '\n'.join(errors)))
-    return result
-
-
 def CheckNoPragmaOnce(input_api, output_api):
-    """Make sure that banned functions are not used."""
+    """Make sure #pragma once is not used."""
     files = []
     pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
     for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
@@ -5888,7 +5873,6 @@
     results.extend(_CheckAndroidWebkitImports(input_api, output_api))
     results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
     results.extend(_CheckNewImagesWarning(input_api, output_api))
-    results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
     results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
     results.extend(_CheckAndroidNullAwayAnnotatedClasses(
         input_api, output_api))
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py
index 1c64ec7..b4edc116 100755
--- a/PRESUBMIT_test.py
+++ b/PRESUBMIT_test.py
@@ -1486,25 +1486,25 @@
         for file in test_files:
             mock_input_api.files = [file]
             msgs.append(
-                PRESUBMIT._CheckAndroidNoBannedImports(mock_input_api,
-                                                       mock_output_api))
+                PRESUBMIT.CheckNoBannedPatterns(mock_input_api,
+                                                mock_output_api))
         self.assertEqual(0, len(msgs[0]))
         self.assertEqual(0, len(msgs[1]))
         self.assertTrue(msgs[2][0].message.startswith(
             textwrap.dedent("""\
-      Banned imports were used.
+      A banned pattern was used.
           BannedUri.java:1:""")))
         self.assertTrue(msgs[3][0].message.startswith(
             textwrap.dedent("""\
-      Banned imports were used.
+      A banned pattern was used.
           BannedTargetApi.java:1:""")))
         self.assertTrue(msgs[4][0].message.startswith(
             textwrap.dedent("""\
-      Banned imports were used.
+      A banned pattern was used.
           BannedActivityTestRule.java:1:""")))
         self.assertTrue(msgs[5][0].message.startswith(
             textwrap.dedent("""\
-      Banned imports were used.
+      A banned pattern was used.
           BannedVectorDrawableCompat.java:1:""")))
 
 
@@ -2938,7 +2938,7 @@
             MockFile('some/js/ok/file.js', ['chrome.send(something);']),
         ]
 
-        results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
+        results = PRESUBMIT.CheckNoBannedPatterns(input_api, MockOutputApi())
 
         self.assertEqual(1, len(results))
         self.assertTrue('ash/webui/file.js' in results[0].message)
@@ -2987,7 +2987,7 @@
                 ]),
         ]
 
-        errors = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
+        errors = PRESUBMIT.CheckNoBannedPatterns(input_api, MockOutputApi())
         self.assertEqual(14, len(errors))
         self.assertTrue(
             'some/java/problematic/diskread.java' in errors[0].message)
@@ -3069,7 +3069,7 @@
             ]),
         ]
 
-        results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
+        results = PRESUBMIT.CheckNoBannedPatterns(input_api, MockOutputApi())
 
         # Each entry in results corresponds to a BanRule with a violation, in
         # the order they were encountered.
@@ -3126,7 +3126,7 @@
                          [f'{banned_rng} engine;']),
                 MockFile('third_party/ok/file.cc', [f'{banned_rng} engine;']),
             ]
-            results = PRESUBMIT.CheckNoBannedFunctions(input_api,
+            results = PRESUBMIT.CheckNoBannedPatterns(input_api,
                                                        MockOutputApi())
             self.assertEqual(2, len(results), banned_rng)
             self.assertTrue(
@@ -3154,7 +3154,7 @@
             ]),
         ]
 
-        errors = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
+        errors = PRESUBMIT.CheckNoBannedPatterns(input_api, MockOutputApi())
         self.assertEqual(3, len(errors))
         self.assertTrue('some/ios/file.mm' in errors[0].message)
         self.assertTrue('another/ios_file.mm' in errors[1].message)
@@ -3170,7 +3170,7 @@
             MockFile('content/renderer/ok/file3.cc', ['mojo::ConvertTo<>']),
         ]
 
-        results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
+        results = PRESUBMIT.CheckNoBannedPatterns(input_api, MockOutputApi())
 
         # Each entry in results corresponds to a BanRule with a violation, in
         # the order they were encountered.
@@ -3195,7 +3195,7 @@
             ]),
         ]
 
-        results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
+        results = PRESUBMIT.CheckNoBannedPatterns(input_api, MockOutputApi())
 
         # Each entry in results corresponds to a BanRule with a violation, in
         # the order they were encountered.
@@ -3223,7 +3223,7 @@
 
         # Each entry in results corresponds to a BanRule with a violation, in
         # the order they were encountered.
-        results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
+        results = PRESUBMIT.CheckNoBannedPatterns(input_api, MockOutputApi())
 
         self.assertEqual(3, len(results))
 
@@ -5799,7 +5799,7 @@
                      ['IsSyncFeatureActive']),
         ]
 
-        results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
+        results = PRESUBMIT.CheckNoBannedPatterns(input_api, MockOutputApi())
 
         self.assertEqual(7, len(results))
         self.assertTrue(all('chrome/browser/android/file.cc' not in r.message for r in results))
@@ -5823,7 +5823,7 @@
             MockFile('components/kiosk/file.cc', ['HasSyncConsent']),
         ]
 
-        results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
+        results = PRESUBMIT.CheckNoBannedPatterns(input_api, MockOutputApi())
 
         self.assertEqual(0, len(results))
 
@@ -5837,7 +5837,7 @@
             MockFile('chrome/foo/file5.java', ['isSyncFeatureActive']),
         ]
 
-        results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
+        results = PRESUBMIT.CheckNoBannedPatterns(input_api, MockOutputApi())
 
         self.assertEqual(4, len(results))
         self.assertTrue(all('components/foo/file1.java' not in r.message for r in results))
@@ -5860,7 +5860,7 @@
             MockFile('chrome/test.txt', ['namespace {']),
         ]
 
-        results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
+        results = PRESUBMIT.CheckNoBannedPatterns(input_api, MockOutputApi())
 
         self.assertEqual(1, len(results))
         self.assertTrue(
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 1a830c7..c3129d2 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
@@ -478,10 +478,6 @@
                 "WebRtcEncodedTransformDirectCallback",
                 "Directly invoke WebRTC Encoded Transform callbacks in a worker."),
         Flag.baseFeature(
-                "RTCAlignReceivedEncodedVideoTransforms",
-                "Aligns the JS calls by WebRTC Encoded Transforms on Video Frames with a Metronome"
-                        + " to save power."),
-        Flag.baseFeature(
                 "WebRtcAudioSinkUseTimestampAligner",
                 "Align WebRTC and Chrome clocks using a timestamp aligner for absolute capture"
                         + " times in Audio RTP packets."),
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index fb9ba0c..d0a048b 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -1246,9 +1246,6 @@
 // Used in finch experiment.
 BASE_FEATURE(kIppFirstSetupForUsbPrinters, base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Enables OS Settings page for japanese.
-BASE_FEATURE(kJapaneseOSSettings, base::FEATURE_DISABLED_BY_DEFAULT);
-
 // Enables Romaji/Kana mode switch for Japanese VK.
 BASE_FEATURE(kJapaneseInputModeSwitchInVK, base::FEATURE_DISABLED_BY_DEFAULT);
 
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 9c023e64..8def5fa 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -576,8 +576,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kIppFirstSetupForUsbPrinters);
 COMPONENT_EXPORT(ASH_CONSTANTS)
-BASE_DECLARE_FEATURE(kJapaneseOSSettings);
-COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kJapaneseInputModeSwitchInVK);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kJupiterScreensaver);
 COMPONENT_EXPORT(ASH_CONSTANTS)
diff --git a/ash/wm/lock_state_controller.cc b/ash/wm/lock_state_controller.cc
index 4ba80e0b..a21b99e 100644
--- a/ash/wm/lock_state_controller.cc
+++ b/ash/wm/lock_state_controller.cc
@@ -216,6 +216,12 @@
         ScreenshotOnShutdownStatus::kFailedInLockScreen);
     return false;
   }
+  if (session_controller->GetSessionState() !=
+      session_manager::SessionState::ACTIVE) {
+    RecordScreenshotOnShutdownStatus(
+        ScreenshotOnShutdownStatus::kFailedSessionIsNotActive);
+    return false;
+  }
   if (session_controller->IsUserGuest() ||
       session_controller->IsUserPublicAccount()) {
     RecordScreenshotOnShutdownStatus(
diff --git a/ash/wm/lock_state_controller_unittest.cc b/ash/wm/lock_state_controller_unittest.cc
index cdfcaafb..731cd3e45 100644
--- a/ash/wm/lock_state_controller_unittest.cc
+++ b/ash/wm/lock_state_controller_unittest.cc
@@ -1500,4 +1500,30 @@
           1)));
 }
 
+TEST_F(LockStateControllerInformedRestoreTest,
+       ScreenshotIsNotTakenWhenSessionIsNotActive) {
+  EXPECT_FALSE(base::PathExists(file_path()));
+
+  // Simulate user adding flow where user has entered their password, but the UI
+  // is still visible (e.g., PIN setup screen).
+  AshTestBase::GetSessionControllerClient()->SetSessionState(
+      session_manager::SessionState::LOGIN_PRIMARY);
+
+  base::HistogramTester histogram_tester;
+
+  base::RunLoop run_loop;
+  lock_state_test_api_->set_informed_restore_image_callback(
+      run_loop.QuitClosure());
+  // Disable the timeout to avoid test flakiness.
+  lock_state_test_api_->disable_screenshot_timeout_for_test(true);
+
+  lock_state_controller_->RequestSignOut();
+  run_loop.Run();
+  EXPECT_FALSE(base::PathExists(file_path()));
+
+  EXPECT_THAT(histogram_tester.GetAllSamples(kScreenshotOnShutdownStatus),
+              testing::ElementsAre(base::Bucket(
+                  ScreenshotOnShutdownStatus::kFailedSessionIsNotActive, 1)));
+}
+
 }  // namespace ash
diff --git a/ash/wm/window_restore/window_restore_metrics.h b/ash/wm/window_restore/window_restore_metrics.h
index 0fecece..4c7165d7 100644
--- a/ash/wm/window_restore/window_restore_metrics.h
+++ b/ash/wm/window_restore/window_restore_metrics.h
@@ -39,7 +39,8 @@
   kFailedInGuestOrPublicUserSession,
   kFailedOtherUserIsActive,
   kFailedWithVisibleWindowFromOtherUser,
-  kMaxValue = kFailedWithVisibleWindowFromOtherUser,
+  kFailedSessionIsNotActive,
+  kMaxValue = kFailedSessionIsNotActive,
 };
 
 // Enumeration of the ways the informed restore dialog could be closed. Used for
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
index 724dfff..d909f5b3 100755
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -538,7 +538,11 @@
         # ciopfs not found in PATH; try the one downloaded from the DEPS hook.
         ciopfs = os.path.join(script_dir, 'ciopfs')
       if not os.path.isdir(toolchain_dir):
-        os.mkdir(toolchain_dir)
+        try:
+          os.mkdir(toolchain_dir)
+        except FileExistsError:
+          # ciopfsd died, but fuse is still mounted.
+          subprocess.check_call(["fusermount", "-u", toolchain_dir])
       if not os.path.isdir(toolchain_dir + '.ciopfs'):
         os.mkdir(toolchain_dir + '.ciopfs')
       # Without use_ino, clang's #pragma once and Wnonportable-include-path
diff --git a/buildtools/third_party/libc++/modules.gni b/buildtools/third_party/libc++/modules.gni
index 7793a88..a4d2635 100644
--- a/buildtools/third_party/libc++/modules.gni
+++ b/buildtools/third_party/libc++/modules.gni
@@ -5,6 +5,7 @@
 import("//build/config/apple/apple_sdk.gni")
 import("//build/config/c++/modules.gni")
 import("//build/config/clang/clang.gni")
+import("//build/config/compiler/compiler.gni")
 import("//build/config/sysroot.gni")
 if (use_xcode_symlinks) {
   import("//build/config/apple/mobile_config.gni")
@@ -90,6 +91,16 @@
       # The module needs to use the same version of -std that is used by the
       # libraries depending on it. Otherwise we get a module config mismatch.
       configs += configs_to_add - [ "//buildtools/third_party/libc++:stdver" ]
+
+      # Any complex target-specific logic needs to go in here.
+      # The modularize tool supports simple attributes, but not conditional
+      # logic.
+      if (target_name == "std_stdatomic_h" && use_cxx23) {
+        # In cxx23, stdatomic.h uses libcxx's stdatomic rather than the
+        # builtin.
+        public_deps -= [ ":_Builtin_stdatomic" ]
+        public_deps += [ ":std" ]
+      }
     }
   }
 
diff --git a/chrome/VERSION b/chrome/VERSION
index 13bf499..e2026a5 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=143
 MINOR=0
-BUILD=7449
+BUILD=7450
 PATCH=0
diff --git a/chrome/android/java/res/values/ids.xml b/chrome/android/java/res/values/ids.xml
index 267538c..f720733 100644
--- a/chrome/android/java/res/values/ids.xml
+++ b/chrome/android/java/res/values/ids.xml
@@ -45,6 +45,7 @@
     <item type="id" name="task_manager" />
     <item type="id" name="esc_key" />
     <item type="id" name="feedback_form" />
+    <item type="id" name="view_source" />
 
     <!-- Editor dialog -->
     <item type="id" name="editor_dialog_done_button" />
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java b/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java
index 17471ba..c1ac12a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java
@@ -106,7 +106,7 @@
         KeyboardShortcutsSemanticMeaning.NOT_IMPLEMENTED_DEV_TOOLS_CONSOLE,
         KeyboardShortcutsSemanticMeaning.NOT_IMPLEMENTED_DEV_TOOLS_INSPECT,
         KeyboardShortcutsSemanticMeaning.NOT_IMPLEMENTED_DEV_TOOLS_TOGGLE,
-        KeyboardShortcutsSemanticMeaning.NOT_IMPLEMENTED_VIEW_SOURCE,
+        KeyboardShortcutsSemanticMeaning.VIEW_SOURCE,
         KeyboardShortcutsSemanticMeaning.TASK_MANAGER,
         KeyboardShortcutsSemanticMeaning.SAVE_PAGE,
         KeyboardShortcutsSemanticMeaning.SHOW_DOWNLOADS,
@@ -192,7 +192,7 @@
         int NOT_IMPLEMENTED_DEV_TOOLS_CONSOLE = 38;
         int NOT_IMPLEMENTED_DEV_TOOLS_INSPECT = 39;
         int NOT_IMPLEMENTED_DEV_TOOLS_TOGGLE = 40;
-        int NOT_IMPLEMENTED_VIEW_SOURCE = 41;
+        int VIEW_SOURCE = 41;
         int TASK_MANAGER = 42;
 
         // Downloads.
@@ -633,6 +633,9 @@
 
         // Developer tools.
         new KeyboardShortcutDefinition(
+                KeyboardShortcutsSemanticMeaning.VIEW_SOURCE,
+                new KeyCombo(KeyEvent.KEYCODE_U, KeyEvent.META_CTRL_ON));
+        new KeyboardShortcutDefinition(
                 KeyboardShortcutsSemanticMeaning.DEV_TOOLS,
                 new KeyCombo(KeyEvent.KEYCODE_I, (KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)));
         new KeyboardShortcutDefinition(
@@ -741,9 +744,6 @@
                 KeyboardShortcutsSemanticMeaning.NOT_IMPLEMENTED_DEV_TOOLS_TOGGLE,
                 new KeyCombo(KeyEvent.KEYCODE_F12, NO_MODIFIER));
         new KeyboardShortcutDefinition(
-                KeyboardShortcutsSemanticMeaning.NOT_IMPLEMENTED_VIEW_SOURCE,
-                new KeyCombo(KeyEvent.KEYCODE_U, KeyEvent.META_CTRL_ON));
-        new KeyboardShortcutDefinition(
                 KeyboardShortcutsSemanticMeaning.NOT_IMPLEMENTED_BASIC_PRINT,
                 new KeyCombo(KeyEvent.KEYCODE_P, KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON));
         new KeyboardShortcutDefinition(
@@ -881,6 +881,13 @@
                     context,
                     shortcutGroupsById,
                     R.string.keyboard_shortcut_developer_group_header,
+                    R.string.keyboard_shortcut_view_source,
+                    KeyEvent.KEYCODE_U,
+                    KeyEvent.META_CTRL_ON);
+            addShortcut(
+                    context,
+                    shortcutGroupsById,
+                    R.string.keyboard_shortcut_developer_group_header,
                     R.string.keyboard_shortcut_developer_tools,
                     KeyEvent.KEYCODE_I,
                     (KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON));
@@ -1000,6 +1007,9 @@
                 } else {
                     break;
                 }
+            case KeyboardShortcutsSemanticMeaning.VIEW_SOURCE:
+                menuOrKeyboardActionController.onMenuOrKeyboardAction(R.id.view_source, false);
+                return true;
             case KeyboardShortcutsSemanticMeaning.DEV_TOOLS:
                 menuOrKeyboardActionController.onMenuOrKeyboardAction(R.id.dev_tools, false);
                 return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
index 50519d5b..cddd7cf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -2732,6 +2732,14 @@
             return true;
         }
 
+        if (id == R.id.view_source
+                && !currentTab.isNativePage()
+                && DevToolsWindowAndroid.canViewSource(
+                        currentTab.getProfile(), currentTab.getWebContents())) {
+            currentTab.getWebContents().getMainFrame().viewSource();
+            return true;
+        }
+
         if (id == R.id.dev_tools
                 && DevToolsWindowAndroid.isDevToolsAllowedFor(
                         currentTab.getProfile(), currentTab.getWebContents())) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
index 77485e8..1a39349 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -1690,10 +1690,7 @@
 
     @Override
     public boolean isInteractiveOmniboxEnabled() {
-        return ChromeFeatureList.sSearchInCCT.isEnabled()
-                && isPackageNameInList(
-                        getClientPackageName(),
-                        ChromeFeatureList.sSearchinCctOmniboxAllowedPackageNames.getValue());
+        return ChromeFeatureList.sSearchInCCT.isEnabled();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java
index 46a27643..2a10ee1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java
@@ -21,6 +21,7 @@
 import org.chromium.base.ApplicationStatus.ActivityStateListener;
 import org.chromium.base.ObserverList;
 import org.chromium.base.TraceEvent;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
@@ -222,7 +223,25 @@
         mBrowserVisibilityDelegate.addObserver(
                 (constraints) -> {
                     if (constraints == BrowserControlsState.SHOWN) {
-                        setPositionsForTabToNonFullscreen();
+                        // When compositor can drive the animation to show controls, do not call
+                        // setPositionsForTabToNonFullscreen to avoid control offset being forced
+                        // set to 0 before the render-driven animation kicks in.
+                        boolean allowRenderDrivenShowConstraint =
+                                ChromeFeatureList.sBrowserControlsRenderDrivenShowConstraint
+                                        .isEnabled();
+                        boolean renderDrivenShowConstraint =
+                                allowRenderDrivenShowConstraint
+                                        && canAnimateNativeBrowserControls();
+                        if (!renderDrivenShowConstraint) {
+                            setPositionsForTabToNonFullscreen();
+                        }
+
+                        // TODO(https://crbug.com/449011189): Maybe cleanup
+                        if (allowRenderDrivenShowConstraint) {
+                            RecordHistogram.recordBooleanHistogram(
+                                    "Android.BrowserControls.RenderDrivenShowConstraint",
+                                    renderDrivenShowConstraint);
+                        }
 
                         // If controls become locked, it's possible we've previously delayed
                         // actually setting visibility until a touch event is over. In this case, we
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java
index 08b7df1..ce38bf5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java
@@ -936,17 +936,41 @@
         int maxInstances = MultiWindowUtils.getMaxInstances();
         if (preferNew && MultiWindowUtils.getInstanceCount() < maxInstances) return windowId;
 
-        SparseIntArray windowIdsOfRunningTabbedActivities =
-                MultiInstanceManagerApi31.getWindowIdsOfRunningTabbedActivities();
-        for (int i : MultiInstanceManagerApi31.getAllPersistedInstanceIds()) {
-            // Exclude instance IDs of non-running activities.
-            if (windowIdsOfRunningTabbedActivities.indexOfValue(i) < 0) continue;
-            if (MultiWindowUtils.readLastAccessedTime(i)
-                    > MultiWindowUtils.readLastAccessedTime(windowId)) {
-                windowId = i;
+        return getLastAccessedWindowIdInternal(/* includeRunningActivitiesOnly= */ true);
+    }
+
+    /**
+     * @return The instance ID of the Chrome window that was last accessed. This will return {@code
+     *     INVALID_WINDOW_ID} if no persisted instance state is found.
+     */
+    public static int getLastAccessedWindowId() {
+        return getLastAccessedWindowIdInternal(/* includeRunningActivitiesOnly= */ false);
+    }
+
+    private static int getLastAccessedWindowIdInternal(boolean includeRunningActivitiesOnly) {
+        int lastAccessedWindowId = INVALID_WINDOW_ID;
+        long maxAccessedTime = 0;
+
+        SparseIntArray windowIdsOfRunningTabbedActivities = null;
+        if (includeRunningActivitiesOnly) {
+            windowIdsOfRunningTabbedActivities =
+                    MultiInstanceManagerApi31.getWindowIdsOfRunningTabbedActivities();
+        }
+
+        Set<Integer> persistedIds = MultiInstanceManagerApi31.getAllPersistedInstanceIds();
+
+        for (int id : persistedIds) {
+            if (includeRunningActivitiesOnly && windowIdsOfRunningTabbedActivities != null) {
+                if (windowIdsOfRunningTabbedActivities.indexOfValue(id) < 0) continue;
+            }
+
+            long accessedTime = readLastAccessedTime(id);
+            if (accessedTime > maxAccessedTime) {
+                maxAccessedTime = accessedTime;
+                lastAccessedWindowId = id;
             }
         }
-        return windowId;
+        return lastAccessedWindowId;
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxPedalsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxPedalsTest.java
index 8e17461..3e3dd55 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxPedalsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxPedalsTest.java
@@ -219,7 +219,8 @@
                     Tab tab = mActivityTestRule.getActivity().getActivityTab();
                     Criteria.checkThat(tab, Matchers.notNullValue());
                     Criteria.checkThat(
-                            tab.getUrl().getSpec(), Matchers.startsWith(UrlConstants.HISTORY_URL));
+                            tab.getUrl().getSpec(),
+                            Matchers.startsWith(UrlConstants.NATIVE_HISTORY_URL));
                 });
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProviderTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProviderTest.java
index 6433f35..95d7263 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProviderTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProviderTest.java
@@ -1228,9 +1228,7 @@
 
     @Test
     @EnableFeatures({ChromeFeatureList.SEARCH_IN_CCT})
-    public void isInteractiveOmniboxEnabled_originValidation() {
-        ChromeFeatureList.sSearchinCctOmniboxAllowedPackageNames.setForTesting(
-                "com.a.b.c|org.d.e.f");
+    public void isInteractiveOmniboxEnabled_flagEnabled() {
         CustomTabsConnection connection = Mockito.mock(CustomTabsConnection.class);
         CustomTabsConnection.setInstanceForTesting(connection);
 
@@ -1240,17 +1238,13 @@
         when(connection.getClientPackageNameForSession(any())).thenReturn("com.a.b.c");
         assertTrue(dataProvider.isInteractiveOmniboxEnabled());
 
-        when(connection.getClientPackageNameForSession(any())).thenReturn("org.d.e.f");
+        when(connection.getClientPackageNameForSession(any())).thenReturn(null);
         assertTrue(dataProvider.isInteractiveOmniboxEnabled());
-
-        when(connection.getClientPackageNameForSession(any())).thenReturn("com.d.e.f");
-        assertFalse(dataProvider.isInteractiveOmniboxEnabled());
     }
 
     @Test
     @DisableFeatures({ChromeFeatureList.SEARCH_IN_CCT})
-    public void isInteractiveOmniboxEnabled_featureDisabled() {
-        ChromeFeatureList.sSearchinCctOmniboxAllowedPackageNames.setForTesting("com.a.b.c");
+    public void isInteractiveOmniboxEnabled_flagDisabled() {
         CustomTabsConnection connection = Mockito.mock(CustomTabsConnection.class);
         CustomTabsConnection.setInstanceForTesting(connection);
 
@@ -1259,6 +1253,9 @@
 
         when(connection.getClientPackageNameForSession(any())).thenReturn("com.a.b.c");
         assertFalse(dataProvider.isInteractiveOmniboxEnabled());
+
+        when(connection.getClientPackageNameForSession(any())).thenReturn(null);
+        assertFalse(dataProvider.isInteractiveOmniboxEnabled());
     }
 
     @Test
@@ -1303,61 +1300,8 @@
     }
 
     @Test
-    @DisableFeatures({ChromeFeatureList.SEARCH_IN_CCT})
-    public void isInteractiveOmniboxEnabled_featureDisabled_returnsFalse() {
-        ChromeFeatureList.sSearchinCctOmniboxAllowedPackageNames.setForTesting(
-                "com.a.b.c|org.d.e.f");
-        CustomTabsConnection connection = Mockito.mock(CustomTabsConnection.class);
-        CustomTabsConnection.setInstanceForTesting(connection);
-
-        Intent intent = new CustomTabsIntent.Builder().build().intent;
-        var dataProvider = new CustomTabIntentDataProvider(intent, mContext, COLOR_SCHEME_LIGHT);
-
-        when(connection.getClientPackageNameForSession(any())).thenReturn("com.a.b.c");
-        assertFalse(dataProvider.isInteractiveOmniboxEnabled());
-
-        when(connection.getClientPackageNameForSession(any())).thenReturn("org.d.e.f");
-        assertFalse(dataProvider.isInteractiveOmniboxEnabled());
-
-        when(connection.getClientPackageNameForSession(any())).thenReturn("com.d.e.f");
-        assertFalse(dataProvider.isInteractiveOmniboxEnabled());
-    }
-
-    @Test
-    @EnableFeatures({ChromeFeatureList.SEARCH_IN_CCT})
-    public void isInteractiveOmniboxEnabled_featureEnabled_returnsTrue() {
-        ChromeFeatureList.sSearchinCctOmniboxAllowedPackageNames.setForTesting(
-                "com.a.b.c|org.d.e.f");
-        CustomTabsConnection connection = Mockito.mock(CustomTabsConnection.class);
-        CustomTabsConnection.setInstanceForTesting(connection);
-
-        Intent intent = new CustomTabsIntent.Builder().build().intent;
-        var dataProvider = new CustomTabIntentDataProvider(intent, mContext, COLOR_SCHEME_LIGHT);
-
-        when(connection.getClientPackageNameForSession(any())).thenReturn("com.a.b.c");
-        assertTrue(dataProvider.isInteractiveOmniboxEnabled());
-
-    }
-
-    @Test
-    @EnableFeatures({ChromeFeatureList.SEARCH_IN_CCT})
-    public void isInteractiveOmniboxEnabled_packageNotAllowed_returnsFalse() {
-        ChromeFeatureList.sSearchinCctOmniboxAllowedPackageNames.setForTesting(
-                "com.a.b.c");
-        CustomTabsConnection connection = Mockito.mock(CustomTabsConnection.class);
-        CustomTabsConnection.setInstanceForTesting(connection);
-
-        Intent intent = new CustomTabsIntent.Builder().build().intent;
-        var dataProvider = new CustomTabIntentDataProvider(intent, mContext, COLOR_SCHEME_LIGHT);
-
-        when(connection.getClientPackageNameForSession(any())).thenReturn("com.d.e.f");
-        assertFalse(dataProvider.isInteractiveOmniboxEnabled());
-    }
-
-    @Test
     @EnableFeatures({ChromeFeatureList.SEARCH_IN_CCT})
     public void addShareOption_conventionalCct_defaultState() {
-        ChromeFeatureList.sSearchinCctOmniboxAllowedPackageNames.setForTesting("com.a.b.c");
         CustomTabsConnection connection = Mockito.mock(CustomTabsConnection.class);
         CustomTabsConnection.setInstanceForTesting(connection);
         when(connection.shouldEnableOmniboxForIntent(any())).thenReturn(false);
@@ -1377,7 +1321,6 @@
     @Test
     @EnableFeatures({ChromeFeatureList.SEARCH_IN_CCT})
     public void addShareOption_conventionalCct_disabledState() {
-        ChromeFeatureList.sSearchinCctOmniboxAllowedPackageNames.setForTesting("com.a.b.c");
         CustomTabsConnection connection = Mockito.mock(CustomTabsConnection.class);
         CustomTabsConnection.setInstanceForTesting(connection);
         when(connection.shouldEnableOmniboxForIntent(any())).thenReturn(false);
@@ -1396,7 +1339,6 @@
     @Test
     @EnableFeatures({ChromeFeatureList.SEARCH_IN_CCT})
     public void addShareOption_searchInCct_enabledState() {
-        ChromeFeatureList.sSearchinCctOmniboxAllowedPackageNames.setForTesting("com.a.b.c");
         CustomTabsConnection connection = Mockito.mock(CustomTabsConnection.class);
         CustomTabsConnection.setInstanceForTesting(connection);
         when(connection.shouldEnableOmniboxForIntent(any())).thenReturn(true);
@@ -1417,7 +1359,6 @@
     @Test
     @EnableFeatures({ChromeFeatureList.SEARCH_IN_CCT})
     public void addOpenInBrowserOption_searchInCct_defaultState() {
-        ChromeFeatureList.sSearchinCctOmniboxAllowedPackageNames.setForTesting("com.a.b.c");
         CustomTabsConnection connection = Mockito.mock(CustomTabsConnection.class);
         CustomTabsConnection.setInstanceForTesting(connection);
         when(connection.shouldEnableOmniboxForIntent(any())).thenReturn(true);
@@ -1438,7 +1379,6 @@
     @Test
     @EnableFeatures({ChromeFeatureList.SEARCH_IN_CCT})
     public void addOpenInBrowserOption_searchInCct_disabledState() {
-        ChromeFeatureList.sSearchinCctOmniboxAllowedPackageNames.setForTesting("com.a.b.c");
         CustomTabsConnection connection = Mockito.mock(CustomTabsConnection.class);
         CustomTabsConnection.setInstanceForTesting(connection);
         when(connection.shouldEnableOmniboxForIntent(any())).thenReturn(true);
@@ -1462,7 +1402,6 @@
     @Test
     @EnableFeatures({ChromeFeatureList.SEARCH_IN_CCT})
     public void addOpenInBrowserOption_conventionalCct_enabledState() {
-        ChromeFeatureList.sSearchinCctOmniboxAllowedPackageNames.setForTesting("com.a.b.c");
         CustomTabsConnection connection = Mockito.mock(CustomTabsConnection.class);
         CustomTabsConnection.setInstanceForTesting(connection);
         when(connection.shouldEnableOmniboxForIntent(any())).thenReturn(false);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsUnitTest.java
index d566e51..aaa33cd 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsUnitTest.java
@@ -20,6 +20,7 @@
 import static org.chromium.chrome.browser.multiwindow.MultiWindowUtils.HISTOGRAM_DESKTOP_WINDOW_COUNT_NEW_INSTANCE_SUFFIX;
 import static org.chromium.chrome.browser.multiwindow.MultiWindowUtils.HISTOGRAM_NUM_ACTIVITIES_DESKTOP_WINDOW;
 import static org.chromium.chrome.browser.multiwindow.MultiWindowUtils.HISTOGRAM_NUM_INSTANCES_DESKTOP_WINDOW;
+import static org.chromium.chrome.browser.multiwindow.MultiWindowUtils.INVALID_TASK_ID;
 
 import android.app.Activity;
 import android.content.Context;
@@ -851,6 +852,24 @@
     }
 
     @Test
+    public void testGetLastAccessedWindowId() {
+        MultiWindowTestUtils.enableMultiInstance();
+
+        final int oldestId = 10;
+        final int midId = 20;
+        final int newestId = 30;
+
+        writeInstanceInfo(oldestId, URL_1, 3, 0, TASK_ID_5);
+        writeInstanceInfo(midId, URL_3, 1, 0, TASK_ID_6);
+        writeInstanceInfo(newestId, null, 0, 0, INVALID_TASK_ID);
+
+        Assert.assertEquals(
+                "The last accessed window ID should be returned.",
+                newestId,
+                MultiWindowUtils.getLastAccessedWindowId());
+    }
+
+    @Test
     public void testInstanceRestorationMessage() {
         MultiWindowUtils.setInstanceCountForTesting(5);
         MultiWindowUtils.setMaxInstancesForTesting(3);
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index c8c83d4..2bfa8448 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -6690,6 +6690,7 @@
       "//components/crash/core/app",
       "//components/device_signals/core/browser/mac",
       "//components/metal_util",
+      "//components/os_crypt/async/browser:keychain_key_provider",
       "//components/policy/core/common:common_constants",
       "//components/remote_cocoa/app_shim:features",
       "//components/remote_cocoa/browser",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index e106daae..b6899b7 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -6452,10 +6452,6 @@
      flag_descriptions::kImeSwitchCheckConnectionStatusName,
      flag_descriptions::kImeSwitchCheckConnectionStatusDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kImeSwitchCheckConnectionStatus)},
-    {"enable-cros-japanese-os-settings",
-     flag_descriptions::kJapaneseOSSettingsName,
-     flag_descriptions::kJapaneseOSSettingsDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(ash::features::kJapaneseOSSettings)},
     {"enable-experimental-accessibility-dictation-context-checking",
      flag_descriptions::kExperimentalAccessibilityDictationContextCheckingName,
      flag_descriptions::
@@ -6551,10 +6547,6 @@
      flag_descriptions::kArcAAudioMMAPLowLatencyName,
      flag_descriptions::kArcAAudioMMAPLowLatencyDescription, kOsCrOS,
      PLATFORM_FEATURE_NAME_TYPE("CrOSLateBootArcVmAAudioMMAPLowLatency")},
-    {"arc-custom-tabs-experiment",
-     flag_descriptions::kArcCustomTabsExperimentName,
-     flag_descriptions::kArcCustomTabsExperimentDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(arc::kCustomTabsExperimentFeature)},
     {kArcEnableAttestationFlag, flag_descriptions::kArcEnableAttestationName,
      flag_descriptions::kArcEnableAttestationDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(arc::kEnableArcAttestation)},
@@ -13330,6 +13322,15 @@
      FEATURE_VALUE_TYPE(
          autofill::features::kAutofillPrioritizeSaveCardOverMandatoryReauth)},
 
+#if BUILDFLAG(IS_ANDROID)
+    {"autofill-enable-keyboard-accessory-chip-redesign",
+     flag_descriptions::kAutofillEnableKeyboardAccessoryChipRedesignName,
+     flag_descriptions::kAutofillEnableKeyboardAccessoryChipRedesignDescription,
+     kOsAndroid,
+     FEATURE_VALUE_TYPE(
+         autofill::features::kAutofillEnableKeyboardAccessoryChipRedesign)},
+#endif
+
     // Add new entries above this line.
 
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
diff --git a/chrome/browser/apps/app_service/browser_app_launcher.cc b/chrome/browser/apps/app_service/browser_app_launcher.cc
index a1d4e3b..fd9b636 100644
--- a/chrome/browser/apps/app_service/browser_app_launcher.cc
+++ b/chrome/browser/apps/app_service/browser_app_launcher.cc
@@ -140,14 +140,6 @@
 
 BrowserAppLauncher::~BrowserAppLauncher() = default;
 
-#if !BUILDFLAG(IS_CHROMEOS)
-void BrowserAppLauncher::LaunchAppWithParams(
-    AppLaunchParams params,
-    base::OnceCallback<void(content::WebContents*)> callback) {
-  LaunchAppWithParamsImpl(std::move(params), profile_, std::move(callback));
-}
-#endif  // !BUILDFLAG(IS_CHROMEOS)
-
 content::WebContents* BrowserAppLauncher::LaunchAppWithParamsForTesting(
     AppLaunchParams params) {
   // For some ChromeOS tests (and specifically ones that use SpeechMonitor),
diff --git a/chrome/browser/apps/app_service/browser_app_launcher.h b/chrome/browser/apps/app_service/browser_app_launcher.h
index 6537a11..b6fc9bbc 100644
--- a/chrome/browser/apps/app_service/browser_app_launcher.h
+++ b/chrome/browser/apps/app_service/browser_app_launcher.h
@@ -31,17 +31,6 @@
   BrowserAppLauncher(const BrowserAppLauncher&) = delete;
   BrowserAppLauncher& operator=(const BrowserAppLauncher&) = delete;
 
-#if !BUILDFLAG(IS_CHROMEOS)
-  // Launches an app for the given `app_id` in a way specified by `params`.
-  //
-  // This interface is deprecated, please use
-  // AppServiceProxy::LaunchAppWithParams() in the future.
-  // TODO(crbug.com/40787924): Remove this interface in non-chrome OS platform.
-  void LaunchAppWithParams(
-      AppLaunchParams params,
-      base::OnceCallback<void(content::WebContents*)> callback);
-#endif  // !BUILDFLAG(IS_CHROMEOS)
-
   // Launches an app for the given `app_id` in a way specified by `params`. This
   // interface should only be used in testing code where reqired a sync launch
   // for browser apps. Please try to use AppServiceProxy::LaunchAppWithParams()
diff --git a/chrome/browser/apps/app_service/publishers/publisher_unittest.cc b/chrome/browser/apps/app_service/publishers/publisher_unittest.cc
index be2b6005..24c7048 100644
--- a/chrome/browser/apps/app_service/publishers/publisher_unittest.cc
+++ b/chrome/browser/apps/app_service/publishers/publisher_unittest.cc
@@ -66,7 +66,7 @@
     const std::string& version,
     const std::string& url,
     const std::string& id) {
-  std::string err;
+  std::u16string err;
   base::Value::Dict value;
   value.Set("name", name);
   value.Set("version", version);
@@ -76,7 +76,7 @@
   scoped_refptr<extensions::Extension> app = extensions::Extension::Create(
       base::FilePath(), extensions::mojom::ManifestLocation::kInternal, value,
       extensions::Extension::WAS_INSTALLED_BY_DEFAULT, id, &err);
-  EXPECT_EQ(err, "");
+  EXPECT_EQ(err, u"");
   return app;
 }
 
diff --git a/chrome/browser/apps/app_shim/BUILD.gn b/chrome/browser/apps/app_shim/BUILD.gn
index 29ba78e7..cf0fa4b 100644
--- a/chrome/browser/apps/app_shim/BUILD.gn
+++ b/chrome/browser/apps/app_shim/BUILD.gn
@@ -42,6 +42,7 @@
     "//chrome/browser/ui/profiles",
     "//chrome/browser/ui/web_applications",
     "//chrome/browser/web_applications",
+    "//chrome/browser/web_applications/extensions",
     "//chrome/common",
     "//chrome/common:app_mode_app_support",
     "//chrome/common:constants",
diff --git a/chrome/browser/apps/app_shim/web_app_shim_manager_delegate_mac.cc b/chrome/browser/apps/app_shim/web_app_shim_manager_delegate_mac.cc
index 78b4b9a8..c735fda 100644
--- a/chrome/browser/apps/app_shim/web_app_shim_manager_delegate_mac.cc
+++ b/chrome/browser/apps/app_shim/web_app_shim_manager_delegate_mac.cc
@@ -10,11 +10,9 @@
 #include "base/functional/callback_helpers.h"
 #include "base/no_destructor.h"
 #include "chrome/browser/apps/app_service/app_launch_params.h"
-#include "chrome/browser/apps/app_service/app_service_proxy.h"
-#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
-#include "chrome/browser/apps/app_service/browser_app_launcher.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/web_applications/web_app_dialogs.h"
+#include "chrome/browser/web_applications/extensions/launch.h"
 #include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
 #include "chrome/browser/web_applications/os_integration/web_app_file_handler_manager.h"
 #include "chrome/browser/web_applications/web_app.h"
@@ -58,11 +56,9 @@
         GetBrowserAppLauncherForTesting().Run(params_copy);
         barrier_callback.Run();
       } else {
-        apps::AppServiceProxyFactory::GetForProfile(profile)
-            ->BrowserAppLauncher()
-            ->LaunchAppWithParams(
-                std::move(params_copy),
-                base::IgnoreArgs<content::WebContents*>(barrier_callback));
+        web_app::LaunchExtensionOrWebApp(
+            profile, std::move(params_copy),
+            base::IgnoreArgs<content::WebContents*>(barrier_callback));
       }
     }
     return;
@@ -72,11 +68,9 @@
     GetBrowserAppLauncherForTesting().Run(params);
     std::move(launch_finished_callback).Run();
   } else {
-    apps::AppServiceProxyFactory::GetForProfile(profile)
-        ->BrowserAppLauncher()
-        ->LaunchAppWithParams(std::move(params),
-                              base::IgnoreArgs<content::WebContents*>(
-                                  std::move(launch_finished_callback)));
+    web_app::LaunchExtensionOrWebApp(profile, std::move(params),
+                                     base::IgnoreArgs<content::WebContents*>(
+                                         std::move(launch_finished_callback)));
   }
 }
 
diff --git a/chrome/browser/apps/platform_apps/extension_app_shim_manager_delegate_mac.cc b/chrome/browser/apps/platform_apps/extension_app_shim_manager_delegate_mac.cc
index 19d74ae..038e8e0 100644
--- a/chrome/browser/apps/platform_apps/extension_app_shim_manager_delegate_mac.cc
+++ b/chrome/browser/apps/platform_apps/extension_app_shim_manager_delegate_mac.cc
@@ -13,9 +13,6 @@
 #include "base/containers/adapters.h"
 #include "base/memory/raw_ptr.h"
 #include "chrome/browser/apps/app_service/app_launch_params.h"
-#include "chrome/browser/apps/app_service/app_service_proxy.h"
-#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
-#include "chrome/browser/apps/app_service/browser_app_launcher.h"
 #include "chrome/browser/apps/app_shim/app_shim_termination_manager.h"
 #include "chrome/browser/apps/platform_apps/app_window_registry_util.h"
 #include "chrome/browser/apps/platform_apps/platform_app_launch.h"
@@ -25,6 +22,7 @@
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "chrome/browser/ui/extensions/extension_enable_flow.h"
 #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
+#include "chrome/browser/web_applications/extensions/launch.h"
 #include "chrome/browser/web_applications/extensions/web_app_extension_shortcut.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_metrics.h"
@@ -204,9 +202,8 @@
         profile, extension, WindowOpenDisposition::NEW_FOREGROUND_TAB,
         apps::LaunchSource::kFromCommandLine);
     params.launch_files = files;
-    apps::AppServiceProxyFactory::GetForProfile(profile)
-        ->BrowserAppLauncher()
-        ->LaunchAppWithParams(std::move(params), base::DoNothing());
+    web_app::LaunchExtensionOrWebApp(profile, std::move(params),
+                                     base::DoNothing());
     return;
   }
   if (files.empty()) {
diff --git a/chrome/browser/ash/app_list/app_context_menu_unittest.cc b/chrome/browser/ash/app_list/app_context_menu_unittest.cc
index a7432d84..f96f4376a 100644
--- a/chrome/browser/ash/app_list/app_context_menu_unittest.cc
+++ b/chrome/browser/ash/app_list/app_context_menu_unittest.cc
@@ -284,7 +284,7 @@
         deserializer.Deserialize(nullptr, nullptr));
 
     DCHECK(manifest.is_dict());
-    std::string error;
+    std::u16string error;
     return extensions::Extension::Create(
         path.DirName(), extensions::mojom::ManifestLocation::kInternal,
         manifest.GetDict(), extensions::Extension::NO_FLAGS, app_id, &error);
@@ -329,7 +329,7 @@
   }
 
   scoped_refptr<extensions::Extension> MakeChromeApp() {
-    std::string err;
+    std::u16string err;
     base::Value::Dict value;
     value.Set("name", "Chrome App");
     value.Set("version", "0.0");
@@ -338,7 +338,7 @@
         base::FilePath(), extensions::mojom::ManifestLocation::kInternal, value,
         extensions::Extension::WAS_INSTALLED_BY_DEFAULT,
         app_constants::kChromeAppId, &err);
-    EXPECT_EQ(err, "");
+    EXPECT_EQ(err, u"");
     return app;
   }
 
diff --git a/chrome/browser/ash/app_list/app_list_test_util.cc b/chrome/browser/ash/app_list/app_list_test_util.cc
index 6acaafc..183dfd3 100644
--- a/chrome/browser/ash/app_list/app_list_test_util.cc
+++ b/chrome/browser/ash/app_list/app_list_test_util.cc
@@ -92,7 +92,7 @@
     const std::string& name,
     const std::string& id,
     extensions::Extension::InitFromValueFlags flags) {
-  std::string err;
+  std::u16string err;
   base::Value::Dict value;
   value.Set("name", name);
   value.Set("version", "0.0");
@@ -100,7 +100,7 @@
   scoped_refptr<extensions::Extension> app = extensions::Extension::Create(
       base::FilePath(), extensions::mojom::ManifestLocation::kInternal, value,
       flags, id, &err);
-  EXPECT_EQ(err, "");
+  EXPECT_EQ(err, u"");
   return app;
 }
 
diff --git a/chrome/browser/ash/app_list/app_service/app_service_app_model_builder_unittest.cc b/chrome/browser/ash/app_list/app_service/app_service_app_model_builder_unittest.cc
index c32db18..d6be84e 100644
--- a/chrome/browser/ash/app_list/app_service/app_service_app_model_builder_unittest.cc
+++ b/chrome/browser/ash/app_list/app_service/app_service_app_model_builder_unittest.cc
@@ -135,7 +135,7 @@
                                              const std::string& version,
                                              const std::string& url,
                                              const std::string& id) {
-  std::string err;
+  std::u16string err;
   base::Value::Dict value;
   value.Set("name", name);
   value.Set("version", version);
@@ -143,7 +143,7 @@
   scoped_refptr<extensions::Extension> app = extensions::Extension::Create(
       base::FilePath(), extensions::mojom::ManifestLocation::kInternal, value,
       extensions::Extension::WAS_INSTALLED_BY_DEFAULT, id, &err);
-  EXPECT_EQ(err, "");
+  EXPECT_EQ(err, u"");
   return app;
 }
 
diff --git a/chrome/browser/ash/app_list/arc/arc_app_test.cc b/chrome/browser/ash/app_list/arc/arc_app_test.cc
index e77511f..9cd89b9 100644
--- a/chrome/browser/ash/app_list/arc/arc_app_test.cc
+++ b/chrome/browser/ash/app_list/arc/arc_app_test.cc
@@ -173,10 +173,8 @@
           arc_service_manager_->arc_bridge_service()->intent_helper());
     }
 
-    if (start_app_service_publisher_) {
-      // Ensure that the singleton apps::ArcApps is constructed.
-      apps::ArcAppsFactory::GetForProfile(profile_);
-    }
+    // Ensure that the singleton apps::ArcApps is constructed.
+    apps::ArcAppsFactory::GetForProfile(profile_);
 
     arc_session_manager_->Initialize();
 
@@ -359,15 +357,12 @@
   CHECK(arc_session_manager_);
   arc_session_manager_->Shutdown();
 
-  if (start_app_service_publisher_) {
-    apps::ArcAppsFactory::GetInstance()->ShutDownForTesting(profile_);
-  }
+  apps::ArcAppsFactory::GetInstance()->ShutDownForTesting(profile_);
 
   if (initialize_real_intent_helper_bridge_) {
     arc_service_manager_->arc_bridge_service()->intent_helper()->CloseInstance(
         intent_helper_instance_.get());
     intent_helper_instance_.reset();
-    intent_helper_host_.reset();
     arc::ArcIntentHelperBridge::ShutDownForTesting(profile_);
   }
 
diff --git a/chrome/browser/ash/app_list/arc/arc_app_test.h b/chrome/browser/ash/app_list/arc/arc_app_test.h
index e600c3a..2c2d7e76 100644
--- a/chrome/browser/ash/app_list/arc/arc_app_test.h
+++ b/chrome/browser/ash/app_list/arc/arc_app_test.h
@@ -24,7 +24,6 @@
 class ArcSessionManager;
 class FakeAppInstance;
 class FakeCompatibilityModeInstance;
-class FakeIntentHelperHost;
 class FakeIntentHelperInstance;
 }  // namespace arc
 
@@ -133,10 +132,6 @@
     persist_service_manager_ = persist_service_manager;
   }
 
-  void set_start_app_service_publisher(bool start_app_service_publisher) {
-    start_app_service_publisher_ = start_app_service_publisher;
-  }
-
   void set_initialize_real_intent_helper_bridge(bool value) {
     initialize_real_intent_helper_bridge_ = value;
   }
@@ -164,10 +159,6 @@
   // down.
   bool persist_service_manager_ = false;
 
-  // Whether the ArcApps AppService publisher should be started during
-  // initialization.
-  bool start_app_service_publisher_ = true;
-
   // If set to true, the real ArcIntentHelperBridge is initialized on test start
   // up.
   bool initialize_real_intent_helper_bridge_ = false;
@@ -183,7 +174,6 @@
   std::unique_ptr<arc::FakeAppInstance> app_instance_;
   std::unique_ptr<arc::FakeCompatibilityModeInstance>
       compatibility_mode_instance_;
-  std::unique_ptr<arc::FakeIntentHelperHost> intent_helper_host_;
   std::unique_ptr<arc::FakeIntentHelperInstance> intent_helper_instance_;
 
   user_manager::TypedScopedUserManager<ash::FakeChromeUserManager>
diff --git a/chrome/browser/ash/app_list/arc/arc_app_unittest.cc b/chrome/browser/ash/app_list/arc/arc_app_unittest.cc
index 5240c025..0290cf0 100644
--- a/chrome/browser/ash/app_list/arc/arc_app_unittest.cc
+++ b/chrome/browser/ash/app_list/arc/arc_app_unittest.cc
@@ -1370,7 +1370,7 @@
     manifest.Set(extensions::manifest_keys::kDescription,
                  "Play Store for testing");
 
-    std::string error;
+    std::u16string error;
     arc_support_host_ = extensions::Extension::Create(
         base::FilePath(), extensions::mojom::ManifestLocation::kUnpacked,
         manifest, extensions::Extension::NO_FLAGS, arc::kPlayStoreAppId,
diff --git a/chrome/browser/ash/app_mode/kiosk_chrome_app_manager_browsertest.cc b/chrome/browser/ash/app_mode/kiosk_chrome_app_manager_browsertest.cc
index 88ff69b..8eaae55 100644
--- a/chrome/browser/ash/app_mode/kiosk_chrome_app_manager_browsertest.cc
+++ b/chrome/browser/ash/app_mode/kiosk_chrome_app_manager_browsertest.cc
@@ -101,11 +101,11 @@
                           required_platform_version);
   }
 
-  std::string err;
+  std::u16string err;
   scoped_refptr<extensions::Extension> app = extensions::Extension::Create(
       base::FilePath(), extensions::mojom::ManifestLocation::kInternal, value,
       extensions::Extension::WAS_INSTALLED_BY_DEFAULT, id, &err);
-  EXPECT_EQ(err, "");
+  EXPECT_EQ(err, u"");
   return app;
 }
 
diff --git a/chrome/browser/ash/child_accounts/apps/app_test_utils.cc b/chrome/browser/ash/child_accounts/apps/app_test_utils.cc
index 89fd1ba1..c61b4d85 100644
--- a/chrome/browser/ash/child_accounts/apps/app_test_utils.cc
+++ b/chrome/browser/ash/child_accounts/apps/app_test_utils.cc
@@ -44,7 +44,7 @@
   manifest.Set(extensions::manifest_keys::kManifestVersion, 2);
   manifest.SetByDottedPath(extensions::manifest_keys::kLaunchWebURL, url);
 
-  std::string error;
+  std::u16string error;
   extensions::Extension::InitFromValueFlags flags =
       extensions::Extension::NO_FLAGS;
   scoped_refptr<extensions::Extension> extension =
diff --git a/chrome/browser/ash/dbus/chrome_features_service_provider.cc b/chrome/browser/ash/dbus/chrome_features_service_provider.cc
index 4eae4879..2049927 100644
--- a/chrome/browser/ash/dbus/chrome_features_service_provider.cc
+++ b/chrome/browser/ash/dbus/chrome_features_service_provider.cc
@@ -197,7 +197,6 @@
     dbus::ExportedObject::ResponseSender response_sender) {
   static const base::Feature constexpr* kFeatureLookup[] = {
       &arc::kBootCompletedBroadcastFeature,
-      &arc::kCustomTabsExperimentFeature,
       &arc::kNativeBridgeToggleFeature,
       &features::kSessionManagerLongKillTimeout,
       &features::kSessionManagerLivenessCheck,
diff --git a/chrome/browser/ash/extensions/BUILD.gn b/chrome/browser/ash/extensions/BUILD.gn
index f444f76..6da04f4 100644
--- a/chrome/browser/ash/extensions/BUILD.gn
+++ b/chrome/browser/ash/extensions/BUILD.gn
@@ -42,7 +42,6 @@
     "signin_screen_extensions_external_loader.h",
     "signin_screen_policy_provider.cc",
     "signin_screen_policy_provider.h",
-    "url_constants.h",
   ]
 
   public_deps = [ "//chrome/browser:browser_public_dependencies" ]
diff --git a/chrome/browser/ash/extensions/device_local_account_management_policy_provider_unittest.cc b/chrome/browser/ash/extensions/device_local_account_management_policy_provider_unittest.cc
index d49ca08..68cd54a 100644
--- a/chrome/browser/ash/extensions/device_local_account_management_policy_provider_unittest.cc
+++ b/chrome/browser/ash/extensions/device_local_account_management_policy_provider_unittest.cc
@@ -32,7 +32,7 @@
   values.Set(extensions::manifest_keys::kName, "test");
   values.Set(extensions::manifest_keys::kVersion, "0.1");
   values.Set(extensions::manifest_keys::kManifestVersion, 2);
-  std::string error;
+  std::u16string error;
   return extensions::Extension::Create(base::FilePath(), location, values,
                                        flags, id, &error);
 }
diff --git a/chrome/browser/ash/extensions/url_constants.h b/chrome/browser/ash/extensions/url_constants.h
deleted file mode 100644
index efd3cf96..0000000
--- a/chrome/browser/ash/extensions/url_constants.h
+++ /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.
-
-#ifndef CHROME_BROWSER_ASH_EXTENSIONS_URL_CONSTANTS_H_
-#define CHROME_BROWSER_ASH_EXTENSIONS_URL_CONSTANTS_H_
-
-namespace extensions {
-
-// IME extension's Japanese options page.
-inline constexpr char kIMEJPOptionsURL[] =
-    "chrome-extension://jkghodnilhceideoidjikpgommlajknk/"
-    "mozc_option.html";
-
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_ASH_EXTENSIONS_URL_CONSTANTS_H_
diff --git a/chrome/browser/ash/file_system_provider/service_unittest.cc b/chrome/browser/ash/file_system_provider/service_unittest.cc
index fba0727..d0a1f29 100644
--- a/chrome/browser/ash/file_system_provider/service_unittest.cc
+++ b/chrome/browser/ash/file_system_provider/service_unittest.cc
@@ -60,7 +60,7 @@
 scoped_refptr<extensions::Extension> CreateFakeExtension(
     const extensions::ExtensionId& extension_id) {
   base::Value::Dict manifest;
-  std::string error;
+  std::u16string error;
   manifest.Set(extensions::manifest_keys::kVersion, "1.0.0.0");
   manifest.Set(extensions::manifest_keys::kManifestVersion, 2);
   manifest.Set(extensions::manifest_keys::kName, "unused");
diff --git a/chrome/browser/ash/notifications/idle_app_name_notification_view_unittest.cc b/chrome/browser/ash/notifications/idle_app_name_notification_view_unittest.cc
index a6bc76d..f4ecf062 100644
--- a/chrome/browser/ash/notifications/idle_app_name_notification_view_unittest.cc
+++ b/chrome/browser/ash/notifications/idle_app_name_notification_view_unittest.cc
@@ -49,7 +49,7 @@
     manifest.Set(extensions::manifest_keys::kDescription, "Test app");
     manifest.SetByDottedPath("author.email", "Someone");
 
-    std::string error;
+    std::u16string error;
     correct_extension_ = extensions::Extension::Create(
         base::FilePath(), extensions::mojom::ManifestLocation::kUnpacked,
         manifest, extensions::Extension::NO_FLAGS, kTestAppName, &error);
diff --git a/chrome/browser/background/extensions/BUILD.gn b/chrome/browser/background/extensions/BUILD.gn
index 474e54bf..d82f5e3 100644
--- a/chrome/browser/background/extensions/BUILD.gn
+++ b/chrome/browser/background/extensions/BUILD.gn
@@ -55,7 +55,7 @@
     "//chrome/app/theme:chrome_unscaled_resources_grit",
     "//chrome/browser:browser_process",
     "//chrome/browser:browser_public_dependencies",
-    "//chrome/browser/apps/app_service",
+    "//chrome/browser/apps/app_service:constants",
     "//chrome/browser/background",
     "//chrome/browser/extensions",
     "//chrome/browser/lifetime:termination_notification",
@@ -79,6 +79,10 @@
   if (enable_glic) {
     deps += [ "//chrome/browser/glic" ]
   }
+
+  if (!is_chromeos) {
+    deps += [ "//chrome/browser/web_applications/extensions" ]
+  }
 }
 
 source_set("unit_tests") {
diff --git a/chrome/browser/background/extensions/background_application_list_model_unittest.cc b/chrome/browser/background/extensions/background_application_list_model_unittest.cc
index 0a5a5f3..7006054e 100644
--- a/chrome/browser/background/extensions/background_application_list_model_unittest.cc
+++ b/chrome/browser/background/extensions/background_application_list_model_unittest.cc
@@ -95,7 +95,7 @@
   }
   manifest.Set(extensions::manifest_keys::kPermissions, std::move(permissions));
 
-  std::string error;
+  std::u16string error;
   scoped_refptr<Extension> extension = Extension::Create(
       bogus_file_pathname(name), extensions::mojom::ManifestLocation::kInternal,
       manifest, Extension::NO_FLAGS, &error);
diff --git a/chrome/browser/background/extensions/background_mode_manager.cc b/chrome/browser/background/extensions/background_mode_manager.cc
index bed49f3..da0e3a8 100644
--- a/chrome/browser/background/extensions/background_mode_manager.cc
+++ b/chrome/browser/background/extensions/background_mode_manager.cc
@@ -26,9 +26,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/apps/app_service/app_service_proxy.h"
-#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
-#include "chrome/browser/apps/app_service/browser_app_launcher.h"
 #include "chrome/browser/background/extensions/background_application_list_model.h"
 #include "chrome/browser/background/extensions/background_mode_optimizer.h"
 #include "chrome/browser/background/startup_launch_manager.h"
@@ -54,6 +51,7 @@
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "chrome/browser/ui/profiles/profile_picker.h"
+#include "chrome/browser/web_applications/extensions/launch.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension_constants.h"
@@ -76,6 +74,7 @@
 #include "ui/base/models/image_model.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image_family.h"
+#include "ui/gfx/image/image_skia.h"
 
 #if BUILDFLAG(IS_WIN)
 #include "chrome/browser/win/app_icon.h"
@@ -412,13 +411,12 @@
     Profile* profile,
     const Extension* extension) {
 #if !BUILDFLAG(IS_CHROMEOS)
-  apps::AppServiceProxyFactory::GetForProfile(profile)
-      ->BrowserAppLauncher()
-      ->LaunchAppWithParams(
-          CreateAppLaunchParamsUserContainer(
-              profile, extension, WindowOpenDisposition::NEW_FOREGROUND_TAB,
-              apps::LaunchSource::kFromBackgroundMode),
-          base::DoNothing());
+  web_app::LaunchExtensionOrWebApp(
+      profile,
+      CreateAppLaunchParamsUserContainer(
+          profile, extension, WindowOpenDisposition::NEW_FOREGROUND_TAB,
+          apps::LaunchSource::kFromBackgroundMode),
+      base::DoNothing());
 #else
   // background mode is not used in Chrome OS platform.
   // TODO(crbug.com/40212901): Remove the background mode manager from Chrome OS
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 489ca27d..539b12a 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -261,6 +261,10 @@
 #include "components/password_manager/core/browser/password_manager_switches.h"
 #endif
 
+#if BUILDFLAG(IS_MAC)
+#include "components/os_crypt/async/browser/keychain_key_provider.h"
+#endif
+
 #if BUILDFLAG(SAFE_BROWSING_AVAILABLE)
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #endif
@@ -1401,6 +1405,14 @@
   }
 #endif  // BUILDFLAG(IS_LINUX)
 
+#if BUILDFLAG(IS_MAC)
+  if (base::FeatureList::IsEnabled(features::kUseKeychainKeyProvider)) {
+    providers.emplace_back(std::make_pair(
+        /*precedence=*/10u,
+        std::make_unique<os_crypt_async::KeychainKeyProvider>()));
+  }
+#endif  // BUILDFLAG(IS_MAC)
+
   os_crypt_async_ =
       std::make_unique<os_crypt_async::OSCryptAsync>(std::move(providers));
 
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_windows_logs_collector_unittest.cc b/chrome/browser/chromeos/app_mode/kiosk_app_windows_logs_collector_unittest.cc
index 461ddeee..790f7773 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_windows_logs_collector_unittest.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_windows_logs_collector_unittest.cc
@@ -57,7 +57,7 @@
   manifest.SetByDottedPath(extensions::manifest_keys::kLaunchWebURL,
                            kLaunchURL);
 
-  std::string error;
+  std::u16string error;
   scoped_refptr<extensions::Extension> extension =
       extensions::Extension::Create(
           base::FilePath(), extensions::mojom::ManifestLocation::kUnpacked,
diff --git a/chrome/browser/devtools/android/java/src/org/chromium/chrome/browser/devtools/DevToolsWindowAndroid.java b/chrome/browser/devtools/android/java/src/org/chromium/chrome/browser/devtools/DevToolsWindowAndroid.java
index 75f60f72..27ea1dd 100644
--- a/chrome/browser/devtools/android/java/src/org/chromium/chrome/browser/devtools/DevToolsWindowAndroid.java
+++ b/chrome/browser/devtools/android/java/src/org/chromium/chrome/browser/devtools/DevToolsWindowAndroid.java
@@ -24,6 +24,12 @@
                 && DevToolsWindowAndroidJni.get().isDevToolsAllowedFor(profile, webContents);
     }
 
+    public static boolean canViewSource(Profile profile, WebContents webContents) {
+        // Disallow ViewSource if DevTools are disabled.
+        return isDevToolsAllowedFor(profile, webContents)
+                && webContents.getNavigationController().canViewSource();
+    }
+
     /**
      * Opens a DevTools window for the given WebContents.
      *
diff --git a/chrome/browser/enterprise/connectors/reporting/extension_install_event_router_unittest.cc b/chrome/browser/enterprise/connectors/reporting/extension_install_event_router_unittest.cc
index e6040b9f..48c48c6 100644
--- a/chrome/browser/enterprise/connectors/reporting/extension_install_event_router_unittest.cc
+++ b/chrome/browser/enterprise/connectors/reporting/extension_install_event_router_unittest.cc
@@ -107,7 +107,7 @@
     int flags = is_from_webstore() ? extensions::Extension::FROM_WEBSTORE
                                    : extensions::Extension::NO_FLAGS;
 
-    std::string error;
+    std::u16string error;
     extension_chrome_ = extensions::Extension::Create(
         base::FilePath(), location, manifest, flags, kFakeExtensionId, &error);
   }
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
index afcb671..3cad504 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
@@ -402,6 +402,31 @@
   }
 }
 
+// On Android, the returned FilePath points to a temporary file managed
+// by `temp_dir`. The caller MUST ensure `temp_dir` is not destroyed before
+// they are finished using the FilePath, as its destruction will delete the
+// underlying file, resulting in a broken path.
+
+// TODO(crbug.com/448823672): Refactor TestExtensionDir to abstract Android's
+// Content URI requirements.
+ui::SelectedFileInfo GetSelectedFileInfoForPath(const base::FilePath& path,
+                                                base::ScopedTempDir& temp_dir) {
+#if BUILDFLAG(IS_ANDROID)
+  // On Android, tests need to work with content URIs instead of direct file
+  // paths. This helper copies the extension files to a temporary cache
+  // directory and creates a content URI pointing to it.
+  CHECK(temp_dir.CreateUniqueTempDir());
+
+  std::optional<base::FilePath> cache_path =
+      base::test::android::CreateCacheCopyAndGetContentUri(path, temp_dir);
+  CHECK(cache_path.has_value());
+  return ui::SelectedFileInfo(*cache_path);
+#else
+  // On other platforms, we can use the direct file path.
+  return ui::SelectedFileInfo(path);
+#endif  // BUILDFLAG(IS_ANDROID)
+}
+
 }  // namespace
 
 // TODO(crbug.com/408458901): Port these tests to desktop Android when we have
@@ -1033,8 +1058,6 @@
                     .size());
 }
 
-// TODO(crbug.com/439448250): Enable on desktop android.
-#if BUILDFLAG(ENABLE_EXTENSIONS)
 TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateLoadUnpackedLoadError) {
   std::unique_ptr<content::WebContents> web_contents(
       content::WebContentsTester::CreateTestWebContents(profile(), nullptr));
@@ -1054,7 +1077,9 @@
     auto function =
         base::MakeRefCounted<api::DeveloperPrivateLoadUnpackedFunction>();
     function->set_accept_dialog_for_testing(true);
-    function->set_selected_file_for_testing(ui::SelectedFileInfo(path));
+    base::ScopedTempDir temp_dir_copy;
+    function->set_selected_file_for_testing(
+        GetSelectedFileInfoForPath(path, temp_dir_copy));
     function->SetRenderFrameHost(web_contents->GetPrimaryMainFrame());
     std::optional<base::Value> result =
         api_test_utils::RunFunctionAndReturnSingleResult(
@@ -1083,7 +1108,9 @@
     auto function =
         base::MakeRefCounted<api::DeveloperPrivateLoadUnpackedFunction>();
     function->set_accept_dialog_for_testing(true);
-    function->set_selected_file_for_testing(ui::SelectedFileInfo(path));
+    base::ScopedTempDir temp_dir_copy;
+    function->set_selected_file_for_testing(
+        GetSelectedFileInfoForPath(path, temp_dir_copy));
     function->SetRenderFrameHost(web_contents->GetPrimaryMainFrame());
     std::optional<base::Value> result =
         api_test_utils::RunFunctionAndReturnSingleResult(
@@ -1116,7 +1143,9 @@
     auto function =
         base::MakeRefCounted<api::DeveloperPrivateLoadUnpackedFunction>();
     function->set_accept_dialog_for_testing(true);
-    function->set_selected_file_for_testing(ui::SelectedFileInfo(path));
+    base::ScopedTempDir temp_dir_copy;
+    function->set_selected_file_for_testing(
+        GetSelectedFileInfoForPath(path, temp_dir_copy));
     function->SetRenderFrameHost(web_contents->GetPrimaryMainFrame());
     std::optional<base::Value> result =
         api_test_utils::RunFunctionAndReturnSingleResult(
@@ -1142,6 +1171,9 @@
            "manifest_version": 2
          })");
   base::FilePath path = dir.UnpackedPath();
+  base::ScopedTempDir first_dir_copy;
+  ui::SelectedFileInfo selected_path =
+      GetSelectedFileInfoForPath(path, first_dir_copy);
 
   DeveloperPrivateAPI::UnpackedRetryId retry_guid;
   {
@@ -1150,7 +1182,7 @@
     auto function =
         base::MakeRefCounted<api::DeveloperPrivateLoadUnpackedFunction>();
     function->set_accept_dialog_for_testing(true);
-    function->set_selected_file_for_testing(ui::SelectedFileInfo(path));
+    function->set_selected_file_for_testing(selected_path);
     function->SetRenderFrameHost(web_contents->GetPrimaryMainFrame());
     std::optional<base::Value> result =
         api_test_utils::RunFunctionAndReturnSingleResult(
@@ -1172,7 +1204,7 @@
     auto function =
         base::MakeRefCounted<api::DeveloperPrivateLoadUnpackedFunction>();
     function->set_accept_dialog_for_testing(true);
-    function->set_selected_file_for_testing(ui::SelectedFileInfo(path));
+    function->set_selected_file_for_testing(selected_path);
     function->SetRenderFrameHost(web_contents->GetPrimaryMainFrame());
     std::optional<base::Value> result =
         api_test_utils::RunFunctionAndReturnSingleResult(
@@ -1202,7 +1234,9 @@
     auto function =
         base::MakeRefCounted<api::DeveloperPrivateLoadUnpackedFunction>();
     function->set_accept_dialog_for_testing(true);
-    function->set_selected_file_for_testing(ui::SelectedFileInfo(second_path));
+    base::ScopedTempDir second_dir_copy;
+    function->set_selected_file_for_testing(
+        GetSelectedFileInfoForPath(second_path, second_dir_copy));
     function->SetRenderFrameHost(web_contents->GetPrimaryMainFrame());
     std::optional<base::Value> result =
         api_test_utils::RunFunctionAndReturnSingleResult(
@@ -1224,17 +1258,29 @@
            "version": "1.0",
            "manifest_version": 2
          })");
+#if BUILDFLAG(IS_ANDROID)
+  // Since Android copies the directory from the source path, the operation
+  // above will not modify the content in Android's local directory. We need to
+  // manually copy the directory again to overwrite the file in Android.
+  ASSERT_TRUE(base::CopyDirectory(path, first_dir_copy.GetPath(), true));
+#endif  // BUILDFLAG(IS_ANDROID)
 
-  // Set the picker to choose an invalid path (the picker should be skipped if
-  // we supply a retry id).
-  base::FilePath empty_path;
+  // Set the picker to an invalid path. Here, we create a real file with an
+  // invalid manifest. This file is never actually used because the retry GUID
+  // takes precedence, but it is required for the file picker setup. (Note: the
+  // picker should be skipped if a retry ID is supplied).
+  TestExtensionDir invalid_dir;
+  invalid_dir.WriteManifest("This is an invalid file.");
+  base::FilePath invalid_path = invalid_dir.UnpackedPath();
 
   {
     // Try reloading the extension by supplying the retry id. It should succeed.
     auto function =
         base::MakeRefCounted<api::DeveloperPrivateLoadUnpackedFunction>();
     function->set_accept_dialog_for_testing(true);
-    function->set_selected_file_for_testing(ui::SelectedFileInfo(empty_path));
+    base::ScopedTempDir invalid_dir_copy;
+    function->set_selected_file_for_testing(
+        GetSelectedFileInfoForPath(invalid_path, invalid_dir_copy));
     function->SetRenderFrameHost(web_contents->GetPrimaryMainFrame());
     TestExtensionRegistryObserver observer(registry());
     api_test_utils::RunFunction(function.get(),
@@ -1246,7 +1292,12 @@
     scoped_refptr<const Extension> extension =
         observer.WaitForExtensionLoaded();
     ASSERT_TRUE(extension);
+#if BUILDFLAG(IS_ANDROID)
+    EXPECT_EQ(extension->path(),
+              *base::ResolveToVirtualDocumentPath(selected_path.file_path));
+#else
     EXPECT_EQ(extension->path(), path);
+#endif  // BUILDFLAG(IS_ANDROID)
   }
 
   {
@@ -1254,7 +1305,9 @@
     auto function =
         base::MakeRefCounted<api::DeveloperPrivateLoadUnpackedFunction>();
     function->set_accept_dialog_for_testing(true);
-    function->set_selected_file_for_testing(ui::SelectedFileInfo(empty_path));
+    base::ScopedTempDir invalid_dir_copy;
+    function->set_selected_file_for_testing(
+        GetSelectedFileInfoForPath(invalid_path, invalid_dir_copy));
     function->SetRenderFrameHost(web_contents->GetPrimaryMainFrame());
     std::string error = api_test_utils::RunFunctionAndReturnError(
         function.get(),
@@ -1266,6 +1319,8 @@
   }
 }
 
+// TODO(crbug.com/439448250): Enable on desktop android.
+#if BUILDFLAG(ENABLE_EXTENSIONS)
 // Tests calling "reload" on an unpacked extension with a manifest error,
 // resulting in the reload failing. The reload call should then respond with
 // the load error, which includes a retry GUID to be passed to loadUnpacked().
diff --git a/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc b/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc
index 22c7061..d816edf 100644
--- a/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc
+++ b/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc
@@ -223,7 +223,7 @@
           "background.html");
     }
 
-    std::string error;
+    std::u16string error;
     return extensions::Extension::Create(
         bogus_file_pathname(name),
         extensions::mojom::ManifestLocation::kInvalidLocation, manifest,
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc b/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc
index 0aad60e..ab17a23 100644
--- a/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc
+++ b/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc
@@ -104,7 +104,7 @@
     base::FilePath path;
     EXPECT_TRUE(base::PathService::Get(DIR_TEST_DATA, &path));
 
-    std::string error;
+    std::u16string error;
     scoped_refptr<Extension> extension(
         Extension::Create(path, mojom::ManifestLocation::kInternal,
                           manifest_builder, Extension::NO_FLAGS, &error));
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
index c9e918db..60acce2 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
@@ -496,7 +496,7 @@
   std::string localized_name =
       details().localized_name ? *details().localized_name : std::string();
 
-  std::string error;
+  std::u16string error;
   dummy_extension_ = ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
       *parsed_manifest_, Extension::FROM_WEBSTORE, id, localized_name,
       std::string(), &error);
@@ -1339,7 +1339,7 @@
     return;
   }
 
-  std::string error;
+  std::u16string error;
   auto dummy_extension = Extension::Create(
       base::FilePath(), mojom::ManifestLocation::kInternal, result->GetDict(),
       Extension::FROM_WEBSTORE, extension_id, &error);
diff --git a/chrome/browser/extensions/chrome_app_sorting_unittest.cc b/chrome/browser/extensions/chrome_app_sorting_unittest.cc
index 25bc42f..bd09a815 100644
--- a/chrome/browser/extensions/chrome_app_sorting_unittest.cc
+++ b/chrome/browser/extensions/chrome_app_sorting_unittest.cc
@@ -576,7 +576,7 @@
     simple_dict.Set(keys::kName, "unused");
     simple_dict.SetByDottedPath(keys::kLaunchLocalPath, "fake.html");
 
-    std::string error;
+    std::u16string error;
     app1_scoped_ = Extension::Create(prefs_.temp_dir().AppendASCII("app1_"),
                                      ManifestLocation::kExternalPref,
                                      simple_dict, Extension::NO_FLAGS, &error);
@@ -742,7 +742,7 @@
     simple_dict.Set(keys::kName, name);
     simple_dict.SetByDottedPath(keys::kLaunchLocalPath, "fake.html");
 
-    std::string errors;
+    std::u16string errors;
     scoped_refptr<Extension> app = Extension::Create(
         prefs_.temp_dir().AppendASCII(name), ManifestLocation::kExternalPref,
         simple_dict, Extension::NO_FLAGS, &errors);
diff --git a/chrome/browser/extensions/chrome_component_extension_resource_manager_unittest.cc b/chrome/browser/extensions/chrome_component_extension_resource_manager_unittest.cc
index 5400a2b..16b8ff9 100644
--- a/chrome/browser/extensions/chrome_component_extension_resource_manager_unittest.cc
+++ b/chrome/browser/extensions/chrome_component_extension_resource_manager_unittest.cc
@@ -64,9 +64,10 @@
   resources_path = resources_path.AppendASCII("file_manager");
 
   // Create a simulated component extension.
+  std::u16string utf16_error;
   scoped_refptr<Extension> extension =
       Extension::Create(resources_path, mojom::ManifestLocation::kComponent,
-                        *manifest, Extension::NO_FLAGS, &error);
+                        *manifest, Extension::NO_FLAGS, &utf16_error);
   ASSERT_TRUE(extension.get());
 
   // Load one of the icons.
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index b5ec8142..ba347da 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -312,7 +312,7 @@
 }
 
 void ComponentLoader::Load(const ComponentExtensionInfo& info) {
-  std::string error;
+  std::u16string error;
   scoped_refptr<const Extension> extension(CreateExtension(info, &error));
   if (!extension.get()) {
     LOG(ERROR) << error;
@@ -459,7 +459,7 @@
 
 scoped_refptr<const Extension> ComponentLoader::CreateExtension(
     const ComponentExtensionInfo& info,
-    std::string* utf8_error) {
+    std::u16string* error) {
   // TODO(abarth): We should REQUIRE_MODERN_MANIFEST_VERSION once we've updated
   //               our component extensions to the new manifest version.
   int flags = Extension::REQUIRE_KEY;
@@ -472,7 +472,7 @@
 
   return Extension::Create(info.root_directory,
                            mojom::ManifestLocation::kComponent, info.manifest,
-                           flags, utf8_error);
+                           flags, error);
 }
 
 // static
diff --git a/chrome/browser/extensions/component_loader.h b/chrome/browser/extensions/component_loader.h
index 1722823..3ebc51c 100644
--- a/chrome/browser/extensions/component_loader.h
+++ b/chrome/browser/extensions/component_loader.h
@@ -241,7 +241,8 @@
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
   scoped_refptr<const Extension> CreateExtension(
-      const ComponentExtensionInfo& info, std::string* utf8_error);
+      const ComponentExtensionInfo& info,
+      std::u16string* error);
 
   // Unloads `component` from the memory.
   void UnloadComponent(ComponentExtensionInfo* component);
diff --git a/chrome/browser/extensions/convert_user_script.cc b/chrome/browser/extensions/convert_user_script.cc
index 8eae060..7d07104 100644
--- a/chrome/browser/extensions/convert_user_script.cc
+++ b/chrome/browser/extensions/convert_user_script.cc
@@ -158,13 +158,9 @@
     return nullptr;
   }
 
-  // TODO(rdevlin.cronin): Continue removing std::string errors and replacing
-  // with std::u16string
-  std::string utf8_error;
   scoped_refptr<Extension> extension =
       Extension::Create(temp_dir.GetPath(), mojom::ManifestLocation::kInternal,
-                        root, Extension::NO_FLAGS, &utf8_error);
-  *error = base::UTF8ToUTF16(utf8_error);
+                        root, Extension::NO_FLAGS, error);
   if (!extension.get()) {
     NOTREACHED() << "Could not init extension " << *error;
   }
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index f9c2d3a..be3b983b 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -364,7 +364,7 @@
       valid = *expected_manifest_ == *original_manifest_;
       if (!valid &&
           expected_manifest_check_level_ == ManifestCheckLevel::kLoose) {
-        std::string error;
+        std::u16string error;
         scoped_refptr<Extension> dummy_extension = Extension::Create(
             base::FilePath(), install_source_, *expected_manifest_,
             creation_flags_, extension->id(), &error);
diff --git a/chrome/browser/extensions/extension_action_icon_factory_unittest.cc b/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
index 430f86ce..4c31250 100644
--- a/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
+++ b/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
@@ -129,10 +129,11 @@
     if (!valid_value || !valid_value->is_dict())
       return nullptr;
 
+    std::u16string utf16_error;
     scoped_refptr<Extension> extension =
         Extension::Create(test_file, location, valid_value->GetDict(),
-                          Extension::NO_FLAGS, &error);
-    EXPECT_TRUE(extension.get()) << error;
+                          Extension::NO_FLAGS, &utf16_error);
+    EXPECT_TRUE(extension.get()) << utf16_error;
     if (extension) {
       ExtensionRegistrar::Get(profile_.get())->AddExtension(extension);
     }
diff --git a/chrome/browser/extensions/extension_install_prompt.cc b/chrome/browser/extensions/extension_install_prompt.cc
index d98e62fd..87ccb36 100644
--- a/chrome/browser/extensions/extension_install_prompt.cc
+++ b/chrome/browser/extensions/extension_install_prompt.cc
@@ -419,7 +419,7 @@
     const std::string& id,
     const std::string& localized_name,
     const std::string& localized_description,
-    std::string* error) {
+    std::u16string* error) {
   std::optional<base::Value::Dict> localized_manifest;
   if (!localized_name.empty() || !localized_description.empty()) {
     localized_manifest = manifest.Clone();
diff --git a/chrome/browser/extensions/extension_install_prompt.h b/chrome/browser/extensions/extension_install_prompt.h
index 79675451..69ed2cc9 100644
--- a/chrome/browser/extensions/extension_install_prompt.h
+++ b/chrome/browser/extensions/extension_install_prompt.h
@@ -272,7 +272,7 @@
       const std::string& id,
       const std::string& localized_name,
       const std::string& localized_description,
-      std::string* error);
+      std::u16string* error);
 
   // Creates a prompt with a parent web content.
   explicit ExtensionInstallPrompt(content::WebContents* contents);
diff --git a/chrome/browser/extensions/extension_management_unittest.cc b/chrome/browser/extensions/extension_management_unittest.cc
index 0864ff3..1622d94 100644
--- a/chrome/browser/extensions/extension_management_unittest.cc
+++ b/chrome/browser/extensions/extension_management_unittest.cc
@@ -309,7 +309,7 @@
     manifest_dict.Set(manifest_keys::kVersion, version);
     manifest_dict.Set(manifest_keys::kManifestVersion, 2);
     manifest_dict.Set(manifest_keys::kUpdateURL, update_url);
-    std::string error;
+    std::u16string error;
     scoped_refptr<const Extension> extension =
         Extension::Create(base::FilePath(), location, std::move(manifest_dict),
                           flags, id, &error);
@@ -434,7 +434,7 @@
     values->Set(manifest_keys::kName, "test");
     values->Set(manifest_keys::kVersion, "0.1");
     values->Set(manifest_keys::kManifestVersion, 2);
-    std::string error;
+    std::u16string error;
     extension_ = Extension::Create(base::FilePath(), location, *values,
                                    Extension::NO_FLAGS, &error);
     ASSERT_TRUE(extension_.get());
diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc
index b3d7bb7..7a13ba39 100644
--- a/chrome/browser/extensions/extension_prefs_unittest.cc
+++ b/chrome/browser/extensions/extension_prefs_unittest.cc
@@ -466,7 +466,7 @@
     manifest.Set(manifest_keys::kManifestVersion, 2);
     base::FilePath path =
         prefs_.extensions_dir().AppendASCII(base::NumberToString(num));
-    std::string errors;
+    std::u16string errors;
     scoped_refptr<Extension> extension =
         Extension::Create(path, ManifestLocation::kInternal, manifest,
                           Extension::NO_FLAGS, id, &errors);
@@ -590,7 +590,7 @@
     manifest.SetByDottedPath(manifest_keys::kBackgroundScripts,
                              std::move(scripts));
     base::FilePath path = prefs_.extensions_dir().AppendASCII("test_0.2");
-    std::string errors;
+    std::u16string errors;
     scoped_refptr<Extension> new_extension =
         Extension::Create(path, ManifestLocation::kInternal, manifest,
                           Extension::NO_FLAGS, id_, &errors);
@@ -816,7 +816,7 @@
 
 PrefsPrepopulatedTestBase::PrefsPrepopulatedTestBase() {
   base::Value::Dict simple_dict;
-  std::string error;
+  std::u16string error;
 
   simple_dict.Set(manifest_keys::kVersion, "1.0.0.0");
   simple_dict.Set(manifest_keys::kManifestVersion, 2);
diff --git a/chrome/browser/extensions/extension_special_storage_policy_unittest.cc b/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
index ec5ad06..cbb3d75 100644
--- a/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
+++ b/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
@@ -113,7 +113,7 @@
     list.Append("http://explicit/protected");
     list.Append("*://*.wildcards/protected");
     manifest.SetByDottedPath(keys::kWebURLs, std::move(list));
-    std::string error;
+    std::u16string error;
     scoped_refptr<Extension> protected_app =
         Extension::Create(path, ManifestLocation::kInvalidLocation, manifest,
                           Extension::NO_FLAGS, &error);
@@ -139,7 +139,7 @@
     list2.Append("http://explicit/unlimited");
     list2.Append("*://*.wildcards/unlimited");
     manifest.SetByDottedPath(keys::kWebURLs, std::move(list2));
-    std::string error;
+    std::u16string error;
     scoped_refptr<Extension> unlimited_app =
         Extension::Create(path, ManifestLocation::kInvalidLocation, manifest,
                           Extension::NO_FLAGS, &error);
@@ -158,7 +158,7 @@
     manifest.Set(keys::kVersion, "1");
     manifest.SetByDottedPath(keys::kPlatformAppBackgroundPage,
                              "background.html");
-    std::string error;
+    std::u16string error;
     scoped_refptr<Extension> app =
         Extension::Create(path, ManifestLocation::kInvalidLocation, manifest,
                           Extension::NO_FLAGS, &error);
diff --git a/chrome/browser/extensions/installed_loader.cc b/chrome/browser/extensions/installed_loader.cc
index d47c685..9b08573 100644
--- a/chrome/browser/extensions/installed_loader.cc
+++ b/chrome/browser/extensions/installed_loader.cc
@@ -288,14 +288,19 @@
       invalid_extensions_.end())
     return;
 
-  std::string error;
   scoped_refptr<const Extension> extension;
+  // TODO(crbug.com/41317803): Continue removing std::string errors and
+  // replacing with std::u16string.
+  std::string error_utf8;
+
   if (info.extension_manifest) {
+    std::u16string error_utf16;
     extension = Extension::Create(info.extension_path, info.extension_location,
                                   *info.extension_manifest,
-                                  GetCreationFlags(&info), &error);
+                                  GetCreationFlags(&info), &error_utf16);
+    error_utf8 = base::UTF16ToUTF8(error_utf16);
   } else {
-    error = manifest_errors::kManifestUnreadable;
+    error_utf8 = manifest_errors::kManifestUnreadable;
   }
 
   // Once installed, non-unpacked extensions cannot change their IDs (e.g., by
@@ -303,13 +308,13 @@
   // TODO(jstritar): migrate preferences when unpacked extensions change IDs.
   if (extension.get() && !Manifest::IsUnpackedLocation(extension->location()) &&
       info.extension_id != extension->id()) {
-    error = manifest_errors::kCannotChangeExtensionID;
+    error_utf8 = manifest_errors::kCannotChangeExtensionID;
     extension = nullptr;
   }
 
   if (!extension.get()) {
     LoadErrorReporter::GetInstance()->ReportLoadError(info.extension_path,
-                                                      error, profile_,
+                                                      error_utf8, profile_,
                                                       false);  // Be quiet.
     return;
   }
diff --git a/chrome/browser/extensions/permissions_based_management_policy_provider_unittest.cc b/chrome/browser/extensions/permissions_based_management_policy_provider_unittest.cc
index 297dd560..d769724 100644
--- a/chrome/browser/extensions/permissions_based_management_policy_provider_unittest.cc
+++ b/chrome/browser/extensions/permissions_based_management_policy_provider_unittest.cc
@@ -79,7 +79,7 @@
       manifest_dict.Set(manifest_keys::kOptionalPermissions,
                         optional_permissions->Clone());
     }
-    std::string error;
+    std::u16string error;
     scoped_refptr<const Extension> extension = Extension::Create(
         base::FilePath(), location, manifest_dict, Extension::NO_FLAGS, &error);
     CHECK(extension.get()) << error;
diff --git a/chrome/browser/extensions/test_extension_prefs.cc b/chrome/browser/extensions/test_extension_prefs.cc
index 584e205..1035fe6 100644
--- a/chrome/browser/extensions/test_extension_prefs.cc
+++ b/chrome/browser/extensions/test_extension_prefs.cc
@@ -183,7 +183,7 @@
   const std::string* name = manifest.FindString(manifest_keys::kName);
   EXPECT_TRUE(name);
   base::FilePath path = extensions_dir_.AppendASCII(*name);
-  std::string errors;
+  std::u16string errors;
   scoped_refptr<Extension> extension =
       Extension::Create(path, location, manifest, extra_flags, &errors);
   EXPECT_TRUE(extension.get()) << errors;
diff --git a/chrome/browser/extensions/user_script_listener_unittest.cc b/chrome/browser/extensions/user_script_listener_unittest.cc
index c1d6f606..2928a5877 100644
--- a/chrome/browser/extensions/user_script_listener_unittest.cc
+++ b/chrome/browser/extensions/user_script_listener_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/scoped_test_mv2_enabler.h"
@@ -70,6 +71,8 @@
   return std::move(*manifest).TakeDict();
 }
 
+// TODO(crbug.com/41317803): Continue removing std::string error and
+// replacing with std::u16string.
 scoped_refptr<Extension> LoadExtension(const std::string& filename,
                                        std::string* error) {
   base::FilePath path;
@@ -81,8 +84,12 @@
   if (!manifest) {
     return nullptr;
   }
-  return Extension::Create(path.DirName(), mojom::ManifestLocation::kUnpacked,
-                           *manifest, Extension::NO_FLAGS, error);
+  std::u16string utf16_error;
+  scoped_refptr<Extension> extension =
+      Extension::Create(path.DirName(), mojom::ManifestLocation::kUnpacked,
+                        *manifest, Extension::NO_FLAGS, &utf16_error);
+  *error = base::UTF16ToUTF8(utf16_error);
+  return extension;
 }
 
 }  // namespace
diff --git a/chrome/browser/extensions/webstore_standalone_installer.cc b/chrome/browser/extensions/webstore_standalone_installer.cc
index b6644eed..cd08abd 100644
--- a/chrome/browser/extensions/webstore_standalone_installer.cc
+++ b/chrome/browser/extensions/webstore_standalone_installer.cc
@@ -152,7 +152,7 @@
     if (!manifest_.has_value())
       return nullptr;
 
-    std::string error;
+    std::u16string error;
     localized_extension_for_display_ =
         ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
             *manifest_, Extension::REQUIRE_KEY | Extension::FROM_WEBSTORE, id_,
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index cbca9bc..7dbaf2fe 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -921,6 +921,11 @@
     "expiry_milestone": 140
   },
   {
+    "name": "autofill-enable-keyboard-accessory-chip-redesign",
+    "owners": [ "tchudakov@google.com", "jkeitel@google.com"],
+    "expiry_milestone": 150
+  },
+  {
     "name": "autofill-enable-loyalty-cards-filling",
     "owners": [ "vizcay@google.com", "tchudakov@google.com"],
     "expiry_milestone": 145
@@ -1489,6 +1494,11 @@
       "expiry_milestone": 140
   },
   {
+    "name": "cache-identity-list-in-chrome",
+    "owners": [ "arthurmilchior@google.com", "chrome-signin-mobile-team@google.com" ],
+    "expiry_milestone": 150
+  },
+  {
     "name": "calculate-native-win-occlusion",
     "owners": [ "davidbienvenu@chromium.org", "fdoray@chromium.org" ],
     "expiry_milestone": 130
@@ -3225,11 +3235,6 @@
     "expiry_milestone": 120
   },
   {
-    "name": "enable-cros-ime-korean-only-mode-switch-on-right-alt",
-    "owners": [ "tranbaoduy@chromium.org", "essential-inputs-team@google.com" ],
-    "expiry_milestone": 123
-  },
-  {
     "name": "enable-cros-ime-manifest-v3",
     "owners": [ "jopalmer@chromium.org", "essential-inputs-team@google.com" ],
     "expiry_milestone": 150
@@ -3265,21 +3270,11 @@
     "expiry_milestone": 120
   },
   {
-    "name": "enable-cros-japanese-os-settings",
-    "owners": [ "jhtin@google.com", "essential-inputs-team@google.com" ],
-    "expiry_milestone": 120
-  },
-  {
     "name": "enable-cros-separate-geo-api-key",
     "owners": [ "zauri@google.com", "cros-privacy-features-dev@google.com"],
     "expiry_milestone": 146
   },
   {
-    "name": "enable-cros-system-japanese-physical-typing",
-    "owners": [ "jhtin@chromium.org", "essential-inputs-team@google.com" ],
-    "expiry_milestone": 146
-  },
-  {
     "name": "enable-cros-touch-text-editing-redesign",
     "owners": [ "michellegc@chromium.org", "essential-inputs-team@google.com" ],
     "expiry_milestone": 140
@@ -4396,11 +4391,6 @@
     "expiry_milestone": -1
   },
   {
-    "name": "enable-signed-out-view-demotion",
-    "owners": [ "sczs@chromium.org", "tinazwang@chromium.org" ],
-    "expiry_milestone": 135
-  },
-  {
     "name": "enable-site-isolation-for-password-sites",
     "owners": [ "site-isolation-dev@chromium.org", "alexmos@chromium.org", "lukasza@chromium.org" ],
     // Note: while password-triggered site isolation launched in M77, it only
@@ -9132,7 +9122,7 @@
   {
     "name": "search-in-cct",
     "owners": [ "ender@google.com", "chrome-mobile-search@google.com" ],
-    "expiry_milestone": 150
+    "expiry_milestone": 300
   },
   {
     "name": "search-in-cct-alternate-tap-handling",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 2c33f19..028715d 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -839,6 +839,12 @@
     "When enabled, flat rate card benefits sourced from Curinos will be shown "
     "in Autofill suggestions.";
 
+const char kAutofillEnableKeyboardAccessoryChipRedesignName[] =
+    "Enable 2 line chips in the Chrome Keyboard Accessory";
+const char kAutofillEnableKeyboardAccessoryChipRedesignDescription[] =
+    "When enabled, Autofill information is displayed on 2 lines in the Chrome "
+    "KeyboardAccessory";
+
 const char kAutofillEnableLoyaltyCardsFillingName[] =
     "Enable Autofill support for filling loyalty cards";
 const char kAutofillEnableLoyaltyCardsFillingDescription[] =
@@ -2521,10 +2527,6 @@
     "different device will not be considered valid, leading to the choice "
     "screen potentially retriggering.";
 
-const char kJapaneseOSSettingsName[] = "Japanese OS Settings Page";
-const char kJapaneseOSSettingsDescription[] =
-    "Enable OS Settings Page for Japanese input methods";
-
 const char kJavascriptHarmonyName[] = "Experimental JavaScript";
 const char kJavascriptHarmonyDescription[] =
     "Enable web pages to use experimental JavaScript features.";
@@ -6430,12 +6432,6 @@
     "Enables the ChromeOS APN Revamp, which updates cellular network APN "
     "system UI and related infrastructure.";
 
-const char kArcCustomTabsExperimentName[] =
-    "Enable Custom Tabs experiment for ARC";
-const char kArcCustomTabsExperimentDescription[] =
-    "Allow Android apps to use Custom Tabs."
-    "This feature only works on the Canary and Dev channels.";
-
 const char kArcEnableAttestationName[] = "Enable ARC attestation";
 const char kArcEnableAttestationDescription[] =
     "Allow key and ID attestation to run for keymint";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 472eaed..0622087 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -519,6 +519,9 @@
 extern const char kAutofillEnableFlatRateCardBenefitsFromCurinosName[];
 extern const char kAutofillEnableFlatRateCardBenefitsFromCurinosDescription[];
 
+extern const char kAutofillEnableKeyboardAccessoryChipRedesignName[];
+extern const char kAutofillEnableKeyboardAccessoryChipRedesignDescription[];
+
 extern const char kAutofillEnableLoyaltyCardsFillingName[];
 extern const char kAutofillEnableLoyaltyCardsFillingDescription[];
 
@@ -1470,9 +1473,6 @@
 extern const char
     kInvalidateSearchEngineChoiceOnDeviceRestoreDetectionDescription[];
 
-extern const char kJapaneseOSSettingsName[];
-extern const char kJapaneseOSSettingsDescription[];
-
 extern const char kJavascriptHarmonyName[];
 extern const char kJavascriptHarmonyDescription[];
 
@@ -3715,8 +3715,6 @@
 extern const char kApnRevampName[];
 extern const char kApnRevampDescription[];
 
-extern const char kArcCustomTabsExperimentName[];
-extern const char kArcCustomTabsExperimentDescription[];
 
 extern const char kArcEnableAttestationName[];
 extern const char kArcEnableAttestationDescription[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 165e66a..24531fd 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -258,6 +258,7 @@
     &kBookmarkPaneAndroid,
     &kBrowserControlsDebugging,
     &kBrowserControlsEarlyResize,
+    &kBrowserControlsRenderDrivenShowConstraint,
     &kCacheActivityTaskID,
     &kCacheIsMultiInstanceApi31Enabled,
     &kCastDeviceFilter,
@@ -680,6 +681,9 @@
 
 BASE_FEATURE(kBrowserControlsEarlyResize, base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kBrowserControlsRenderDrivenShowConstraint,
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 BASE_FEATURE(kCacheActivityTaskID, base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE(kCacheIsMultiInstanceApi31Enabled,
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 88c180c..58a0cc9 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -79,6 +79,7 @@
 BASE_DECLARE_FEATURE(kBookmarkPaneAndroid);
 BASE_DECLARE_FEATURE(kBrowserControlsDebugging);
 BASE_DECLARE_FEATURE(kBrowserControlsEarlyResize);
+BASE_DECLARE_FEATURE(kBrowserControlsRenderDrivenShowConstraint);
 BASE_DECLARE_FEATURE(kCacheActivityTaskID);
 BASE_DECLARE_FEATURE(kCacheIsMultiInstanceApi31Enabled);
 BASE_DECLARE_FEATURE(kCastDeviceFilter);
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 ade6d4c..eee3be1b 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
@@ -298,6 +298,8 @@
     public static final String BROWSER_CONTROLS_DEBUGGING = "BrowserControlsDebugging";
     public static final String BROWSER_CONTROLS_EARLY_RESIZE = "BrowserControlsEarlyResize";
     public static final String BROWSER_CONTROLS_IN_VIZ = "AndroidBrowserControlsInViz";
+    public static final String BROWSER_CONTROLS_RENDER_DRIVEN_SHOW_CONSTRAINT =
+            "BrowserControlsRenderDrivenShowConstraint";
     public static final String BROWSING_DATA_MODEL = "BrowsingDataModel";
     public static final String CACHE_ACTIVITY_TASKID = "CacheActivityTaskID";
     public static final String CACHE_IS_MULTI_INSTANCE_API_31_ENABLED =
@@ -1305,6 +1307,9 @@
             newMutableFlagWithSafeDefault(BROWSER_CONTROLS_EARLY_RESIZE, false);
     public static final MutableFlagWithSafeDefault sBrowserControlsInViz =
             newMutableFlagWithSafeDefault(BROWSER_CONTROLS_IN_VIZ, true);
+    // Default to false. The logic behind the flag is not relevant when native is not initialized.
+    public static final MutableFlagWithSafeDefault sBrowserControlsRenderDrivenShowConstraint =
+            newMutableFlagWithSafeDefault(BROWSER_CONTROLS_RENDER_DRIVEN_SHOW_CONSTRAINT, false);
     public static final MutableFlagWithSafeDefault sChromeNativeUrlOverriding =
             newMutableFlagWithSafeDefault(CHROME_NATIVE_URL_OVERRIDING, false);
     public static final MutableFlagWithSafeDefault sClearBrowsingDataAndroidSurvey =
@@ -1692,14 +1697,6 @@
     public static final BooleanCachedFeatureParam sSearchinCctApplyReferrerId =
             newBooleanCachedFeatureParam(SEARCH_IN_CCT, "apply_referrer_id", false);
 
-    /** Pipe ("|") separated list of package names allowed to use the interactive Omnibox. */
-    // TODO(crbug.com/40239922): remove default value when no longer relevant.
-    public static final StringCachedFeatureParam sSearchinCctOmniboxAllowedPackageNames =
-            newStringCachedFeatureParam(
-                    SEARCH_IN_CCT,
-                    "omnibox_allowed_package_names",
-                    BuildConfig.ENABLE_DEBUG_LOGS ? "org.chromium.customtabsclient" : "");
-
     public static final IntCachedFeatureParam sStartSurfaceReturnTimeTabletSecs =
             newIntCachedFeatureParam(
                     START_SURFACE_RETURN_TIME,
@@ -1815,7 +1812,6 @@
                     sReadAloudAudioOverviewsSpeedAdditionPercentage,
                     sReadAloudReadabilityDelayMsAfterPageLoad,
                     sSearchinCctApplyReferrerId,
-                    sSearchinCctOmniboxAllowedPackageNames,
                     sShouldConsiderLanguageInOverviewReadability,
                     sStartSurfaceReturnTimeTabletSecs,
                     sTabGroupListContainment,
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureListUnitTest.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureListUnitTest.java
index 33aa3164..d4b905ff 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureListUnitTest.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureListUnitTest.java
@@ -22,8 +22,11 @@
 import org.chromium.components.cached_flags.CachedFlag;
 
 import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
 /** Tests the behavior of {@link ChromeFeatureList}. */
@@ -160,4 +163,30 @@
                 Collections.emptySet(),
                 listedButNotDeclared);
     }
+
+    @Test
+    public void testFeatureNamesHaveUniqueValues() throws IllegalAccessException {
+        final Map<String, String> featureNamesValuesToSymbols = new HashMap<>();
+
+        for (Field field : ChromeFeatureList.class.getDeclaredFields()) {
+            if (field.getType() != String.class || !Modifier.isPublic(field.getModifiers())) {
+                continue;
+            }
+
+            final String fieldValue = (String) field.get(null);
+            final String fieldSymbol = field.getName();
+            final String maybeOtherSymbolWithEqualValue =
+                    featureNamesValuesToSymbols.get(fieldValue);
+
+            assertTrue(
+                    "Two feature name declarations ("
+                            + fieldSymbol
+                            + " and "
+                            + maybeOtherSymbolWithEqualValue
+                            + ") share the same value "
+                            + fieldValue,
+                    maybeOtherSymbolWithEqualValue == null);
+            featureNamesValuesToSymbols.put(fieldValue, fieldSymbol);
+        }
+    }
 }
diff --git a/chrome/browser/media_galleries/media_galleries_test_util.cc b/chrome/browser/media_galleries/media_galleries_test_util.cc
index b0efe4c..5faca36 100644
--- a/chrome/browser/media_galleries/media_galleries_test_util.cc
+++ b/chrome/browser/media_galleries/media_galleries_test_util.cc
@@ -15,6 +15,7 @@
 #include "base/files/file_util.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
@@ -67,12 +68,12 @@
   extensions::ExtensionPrefs* extension_prefs =
       extensions::ExtensionPrefs::Get(profile);
   base::FilePath path = extension_prefs->install_directory().AppendASCII(name);
-  std::string errors;
+  std::u16string utf16_error;
   scoped_refptr<extensions::Extension> extension =
       extensions::Extension::Create(
           path, extensions::mojom::ManifestLocation::kInternal, manifest,
-          extensions::Extension::NO_FLAGS, &errors);
-  EXPECT_TRUE(extension.get() != nullptr) << errors;
+          extensions::Extension::NO_FLAGS, std::string(), &utf16_error);
+  EXPECT_TRUE(extension.get() != nullptr) << utf16_error;
   EXPECT_TRUE(crx_file::id_util::IdIsValid(extension->id()));
   if (!extension.get() || !crx_file::id_util::IdIsValid(extension->id()))
     return nullptr;
diff --git a/chrome/browser/new_tab_page/ntp_promo/ntp_promo_interactive_uitest.cc b/chrome/browser/new_tab_page/ntp_promo/ntp_promo_interactive_uitest.cc
index 07183df..326b68d 100644
--- a/chrome/browser/new_tab_page/ntp_promo/ntp_promo_interactive_uitest.cc
+++ b/chrome/browser/new_tab_page/ntp_promo/ntp_promo_interactive_uitest.cc
@@ -403,7 +403,13 @@
       CheckShowMetrics(ShowNtpPromosResult::kShown));
 }
 
-IN_PROC_BROWSER_TEST_P(NtpPromoUiTest, TestPromoCompleted) {
+// TODO(crbug.com/448993914): Re-enable this test
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_TestPromoCompleted DISABLED_TestPromoCompleted
+#else
+#define MAYBE_TestPromoCompleted TestPromoCompleted
+#endif
+IN_PROC_BROWSER_TEST_P(NtpPromoUiTest, MAYBE_TestPromoCompleted) {
   InstallTestPromo(Eligibility::kCompleted);
   RunTestSequence(
       InstrumentTab(kNtpElementId),
@@ -476,6 +482,13 @@
 // or run these tests on ChromeOS.
 #if !BUILDFLAG(IS_CHROMEOS)
 
+// TODO(crbug.com/448993914): Re-enable this test
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_SigninPromoAppearsAndIsClickable \
+  DISABLED_SigninPromoAppearsAndIsClickable
+#else
+#define MAYBE_SigninPromoAppearsAndIsClickable SigninPromoAppearsAndIsClickable
+#endif
 IN_PROC_BROWSER_TEST_P(NtpPromoUiTest, SigninPromoAppearsAndIsClickable) {
   ClearRegisteredPromosExcept(kNtpSignInPromoId);
   RunTestSequence(
@@ -500,7 +513,16 @@
 
 #endif  // !BUILDFLAG(IS_CHROMEOS)
 
-IN_PROC_BROWSER_TEST_P(NtpPromoUiTest, ExtensionsPromoAppearsAndIsClickable) {
+// TODO(crbug.com/448993914): Re-enable this test
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_ExtensionsPromoAppearsAndIsClickable \
+  DISABLED_ExtensionsPromoAppearsAndIsClickable
+#else
+#define MAYBE_ExtensionsPromoAppearsAndIsClickable \
+  ExtensionsPromoAppearsAndIsClickable
+#endif
+IN_PROC_BROWSER_TEST_P(NtpPromoUiTest,
+                       MAYBE_ExtensionsPromoAppearsAndIsClickable) {
   ClearRegisteredPromosExcept(kNtpExtensionsPromoId);
   RunTestSequence(
       InstrumentTab(kNtpElementId),
@@ -522,8 +544,16 @@
   // TODD(https://crbug.com/433607240): Check model, histograms.
 }
 
+// TODO(crbug.com/448993914): Re-enable this test
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_CustomizationPromoAppearsAndIsClickable \
+  DISABLED_CustomizationPromoAppearsAndIsClickable
+#else
+#define MAYBE_CustomizationPromoAppearsAndIsClickable \
+  CustomizationPromoAppearsAndIsClickable
+#endif
 IN_PROC_BROWSER_TEST_P(NtpPromoUiTest,
-                       CustomizationPromoAppearsAndIsClickable) {
+                       MAYBE_CustomizationPromoAppearsAndIsClickable) {
   ClearRegisteredPromosExcept(kNtpCustomizationPromoId);
   RunTestSequence(
       InstrumentTab(kNtpElementId),
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
index 1058152b..c9f5b54 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
@@ -391,9 +391,17 @@
 
 // Test that viewport ad density does not accumulate for ads that are injected
 // while the tab is in the background.
+// TODO(crbug.com/448982399): Re-enable this test
+#if BUILDFLAG(IS_MAC) && defined(ARCH_CPU_X86_64)
+#define MAYBE_AdDensity_AdCreatedInBackgroundNotAccountedWhileInBackground \
+  DISABLED_AdDensity_AdCreatedInBackgroundNotAccountedWhileInBackground
+#else
+#define MAYBE_AdDensity_AdCreatedInBackgroundNotAccountedWhileInBackground \
+  AdDensity_AdCreatedInBackgroundNotAccountedWhileInBackground
+#endif
 IN_PROC_BROWSER_TEST_F(
     AdsPageLoadMetricsObserverBrowserTest,
-    AdDensity_AdCreatedInBackgroundNotAccountedWhileInBackground) {
+    MAYBE_AdDensity_AdCreatedInBackgroundNotAccountedWhileInBackground) {
   SetRulesetWithRules(
       {subresource_filter::testing::CreateSuffixRule("pixel.png")});
 
diff --git a/chrome/browser/platform_util_unittest.cc b/chrome/browser/platform_util_unittest.cc
index c74778f..71cd248 100644
--- a/chrome/browser/platform_util_unittest.cc
+++ b/chrome/browser/platform_util_unittest.cc
@@ -119,12 +119,14 @@
     base::Value::Dict* manifest_dictionary = manifest->GetIfDict();
     ASSERT_TRUE(manifest_dictionary);
 
+    std::u16string utf16_error;
     scoped_refptr<extensions::Extension> extension =
         extensions::Extension::Create(
             test_directory.AppendASCII("invalid-extension"),
             extensions::mojom::ManifestLocation::kInvalidLocation,
-            *manifest_dictionary, extensions::Extension::NO_FLAGS, &error);
-    ASSERT_TRUE(error.empty()) << error;
+            *manifest_dictionary, extensions::Extension::NO_FLAGS,
+            &utf16_error);
+    ASSERT_TRUE(utf16_error.empty()) << utf16_error;
 
     std::vector<apps::AppPtr> apps;
     auto app = std::make_unique<apps::App>(apps::AppType::kChromeApp,
diff --git a/chrome/browser/profile_resetter/profile_resetter_unittest.cc b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
index 63e10f6c..d4857cf 100644
--- a/chrome/browser/profile_resetter/profile_resetter_unittest.cc
+++ b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
@@ -372,7 +372,7 @@
       NOTREACHED();
   }
   manifest.SetByDottedPath(extensions::manifest_keys::kOmniboxKeyword, name);
-  std::string error;
+  std::u16string error;
   scoped_refptr<Extension> extension = Extension::Create(
       path,
       location,
diff --git a/chrome/browser/resources/ash/settings/os_languages_page/input_method_options_page.ts b/chrome/browser/resources/ash/settings/os_languages_page/input_method_options_page.ts
index 73c66a8..ddbbf8c 100644
--- a/chrome/browser/resources/ash/settings/os_languages_page/input_method_options_page.ts
+++ b/chrome/browser/resources/ash/settings/os_languages_page/input_method_options_page.ts
@@ -249,8 +249,6 @@
           loadTimeData.getBoolean('isPhysicalKeyboardAutocorrectAllowed'),
       isPhysicalKeyboardPredictiveWritingAllowed:
           loadTimeData.getBoolean('isPhysicalKeyboardPredictiveWritingAllowed'),
-      isJapaneseSettingsAllowed:
-          loadTimeData.getBoolean('systemJapanesePhysicalTyping'),
       isVietnameseFirstPartyInputSettingsAllowed:
           loadTimeData.getBoolean('allowFirstPartyVietnameseInput'),
     });
diff --git a/chrome/browser/resources/ash/settings/os_languages_page/input_method_settings.ts b/chrome/browser/resources/ash/settings/os_languages_page/input_method_settings.ts
index 4649880f..0144195a1 100644
--- a/chrome/browser/resources/ash/settings/os_languages_page/input_method_settings.ts
+++ b/chrome/browser/resources/ash/settings/os_languages_page/input_method_settings.ts
@@ -9,7 +9,6 @@
 export interface SettingsContext {
   isPhysicalKeyboardAutocorrectAllowed: boolean;
   isPhysicalKeyboardPredictiveWritingAllowed: boolean;
-  isJapaneseSettingsAllowed: boolean;
   isVietnameseFirstPartyInputSettingsAllowed: boolean;
 }
 
@@ -97,6 +96,10 @@
     // ZHUYIN_SETTINGS
     'zh-hant-t-i0-und': [SettingsType.ZHUYIN_SETTINGS],
 
+    // JAPANESE SETTINGS
+    'nacl_mozc_jp': [SettingsType.JAPANESE_SETTINGS],
+    'nacl_mozc_us': [SettingsType.JAPANESE_SETTINGS],
+
     // KOREAN_SETTINGS
     'ko-t-i0-und': [SettingsType.KOREAN_SETTINGS],
 
@@ -151,12 +154,6 @@
 
   };
 
-  // MOZC settings
-  if (context.isJapaneseSettingsAllowed) {
-    settingsMap['nacl_mozc_jp'] = [SettingsType.JAPANESE_SETTINGS];
-    settingsMap['nacl_mozc_us'] = [SettingsType.JAPANESE_SETTINGS];
-  }
-
   // Vietnamese first party input
   if (context.isVietnameseFirstPartyInputSettingsAllowed) {
     settingsMap['vkd_vi_telex'] = [SettingsType.VIETNAMESE_TELEX_SETTINGS];
diff --git a/chrome/browser/resources/ash/settings/os_languages_page/input_page.ts b/chrome/browser/resources/ash/settings/os_languages_page/input_page.ts
index 0a1052db..11fbee0 100644
--- a/chrome/browser/resources/ash/settings/os_languages_page/input_page.ts
+++ b/chrome/browser/resources/ash/settings/os_languages_page/input_page.ts
@@ -100,13 +100,6 @@
         value: false,
       },
 
-      languageSettingsJapaneseEnabled_: {
-        type: Boolean,
-        value() {
-          return loadTimeData.getBoolean('systemJapanesePhysicalTyping');
-        },
-      },
-
       /**
        * Whether the shortcut reminder for the last used IME is currently
        * showing.
@@ -200,7 +193,6 @@
 
   // loadTimeData flags.
   private onDeviceGrammarCheckEnabled_: boolean;
-  private languageSettingsJapaneseEnabled_: boolean;
   private languagePacksInSettingsEnabled_ =
       loadTimeData.getBoolean('languagePacksInSettingsEnabled');
   private readonly allowEmojiSuggestion_: boolean =
@@ -384,8 +376,6 @@
           loadTimeData.getBoolean('isPhysicalKeyboardAutocorrectAllowed'),
       isPhysicalKeyboardPredictiveWritingAllowed:
           loadTimeData.getBoolean('isPhysicalKeyboardPredictiveWritingAllowed'),
-      isJapaneseSettingsAllowed:
-          loadTimeData.getBoolean('systemJapanesePhysicalTyping'),
       isVietnameseFirstPartyInputSettingsAllowed:
           loadTimeData.getBoolean('allowFirstPartyVietnameseInput'),
     });
diff --git a/chrome/browser/safe_browsing/chrome_ui_manager_delegate_unittest.cc b/chrome/browser/safe_browsing/chrome_ui_manager_delegate_unittest.cc
index be03389..6fb34b55 100644
--- a/chrome/browser/safe_browsing/chrome_ui_manager_delegate_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_ui_manager_delegate_unittest.cc
@@ -39,7 +39,7 @@
   manifest.Set(extensions::manifest_keys::kVersion, "0.0.0.0");
   manifest.SetByDottedPath(
       extensions::manifest_keys::kPlatformAppBackgroundPage, "background.html");
-  std::string error;
+  std::u16string error;
   scoped_refptr<extensions::Extension> app;
   app = extensions::Extension::Create(
       base::FilePath(), extensions::mojom::ManifestLocation::kComponent,
diff --git a/chrome/browser/sync/glue/extensions_activity_monitor_unittest.cc b/chrome/browser/sync/glue/extensions_activity_monitor_unittest.cc
index 74b36b1..30a6b55c 100644
--- a/chrome/browser/sync/glue/extensions_activity_monitor_unittest.cc
+++ b/chrome/browser/sync/glue/extensions_activity_monitor_unittest.cc
@@ -44,7 +44,7 @@
   value.Set(keys::kManifestVersion, 2);
   value.Set(keys::kVersion, "1.0.0.0");
   value.Set(keys::kName, name);
-  std::string error;
+  std::u16string error;
   scoped_refptr<Extension> extension(Extension::Create(
       path, extensions::mojom::ManifestLocation::kInvalidLocation, value,
       Extension::NO_FLAGS, &error));
diff --git a/chrome/browser/sync/test/integration/sync_extension_helper.cc b/chrome/browser/sync/test/integration/sync_extension_helper.cc
index 4ed42b940..80849c1 100644
--- a/chrome/browser/sync/test/integration/sync_extension_helper.cc
+++ b/chrome/browser/sync/test/integration/sync_extension_helper.cc
@@ -366,7 +366,7 @@
     ADD_FAILURE();
     return nullptr;
   }
-  std::string error;
+  std::u16string error;
   scoped_refptr<Extension> extension = Extension::Create(
       extension_dir, extensions::mojom::ManifestLocation::kInternal, source,
       Extension::NO_FLAGS, &error);
diff --git a/chrome/browser/themes/browser_theme_pack_unittest.cc b/chrome/browser/themes/browser_theme_pack_unittest.cc
index 05851ce..2ef853a 100644
--- a/chrome/browser/themes/browser_theme_pack_unittest.cc
+++ b/chrome/browser/themes/browser_theme_pack_unittest.cc
@@ -331,11 +331,12 @@
       deserializer.Deserialize(nullptr, &error);
   EXPECT_EQ("", error);
   ASSERT_TRUE(valid_value.get() && valid_value->is_dict());
+  std::u16string utf16_error;
   scoped_refptr<Extension> extension(Extension::Create(
       extension_path, extensions::mojom::ManifestLocation::kInvalidLocation,
-      valid_value->GetDict(), Extension::NO_FLAGS, &error));
+      valid_value->GetDict(), Extension::NO_FLAGS, &utf16_error));
   ASSERT_TRUE(extension.get());
-  ASSERT_EQ("", error);
+  ASSERT_EQ(u"", utf16_error);
   BrowserThemePack::BuildFromExtension(extension.get(), pack);
 }
 
diff --git a/chrome/browser/themes/theme_service_test_utils.cc b/chrome/browser/themes/theme_service_test_utils.cc
index cf50752..95e9dd3 100644
--- a/chrome/browser/themes/theme_service_test_utils.cc
+++ b/chrome/browser/themes/theme_service_test_utils.cc
@@ -43,13 +43,13 @@
   source.Set(extensions::manifest_keys::kTheme, base::Value::Dict());
   source.Set(extensions::manifest_keys::kUpdateURL, update_url);
   source.Set(extensions::manifest_keys::kVersion, "0.0.0.0");
-  std::string error;
+  std::u16string error;
   scoped_refptr<extensions::Extension> extension =
       extensions::Extension::Create(extension_path, location, source,
                                     extensions::Extension::NO_FLAGS, id,
                                     &error);
   EXPECT_TRUE(extension.get());
-  EXPECT_EQ("", error);
+  EXPECT_EQ(u"", error);
   return extension;
 }
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 89aa6b2f..d6bb436 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3187,6 +3187,7 @@
       "//chrome/browser/apps/app_shim",
       "//chrome/browser/enterprise/connectors/device_trust/key_management/core/mac",
       "//chrome/browser/updater:browser_updater_client",
+      "//chrome/browser/web_applications/extensions",
       "//chrome/updater:browser_sources",
       "//components/remote_cocoa/app_shim",
       "//components/remote_cocoa/app_shim:features",
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/action/OmniboxPedal.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/action/OmniboxPedal.java
index 6be471a..04aaa6dd 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/action/OmniboxPedal.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/action/OmniboxPedal.java
@@ -7,6 +7,8 @@
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.build.annotations.NullMarked;
+import org.chromium.chrome.browser.url_constants.UrlConstantResolver;
+import org.chromium.chrome.browser.url_constants.UrlConstantResolverFactory;
 import org.chromium.components.browser_ui.settings.SettingsNavigation.SettingsFragment;
 import org.chromium.components.embedder_support.util.UrlConstants;
 import org.chromium.components.omnibox.R;
@@ -67,7 +69,9 @@
                 delegate.openSettingsPage(SettingsFragment.ACCESSIBILITY);
                 break;
             case OmniboxPedalId.VIEW_CHROME_HISTORY:
-                delegate.loadPageInCurrentTab(UrlConstants.HISTORY_URL);
+                UrlConstantResolver resolver =
+                        UrlConstantResolverFactory.getForProfile(/* profile= */ null);
+                delegate.loadPageInCurrentTab(resolver.getHistoryPageUrl());
                 break;
             case OmniboxPedalId.PLAY_CHROME_DINO_GAME:
                 delegate.loadPageInCurrentTab(UrlConstants.CHROME_DINO_URL);
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/action/OmniboxPedalUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/action/OmniboxPedalUnitTest.java
index 9db90d6..611e1f85 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/action/OmniboxPedalUnitTest.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/action/OmniboxPedalUnitTest.java
@@ -163,7 +163,7 @@
     @Test
     public void executePedal_viewChromeHistory() {
         new OmniboxPedal(0, "hint", "", OmniboxPedalId.VIEW_CHROME_HISTORY).execute(mDelegate);
-        verify(mDelegate, times(1)).loadPageInCurrentTab(UrlConstants.HISTORY_URL);
+        verify(mDelegate, times(1)).loadPageInCurrentTab(UrlConstants.NATIVE_HISTORY_URL);
         verifyNoMoreInteractions(mDelegate);
     }
 
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index ea68d1c..45d671d 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -5458,6 +5458,9 @@
       <message name="IDS_KEYBOARD_SHORTCUT_TOGGLE_BOOKMARK_BAR" desc="A text label that appears next to the keyboard shortcut that will toggle the bookmark bar. The shortcut description is shown in a system dialog along with all other supported shortcuts. [CHAR_LIMIT=55]">
         Show or hide Bookmarks bar
       </message>
+      <message name="IDS_KEYBOARD_SHORTCUT_VIEW_SOURCE" desc="A text label that appears next to the keyboard shortcut that will display non-editable HTML source code for the current page. The shortcut description is shown in a system dialog along with all other supported shortcuts. [CHAR_LIMIT=55]">
+        View page source
+      </message>
       <message name="IDS_KEYBOARD_SHORTCUT_DEVELOPER_TOOLS" desc="A text label that appears next to the keyboard shortcut that will open Developer Tools. The shortcut description is shown in a system dialog along with all other supported shortcuts. [CHAR_LIMIT=55]">
         Open Developer Tools
       </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_KEYBOARD_SHORTCUT_VIEW_SOURCE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_KEYBOARD_SHORTCUT_VIEW_SOURCE.png.sha1
new file mode 100644
index 0000000..6d9a9c3
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_KEYBOARD_SHORTCUT_VIEW_SOURCE.png.sha1
@@ -0,0 +1 @@
+d2af500b60ab6c95b94ddbf7ebca079277a88749
\ No newline at end of file
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
index b78d9e5..c530a71 100644
--- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
+++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
@@ -588,7 +588,7 @@
         app_list::AppListSyncableServiceFactory::GetForProfile(profile());
     StartAppSyncService(app_list_syncable_service_->GetAllSyncDataForTesting());
 
-    std::string error;
+    std::u16string error;
     extension_chrome_ = Extension::Create(
         base::FilePath(), ManifestLocation::kUnpacked, manifest,
         Extension::NO_FLAGS, app_constants::kChromeAppId, &error);
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 767da91..d575635b 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -25,9 +25,6 @@
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/apps/app_service/app_launch_params.h"
-#include "chrome/browser/apps/app_service/app_service_proxy.h"
-#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
-#include "chrome/browser/apps/app_service/browser_app_launcher.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
@@ -236,6 +233,10 @@
 #include "chrome/browser/apps/link_capturing/enable_link_capturing_infobar_delegate.h"
 #endif
 
+#if BUILDFLAG(IS_MAC)
+#include "chrome/browser/web_applications/extensions/launch.h"
+#endif
+
 #if BUILDFLAG(ENABLE_LENS_DESKTOP_GOOGLE_BRANDED_FEATURES)
 #include "chrome/browser/lens/region_search/lens_region_search_controller.h"
 #include "chrome/browser/lens/region_search/lens_region_search_helper.h"
@@ -1048,9 +1049,8 @@
     apps::AppLaunchParams params = apps::AppLaunchParams(
         app_id, launch_container, WindowOpenDisposition::NEW_WINDOW,
         apps::LaunchSource::kFromKeyboard);
-    apps::AppServiceProxyFactory::GetForProfile(profile)
-        ->BrowserAppLauncher()
-        ->LaunchAppWithParams(std::move(params), base::DoNothing());
+    web_app::LaunchExtensionOrWebApp(profile, std::move(params),
+                                     base::DoNothing());
     return;
   }
 
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
index 78a35c76..0b16f15 100644
--- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
+++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
@@ -11,9 +11,6 @@
 #include "base/functional/callback_helpers.h"
 #include "base/memory/raw_ptr.h"
 #include "chrome/browser/apps/app_service/app_launch_params.h"
-#include "chrome/browser/apps/app_service/app_service_proxy.h"
-#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
-#include "chrome/browser/apps/app_service/browser_app_launcher.h"
 #include "chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h"
 #include "chrome/browser/apps/app_shim/app_shim_host_mac.h"
 #include "chrome/browser/apps/app_shim/app_shim_manager_mac.h"
@@ -22,6 +19,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/web_applications/extensions/launch.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
@@ -67,14 +65,12 @@
 
     for (int i = 0; i < num_windows; ++i) {
       content::CreateAndLoadWebContentsObserver app_loaded_observer;
-      apps::AppServiceProxyFactory::GetForProfile(profile())
-          ->BrowserAppLauncher()
-          ->LaunchAppWithParams(
-              apps::AppLaunchParams(app->id(),
-                                    apps::LaunchContainer::kLaunchContainerNone,
-                                    WindowOpenDisposition::NEW_WINDOW,
-                                    apps::LaunchSource::kFromTest),
-              base::DoNothing());
+      web_app::LaunchExtensionOrWebApp(
+          profile(),
+          apps::AppLaunchParams(
+              app->id(), apps::LaunchContainer::kLaunchContainerNone,
+              WindowOpenDisposition::NEW_WINDOW, apps::LaunchSource::kFromTest),
+          base::DoNothing());
       app_loaded_observer.Wait();
     }
   }
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 7f1f97f..3bf509a 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -395,6 +395,47 @@
                         tabs::TabInterface::DetachReason::kDelete);
 }
 
+std::vector<std::variant<std::unique_ptr<tabs::TabModel>,
+                         std::unique_ptr<DetachedTabCollection>>>
+TabStripModel::DetachTabsAndCollectionsForInsertion(
+    const std::vector<int>& tab_indices) {
+  const std::vector<tab_groups::TabGroupId> groups_to_move =
+      GetGroupsDestroyedFromRemovingIndices(tab_indices);
+
+  std::vector<tabs::TabInterface*> tab_interfaces;
+  for (const int index : tab_indices) {
+    tab_interfaces.push_back(GetTabAtIndex(index));
+  }
+
+  std::vector<std::variant<std::unique_ptr<tabs::TabModel>,
+                           std::unique_ptr<DetachedTabCollection>>>
+      owned_tabs_and_collections;
+
+  for (const tabs::TabInterface* tab_interface : tab_interfaces) {
+    const int index = GetIndexOfTab(tab_interface);
+    if (index == TabStripModel::kNoTab) {
+      // If this is a tab, we already moved it as part of its group.
+      // If this is a header, we will move it when we get to its first tab.
+      continue;
+    }
+
+    const std::optional<tab_groups::TabGroupId> group =
+        tab_interface->GetGroup();
+    if (std::find(groups_to_move.begin(), groups_to_move.end(), group) !=
+        groups_to_move.end()) {
+      owned_tabs_and_collections.emplace_back(
+          DetachTabGroupForInsertion(group.value()));
+    } else if (tab_interface->IsSplit()) {
+      owned_tabs_and_collections.emplace_back(
+          DetachSplitTabForInsertion(tab_interface->GetSplit().value()));
+    } else {
+      owned_tabs_and_collections.emplace_back(DetachTabAtForInsertion(index));
+    }
+  }
+
+  return owned_tabs_and_collections;
+}
+
 std::unique_ptr<DetachedTab> TabStripModel::DetachTabWithReasonAt(
     int index,
     TabStripModelChange::RemoveReason web_contents_remove_reason,
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index 30154e7c..58597c0 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -350,6 +350,10 @@
   // Detaches the WebContents at the specified index and immediately deletes it.
   void DetachAndDeleteWebContentsAt(int index);
 
+  std::vector<std::variant<std::unique_ptr<tabs::TabModel>,
+                           std::unique_ptr<DetachedTabCollection>>>
+  DetachTabsAndCollectionsForInsertion(const std::vector<int>& tab_indices);
+
   // Makes the tab at the specified index the active tab. |gesture_detail.type|
   // contains the gesture type that triggers the tab activation.
   // |gesture_detail.time_stamp| contains the timestamp of the user gesture, if
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_interactive_uitest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_interactive_uitest.cc
index cb54189..cf28378 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_interactive_uitest.cc
@@ -276,8 +276,21 @@
       CheckViewProperty(kBNodeMenuId, &views::MenuItemView::title, u"b"));
 }
 
+// TODO(crbug.com/375959961): For X11, the menu is always closed on drag
+// completion because the native widget's state is not properly updated.
+// TODO(crbug.com/388531778): DND tests are fail on Windows and Wayland. This
+// should be re-enabled once fix.
+// TODO(crbug.com/448993919): Re-enable this test on Mac.
+#if BUILDFLAG(IS_OZONE_X11) || BUILDFLAG(IS_WIN) || \
+    BUILDFLAG(IS_OZONE_WAYLAND) || BUILDFLAG(IS_MAC)
+#define MAYBE_BookmarksDragAndDropToNestedFolder \
+  DISABLED_BookmarksDragAndDropToNestedFolder
+#else
+#define MAYBE_BookmarksDragAndDropToNestedFolder \
+  BookmarksDragAndDropToNestedFolder
+#endif
 IN_PROC_BROWSER_TEST_F(BookmarkBarDragAndDropInteractiveTest,
-                       MAYBE_DISABLED(BookmarksDragAndDropToNestedFolder)) {
+                       MAYBE_BookmarksDragAndDropToNestedFolder) {
   // Add two bookmarks nodes to the bookmarks bar.
   bookmarks::BookmarkModel* const model =
       BookmarkModelFactory::GetForBrowserContext(browser()->profile());
diff --git a/chrome/browser/ui/views/data_sharing/collaboration_controller_delegate_desktop.cc b/chrome/browser/ui/views/data_sharing/collaboration_controller_delegate_desktop.cc
index c58fcab..3c332c1 100644
--- a/chrome/browser/ui/views/data_sharing/collaboration_controller_delegate_desktop.cc
+++ b/chrome/browser/ui/views/data_sharing/collaboration_controller_delegate_desktop.cc
@@ -27,6 +27,7 @@
 #include "components/collaboration/public/collaboration_service.h"
 #include "components/collaboration/public/service_status.h"
 #include "components/saved_tab_groups/public/tab_group_sync_service.h"
+#include "components/signin/public/base/signin_metrics.h"
 #include "components/signin/public/identity_manager/account_info.h"
 #include "ui/views/bubble/bubble_dialog_model_host.h"
 #include "ui/views/widget/widget.h"
@@ -523,13 +524,35 @@
                 .SetEnabled(true));
 
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+    AccountInfo account_for_promo = signin_ui_util::GetSingleAccountForPromos(
+        IdentityManagerFactory::GetForProfile(browser_->profile()));
+
     if (base::FeatureList::IsEnabled(
             syncer::kReplaceSyncPromosWithSignInPromos)) {
       dialog_builder.SetFootnote(ui::DialogModelLabel(dialog_text.footnote));
+
+      // Record metrics about signin and history sync opt in being offered.
+      switch (status.signin_status) {
+        case collaboration::SigninStatus::kSigninDisabled:
+          break;
+        case collaboration::SigninStatus::kNotSignedIn:
+          signin_metrics::LogSignInOffered(
+              signin_metrics::AccessPoint::kCollaborationShareTabGroup,
+              account_for_promo.IsEmpty()
+                  ? signin_metrics::PromoAction::
+                        PROMO_ACTION_NEW_ACCOUNT_NO_EXISTING_ACCOUNT
+                  : signin_metrics::PromoAction::PROMO_ACTION_WITH_DEFAULT);
+          signin_metrics::LogHistorySyncOptInOffered(
+              signin_metrics::AccessPoint::kCollaborationShareTabGroup);
+          break;
+        case collaboration::SigninStatus::kSignedInPaused:
+        case collaboration::SigninStatus::kSignedIn:
+          signin_metrics::LogHistorySyncOptInOffered(
+              signin_metrics::AccessPoint::kCollaborationShareTabGroup);
+          break;
+      }
     }
 
-    AccountInfo account_for_promo = signin_ui_util::GetSingleAccountForPromos(
-        IdentityManagerFactory::GetForProfile(browser_->profile()));
 #else
     AccountInfo account_for_promo =
         GetAccountInfoFromProfile(browser_->profile());
diff --git a/chrome/browser/ui/views/data_sharing/collaboration_controller_delegate_desktop_interactive_uitest.cc b/chrome/browser/ui/views/data_sharing/collaboration_controller_delegate_desktop_interactive_uitest.cc
index 3e1efbab..de992d0 100644
--- a/chrome/browser/ui/views/data_sharing/collaboration_controller_delegate_desktop_interactive_uitest.cc
+++ b/chrome/browser/ui/views/data_sharing/collaboration_controller_delegate_desktop_interactive_uitest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/mock_callback.h"
 #include "chrome/browser/signin/chrome_signin_client_test_util.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
@@ -498,8 +499,7 @@
         syncer::UserSelectableType::kSavedTabGroups, enabled);
   }
 
-  void ShowAndAcceptDialog(
-      collaboration::ServiceStatus status = collaboration::ServiceStatus()) {
+  void ShowAndAcceptDialog(collaboration::SigninStatus signin_status) {
     // Set up an account picture in case it is shown in the dialog.
     signin::SimulateAccountImageFetch(
         identity_manager(),
@@ -511,7 +511,8 @@
     TestCollaborationControllerDelegateDesktop delegate(browser());
     EXPECT_CALL(delegate, GetServiceStatus())
         .Times(2)
-        .WillRepeatedly(testing::Return(status));
+        .WillRepeatedly(testing::Return(
+            collaboration::ServiceStatus{.signin_status = signin_status}));
     EXPECT_EQ(nullptr, delegate.prompt_dialog_widget_for_testing());
     base::MockCallback<
         collaboration::CollaborationControllerDelegate::ResultCallback>
@@ -542,7 +543,9 @@
 IN_PROC_BROWSER_TEST_F(
     CollaborationControllerDelegateDesktopInteractiveUITestWithHistorySyncOptIn,
     PromptDialogAccept_SignedOut) {
-  ShowAndAcceptDialog();
+  base::HistogramTester histogram_tester;
+
+  ShowAndAcceptDialog(collaboration::SigninStatus::kNotSignedIn);
 
   EXPECT_TRUE(SigninPromoTabHelper::GetForWebContents(
                   *browser()->tab_strip_model()->GetActiveWebContents())
@@ -564,11 +567,35 @@
       syncer::UserSelectableType::kTabs));
   EXPECT_TRUE(sync_service()->GetUserSettings()->GetSelectedTypes().Has(
       syncer::UserSelectableType::kSavedTabGroups));
+
+  // Signin metrics - Offered/Started/Completed are recorded, but no values for
+  // WebSignin (WithDefault).
+  histogram_tester.ExpectBucketCount(
+      "Signin.SignIn.Offered",
+      signin_metrics::AccessPoint::kCollaborationShareTabGroup, 1);
+  histogram_tester.ExpectBucketCount(
+      "Signin.SignIn.Offered.NewAccountNoExistingAccount",
+      signin_metrics::AccessPoint::kCollaborationShareTabGroup, 1);
+  histogram_tester.ExpectTotalCount("Signin.SignIn.Offered.WithDefault", 0);
+  histogram_tester.ExpectBucketCount(
+      "Signin.SignIn.Started",
+      signin_metrics::AccessPoint::kCollaborationShareTabGroup, 1);
+  histogram_tester.ExpectBucketCount(
+      "Signin.SignIn.Completed",
+      signin_metrics::AccessPoint::kCollaborationShareTabGroup, 1);
+  histogram_tester.ExpectTotalCount("Signin.WebSignin.SourceToChromeSignin", 0);
+
+  histogram_tester.ExpectUniqueSample(
+      "Signin.HistorySyncOptIn.Offered",
+      signin_metrics::AccessPoint::kCollaborationShareTabGroup,
+      /*expected_bucket_count=*/1);
 }
 
 IN_PROC_BROWSER_TEST_F(
     CollaborationControllerDelegateDesktopInteractiveUITestWithHistorySyncOptIn,
     PromptDialogAccept_WebSignedIn) {
+  base::HistogramTester histogram_tester;
+
   AccountInfo info = signin::MakeAccountAvailable(
       identity_manager(),
       signin::AccountAvailabilityOptionsBuilder(test_url_loader_factory())
@@ -577,7 +604,7 @@
           .Build("test@email.com"));
 
   // Accepting the dialog should sign the user in and also enable history sync.
-  ShowAndAcceptDialog();
+  ShowAndAcceptDialog(collaboration::SigninStatus::kNotSignedIn);
 
   EXPECT_TRUE(IsSignedIn());
   EXPECT_FALSE(SigninPromoTabHelper::GetForWebContents(
@@ -590,6 +617,31 @@
       syncer::UserSelectableType::kTabs));
   EXPECT_TRUE(sync_service()->GetUserSettings()->GetSelectedTypes().Has(
       syncer::UserSelectableType::kSavedTabGroups));
+
+  // Signin metrics - WebSignin (WithDefault) metrics are also recorded.
+  histogram_tester.ExpectBucketCount(
+      "Signin.SignIn.Offered",
+      signin_metrics::AccessPoint::kCollaborationShareTabGroup, 1);
+  histogram_tester.ExpectTotalCount("Signin.SignIn.Started", 0);
+  histogram_tester.ExpectBucketCount(
+      "Signin.SignIn.Completed",
+      signin_metrics::AccessPoint::kCollaborationShareTabGroup, 1);
+  histogram_tester.ExpectBucketCount(
+      "Signin.SignIn.Offered",
+      signin_metrics::AccessPoint::kCollaborationShareTabGroup, 1);
+  histogram_tester.ExpectBucketCount(
+      "Signin.SignIn.Offered.WithDefault",
+      signin_metrics::AccessPoint::kCollaborationShareTabGroup, 1);
+  histogram_tester.ExpectTotalCount(
+      "Signin.SignIn.Offered.NewAccountNoExistingAccount", 0);
+  histogram_tester.ExpectBucketCount(
+      "Signin.WebSignin.SourceToChromeSignin",
+      signin_metrics::AccessPoint::kCollaborationShareTabGroup, 1);
+
+  histogram_tester.ExpectUniqueSample(
+      "Signin.HistorySyncOptIn.Offered",
+      signin_metrics::AccessPoint::kCollaborationShareTabGroup,
+      /*expected_bucket_count=*/1);
 }
 
 IN_PROC_BROWSER_TEST_F(
@@ -599,7 +651,10 @@
       identity_manager(), "test@email.com", signin::ConsentLevel::kSignin);
   signin::SetInvalidRefreshTokenForPrimaryAccount(identity_manager());
 
-  ShowAndAcceptDialog();
+  // Start recording metrics after signing in.
+  base::HistogramTester histogram_tester;
+
+  ShowAndAcceptDialog(collaboration::SigninStatus::kSignedInPaused);
 
   EXPECT_TRUE(SigninPromoTabHelper::GetForWebContents(
                   *browser()->tab_strip_model()->GetActiveWebContents())
@@ -626,6 +681,20 @@
       syncer::UserSelectableType::kTabs));
   EXPECT_TRUE(sync_service()->GetUserSettings()->GetSelectedTypes().Has(
       syncer::UserSelectableType::kSavedTabGroups));
+
+  // Signin metrics - nothing should be recorded for reauth.
+  histogram_tester.ExpectTotalCount("Signin.SignIn.Offered", 0);
+  histogram_tester.ExpectTotalCount("Signin.SignIn.Started", 0);
+  histogram_tester.ExpectTotalCount("Signin.SignIn.Completed", 0);
+  histogram_tester.ExpectTotalCount("Signin.SignIn.Offered.WithDefault", 0);
+  histogram_tester.ExpectTotalCount(
+      "Signin.SignIn.Offered.NewAccountNoExistingAccount", 0);
+  histogram_tester.ExpectTotalCount("Signin.WebSignin.SourceToChromeSignin", 0);
+
+  histogram_tester.ExpectUniqueSample(
+      "Signin.HistorySyncOptIn.Offered",
+      signin_metrics::AccessPoint::kCollaborationShareTabGroup,
+      /*expected_bucket_count=*/1);
 }
 
 IN_PROC_BROWSER_TEST_F(
@@ -633,8 +702,11 @@
     PromptDialogAccept_SignedInWithoutHistorySync) {
   SignIn();
 
+  // Start recording metrics after signing in.
+  base::HistogramTester histogram_tester;
+
   // Accepting the dialog should enable history sync.
-  ShowAndAcceptDialog();
+  ShowAndAcceptDialog(collaboration::SigninStatus::kSignedIn);
 
   EXPECT_TRUE(IsSignedIn());
   EXPECT_FALSE(SigninPromoTabHelper::GetForWebContents(
@@ -647,15 +719,29 @@
       syncer::UserSelectableType::kTabs));
   EXPECT_TRUE(sync_service()->GetUserSettings()->GetSelectedTypes().Has(
       syncer::UserSelectableType::kSavedTabGroups));
+
+  // Signin metrics - nothing should be recorded for only history sync optin.
+  histogram_tester.ExpectTotalCount("Signin.SignIn.Offered", 0);
+  histogram_tester.ExpectTotalCount("Signin.SignIn.Started", 0);
+  histogram_tester.ExpectTotalCount("Signin.SignIn.Completed", 0);
+  histogram_tester.ExpectTotalCount("Signin.SignIn.Offered.WithDefault", 0);
+  histogram_tester.ExpectTotalCount(
+      "Signin.SignIn.Offered.NewAccountNoExistingAccount", 0);
+  histogram_tester.ExpectTotalCount("Signin.WebSignin.SourceToChromeSignin", 0);
+
+  histogram_tester.ExpectUniqueSample(
+      "Signin.HistorySyncOptIn.Offered",
+      signin_metrics::AccessPoint::kCollaborationShareTabGroup,
+      /*expected_bucket_count=*/1);
 }
 
 IN_PROC_BROWSER_TEST_F(
     CollaborationControllerDelegateDesktopInteractiveUITestWithHistorySyncOptIn,
     PromptDialogAccept_SignInDisabled) {
+  base::HistogramTester histogram_tester;
+
   // Show dialog and open the Google services settings page.
-  collaboration::ServiceStatus status;
-  status.signin_status = collaboration::SigninStatus::kSigninDisabled;
-  ShowAndAcceptDialog(status);
+  ShowAndAcceptDialog(collaboration::SigninStatus::kSigninDisabled);
 
   // Verify the settings page was opened.
   EXPECT_EQ(
@@ -674,5 +760,19 @@
       syncer::UserSelectableType::kTabs));
   EXPECT_FALSE(sync_service()->GetUserSettings()->GetSelectedTypes().Has(
       syncer::UserSelectableType::kSavedTabGroups));
+
+  // Signin metrics - nothing should be recorded for sync disabled.
+  histogram_tester.ExpectTotalCount("Signin.SignIn.Offered", 0);
+  histogram_tester.ExpectTotalCount("Signin.SignIn.Started", 0);
+  histogram_tester.ExpectTotalCount("Signin.SignIn.Completed", 0);
+  histogram_tester.ExpectTotalCount("Signin.SignIn.Offered.WithDefault", 0);
+  histogram_tester.ExpectTotalCount(
+      "Signin.SignIn.Offered.NewAccountNoExistingAccount", 0);
+  histogram_tester.ExpectTotalCount("Signin.WebSignin.SourceToChromeSignin", 0);
+
+  histogram_tester.ExpectUniqueSample(
+      "Signin.HistorySyncOptIn.Offered",
+      signin_metrics::AccessPoint::kCollaborationShareTabGroup,
+      /*expected_bucket_count=*/0);
 }
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
diff --git a/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc b/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc
index f7ba14d8..01870ff7 100644
--- a/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc
+++ b/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc
@@ -18,9 +18,6 @@
 #include "base/test/bind.h"
 #include "base/win/scoped_propvariant.h"
 #include "chrome/browser/apps/app_service/app_launch_params.h"
-#include "chrome/browser/apps/app_service/app_service_proxy.h"
-#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
-#include "chrome/browser/apps/app_service/browser_app_launcher.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/profiles/profile.h"
@@ -34,6 +31,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/web_applications/extensions/launch.h"
 #include "chrome/browser/web_applications/os_integration/web_app_shortcut.h"
 #include "chrome/browser/web_applications/os_integration/web_app_shortcut_win.h"
 #include "chrome/common/chrome_switches.h"
@@ -205,14 +203,13 @@
   EXPECT_TRUE(extension);
 
   base::RunLoop done;
-  apps::AppServiceProxyFactory::GetForProfile(browser()->profile())
-      ->BrowserAppLauncher()
-      ->LaunchAppWithParams(
-          apps::AppLaunchParams(extension->id(),
-                                apps::LaunchContainer::kLaunchContainerWindow,
-                                WindowOpenDisposition::NEW_FOREGROUND_TAB,
-                                apps::LaunchSource::kFromTest),
-          base::IgnoreArgs<content::WebContents*>(done.QuitClosure()));
+  web_app::LaunchExtensionOrWebApp(
+      browser()->profile(),
+      apps::AppLaunchParams(extension->id(),
+                            apps::LaunchContainer::kLaunchContainerWindow,
+                            WindowOpenDisposition::NEW_FOREGROUND_TAB,
+                            apps::LaunchSource::kFromTest),
+      base::IgnoreArgs<content::WebContents*>(done.QuitClosure()));
   done.Run();
 
   // Check that the new browser has an app name.
diff --git a/chrome/browser/ui/views/frame/multi_contents_view_drop_target_controller_browsertest.cc b/chrome/browser/ui/views/frame/multi_contents_view_drop_target_controller_browsertest.cc
index e7c0fd9..09e16175 100644
--- a/chrome/browser/ui/views/frame/multi_contents_view_drop_target_controller_browsertest.cc
+++ b/chrome/browser/ui/views/frame/multi_contents_view_drop_target_controller_browsertest.cc
@@ -129,8 +129,16 @@
   EXPECT_FALSE(IsDropTimerRunning());
 }
 
+// TODO(crbug.com/440805211): Re-enable this test
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_OnTabDragUpdatedMaximizedWithEndPoint \
+  DISABLED_OnTabDragUpdatedMaximizedWithEndPoint
+#else
+#define MAYBE_OnTabDragUpdatedMaximizedWithEndPoint \
+  OnTabDragUpdatedMaximizedWithEndPoint
+#endif
 IN_PROC_BROWSER_TEST_F(MultiContentsViewDropTargetControllerBrowserTest,
-                       OnTabDragUpdatedMaximizedWithEndPoint) {
+                       MAYBE_OnTabDragUpdatedMaximizedWithEndPoint) {
   SimulateTabDrag(true, gfx::Point(GetViewWidth() - 10, 250));
   EXPECT_FALSE(IsDropTimerRunning());
 }
diff --git a/chrome/browser/ui/views/profiles/first_run_interactive_uitest.cc b/chrome/browser/ui/views/profiles/first_run_interactive_uitest.cc
index 680a088..83d26b0 100644
--- a/chrome/browser/ui/views/profiles/first_run_interactive_uitest.cc
+++ b/chrome/browser/ui/views/profiles/first_run_interactive_uitest.cc
@@ -90,6 +90,11 @@
 const DeepQuery kSearchEngineChoiceActionButton{"search-engine-choice-app",
                                                 "#actionButton"};
 
+const DeepQuery kOptInSyncHistoryButton{"history-sync-optin-app",
+                                        "#acceptButton"};
+const DeepQuery kDontSyncHistoryButton{"history-sync-optin-app",
+                                       "#rejectButton"};
+
 enum class SyncButtonsFeatureConfig : int {
   // Deprecated: kDisabled = 0,
   // Simulate async load resulting in not-equal buttons.
@@ -211,10 +216,6 @@
             UseDefaultTrackerAllowingPromos(
                 {feature_engagement::kIPHSupervisedUserProfileSigninFeature})),
         params_(params) {
-    // TODO(crbug.com/447151253): Fix the tests to work with the feature
-    // enabled.
-    scoped_feature_list_.InitAndDisableFeature(
-        syncer::kReplaceSyncPromosWithSignInPromos);
   }
   ~FirstRunInteractiveUiTest() override = default;
 
@@ -331,7 +332,8 @@
   }
 
   void SimulateSignIn(const std::string& account_email,
-                      const std::string& account_given_name) {
+                      const std::string& account_given_name,
+                      bool with_extended_info = true) {
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
     auto enable_disclaimer_on_primary_account_change_resetter =
         enterprise_util::DisableAutomaticManagementDisclaimerUntilReset(
@@ -348,12 +350,14 @@
             .WithAccessPoint(signin_metrics::AccessPoint::kForYouFre)
             .Build(account_email));
 
-    account_info =
-        signin::WithGeneratedUserInfo(account_info, account_given_name);
+    if (with_extended_info) {
+      account_info =
+          signin::WithGeneratedUserInfo(account_info, account_given_name);
+    }
 
     // Controls behavior of sync buttons and supervision.
     AccountCapabilitiesTestMutator mutator(&account_info.capabilities);
-    if (account_email == kTestEnterpriseEmail) {
+    if (with_extended_info && account_email == kTestEnterpriseEmail) {
       account_info.hosted_domain = "chromium.org";
     }
     mutator.set_is_subject_to_enterprise_features(account_email ==
@@ -381,7 +385,9 @@
         break;
     }
 
-    ASSERT_TRUE(account_info.IsValid());
+    if (with_extended_info) {
+      ASSERT_TRUE(account_info.IsValid());
+    }
 
     // Kombucha note: This function waits on a `base::RunLoop`.
     signin::UpdateAccountInfoForAccount(identity_manager, account_info);
@@ -437,9 +443,12 @@
     }
   }
 
+  static GURL GetHistorySyncOptinURL() {
+    return GURL("chrome://history-sync-optin?launch_context=0");
+  }
+
  private:
   TestParam params_;
-  base::test::ScopedFeatureList scoped_feature_list_;
 
   ChromeSigninClientWithURLLoaderHelper url_loader_factory_helper_;
   base::HistogramTester histogram_tester_;
@@ -475,18 +484,32 @@
   // Pulled out of the test sequence because it waits using `RunLoop`s.
   SimulateSignIn(kTestEmail, kTestGivenName);
 
-  GURL sync_page_url = AppendSyncConfirmationQueryParams(
-      GURL("chrome://sync-confirmation/"), SyncConfirmationStyle::kWindow,
-      /*is_sync_promo=*/true);
-  RunTestSequenceInContext(
-      views::ElementTrackerViews::GetContextForView(view()),
-      // Web Contents already instrumented in the previous sequence.
-      WaitForWebContentsNavigation(kWebContentsId, sync_page_url),
-      // Button is visible once capabilities are loaded or defaulted.
-      WaitForButtonVisible(kWebContentsId, kDontSyncButton),
-      EnsurePresent(kWebContentsId, kDontSyncButton),
-      PressJsButton(kWebContentsId, kDontSyncButton)
-          .SetMustRemainVisible(false));
+  if (base::FeatureList::IsEnabled(
+          syncer::kReplaceSyncPromosWithSignInPromos)) {
+    GURL history_page_url = GetHistorySyncOptinURL();
+    RunTestSequenceInContext(
+        views::ElementTrackerViews::GetContextForView(view()),
+        // Web Contents already instrumented in the previous sequence.
+        WaitForWebContentsNavigation(kWebContentsId, history_page_url),
+        // Button is visible once capabilities are loaded or defaulted.
+        WaitForButtonVisible(kWebContentsId, kDontSyncHistoryButton),
+        EnsurePresent(kWebContentsId, kDontSyncHistoryButton),
+        PressJsButton(kWebContentsId, kDontSyncHistoryButton)
+            .SetMustRemainVisible(false));
+  } else {
+    GURL sync_page_url = AppendSyncConfirmationQueryParams(
+        GURL("chrome://sync-confirmation/"), SyncConfirmationStyle::kWindow,
+        /*is_sync_promo=*/true);
+    RunTestSequenceInContext(
+        views::ElementTrackerViews::GetContextForView(view()),
+        // Web Contents already instrumented in the previous sequence.
+        WaitForWebContentsNavigation(kWebContentsId, sync_page_url),
+        // Button is visible once capabilities are loaded or defaulted.
+        WaitForButtonVisible(kWebContentsId, kDontSyncButton),
+        EnsurePresent(kWebContentsId, kDontSyncButton),
+        PressJsButton(kWebContentsId, kDontSyncButton)
+            .SetMustRemainVisible(false));
+  }
 
   WaitForPickerClosed();
 
@@ -811,34 +834,55 @@
   // Pulled out of the test sequence because it waits using `RunLoop`s.
   SimulateSignIn(kTestEmail, kTestGivenName);
 
-  GURL sync_page_url = AppendSyncConfirmationQueryParams(
-      GURL("chrome://sync-confirmation/"), SyncConfirmationStyle::kWindow,
-      /*is_sync_promo=*/true);
   histogram_tester().ExpectUniqueSample(
       "Signin.SignIn.Completed", signin_metrics::AccessPoint::kForYouFre, 1);
 
   const DeepQuery first_search_engine = {"search-engine-choice-app",
                                          "cr-radio-button"};
 
-  RunTestSequenceInContext(
-      views::ElementTrackerViews::GetContextForView(view()),
-      // Web Contents already instrumented in the previous sequence.
-      WaitForWebContentsNavigation(kWebContentsId, sync_page_url),
+  if (base::FeatureList::IsEnabled(
+          syncer::kReplaceSyncPromosWithSignInPromos)) {
+    GURL history_page_url = GetHistorySyncOptinURL();
+    RunTestSequenceInContext(
+        views::ElementTrackerViews::GetContextForView(view()),
+        // Web Contents already instrumented in the previous sequence.
+        WaitForWebContentsNavigation(kWebContentsId, history_page_url),
 
-      Do([&] {
-        histogram_tester().ExpectUniqueSample(
-            "Signin.SyncOptIn.Started", signin_metrics::AccessPoint::kForYouFre,
-            1);
-      }),
+        // TODO(crbug.com/445927205): Verify Signin.HistorySyncOptIn.Started
+        // once it is implemented.
 
-      // Button is visible once capabilities are loaded or defaulted.
-      WaitForButtonVisible(kWebContentsId, kOptInSyncButton),
+        // Button is visible once capabilities are loaded or defaulted.
+        WaitForButtonVisible(kWebContentsId, kOptInSyncHistoryButton),
 
-      EnsurePresent(kWebContentsId, kOptInSyncButton),
-      PressJsButton(kWebContentsId, kOptInSyncButton)
-          .SetMustRemainVisible(false),
+        EnsurePresent(kWebContentsId, kOptInSyncHistoryButton),
+        PressJsButton(kWebContentsId, kOptInSyncHistoryButton)
+            .SetMustRemainVisible(false),
 
-      CompleteSearchEngineChoiceStep(), CompleteDefaultBrowserStep());
+        CompleteSearchEngineChoiceStep(), CompleteDefaultBrowserStep());
+  } else {
+    GURL sync_page_url = AppendSyncConfirmationQueryParams(
+        GURL("chrome://sync-confirmation/"), SyncConfirmationStyle::kWindow,
+        /*is_sync_promo=*/true);
+    RunTestSequenceInContext(
+        views::ElementTrackerViews::GetContextForView(view()),
+        // Web Contents already instrumented in the previous sequence.
+        WaitForWebContentsNavigation(kWebContentsId, sync_page_url),
+
+        Do([&] {
+          histogram_tester().ExpectUniqueSample(
+              "Signin.SyncOptIn.Started",
+              signin_metrics::AccessPoint::kForYouFre, 1);
+        }),
+
+        // Button is visible once capabilities are loaded or defaulted.
+        WaitForButtonVisible(kWebContentsId, kOptInSyncButton),
+
+        EnsurePresent(kWebContentsId, kOptInSyncButton),
+        PressJsButton(kWebContentsId, kOptInSyncButton)
+            .SetMustRemainVisible(false),
+
+        CompleteSearchEngineChoiceStep(), CompleteDefaultBrowserStep());
+  }
 
   WaitForPickerClosed();
 
@@ -854,8 +898,14 @@
     EXPECT_TRUE(privacy_sandbox_service->IsPromptOpenForBrowser(browser()));
   }
 
-  histogram_tester().ExpectUniqueSample(
-      "Signin.SyncOptIn.Completed", signin_metrics::AccessPoint::kForYouFre, 1);
+  if (!base::FeatureList::IsEnabled(
+          syncer::kReplaceSyncPromosWithSignInPromos)) {
+    // TODO(crbug.com/445927205): Verify Signin.HistorySyncOptIn.Completed
+    // once it is implemented.
+    histogram_tester().ExpectUniqueSample(
+        "Signin.SyncOptIn.Completed", signin_metrics::AccessPoint::kForYouFre,
+        1);
+  }
 
   histogram_tester().ExpectBucketCount("ProfilePicker.FirstRun.DefaultBrowser",
                                        DefaultBrowserChoice::kClickSetAsDefault,
@@ -880,16 +930,22 @@
       "Signin.SignIn.Started", signin_metrics::AccessPoint::kForYouFre, 1);
   histogram_tester().ExpectUniqueSample(
       "Signin.SignIn.Completed", signin_metrics::AccessPoint::kForYouFre, 1);
-  histogram_tester().ExpectUniqueSample(
-      "Signin.SyncOptIn.Started", signin_metrics::AccessPoint::kForYouFre, 1);
-  histogram_tester().ExpectUniqueSample(
-      "Signin.SyncOptIn.Completed", signin_metrics::AccessPoint::kForYouFre, 1);
-  histogram_tester().ExpectUniqueSample(
-      "Signin.SyncButtons.Shown",
-      *ExpectedButtonShownMetric(SyncButtonsFeatureConfig()), 1);
-  histogram_tester().ExpectUniqueSample(
-      "Signin.SyncButtons.Clicked",
-      ExpectedOptInButtonClickedMetric(SyncButtonsFeatureConfig()), 1);
+  if (!base::FeatureList::IsEnabled(
+          syncer::kReplaceSyncPromosWithSignInPromos)) {
+    // TODO(crbug.com/445927205): Adapt these histograms for history optin.
+    histogram_tester().ExpectUniqueSample(
+        "Signin.SyncOptIn.Started", signin_metrics::AccessPoint::kForYouFre, 1);
+    histogram_tester().ExpectUniqueSample(
+        "Signin.SyncOptIn.Completed", signin_metrics::AccessPoint::kForYouFre,
+        1);
+    // TODO(crbug.com/435374353): Support equal weight buttons in history optin.
+    histogram_tester().ExpectUniqueSample(
+        "Signin.SyncButtons.Shown",
+        *ExpectedButtonShownMetric(SyncButtonsFeatureConfig()), 1);
+    histogram_tester().ExpectUniqueSample(
+        "Signin.SyncButtons.Clicked",
+        ExpectedOptInButtonClickedMetric(SyncButtonsFeatureConfig()), 1);
+  }
   histogram_tester().ExpectUniqueSample(
       "ProfilePicker.FirstRun.ExitStatus",
       ProfilePicker::FirstRunExitStatus::kCompleted, 1);
@@ -950,21 +1006,37 @@
   // Pulled out of the test sequence because it waits using `RunLoop`s.
   SimulateSignIn(kTestEmail, kTestGivenName);
 
-  RunTestSequenceInContext(
-      views::ElementTrackerViews::GetContextForView(view()),
-      WaitForWebContentsNavigation(
-          kWebContentsId,
-          AppendSyncConfirmationQueryParams(GURL("chrome://sync-confirmation/"),
-                                            SyncConfirmationStyle::kWindow,
-                                            /*is_sync_promo=*/true)),
+  if (base::FeatureList::IsEnabled(
+          syncer::kReplaceSyncPromosWithSignInPromos)) {
+    GURL history_page_url = GetHistorySyncOptinURL();
+    RunTestSequenceInContext(
+        views::ElementTrackerViews::GetContextForView(view()),
+        WaitForWebContentsNavigation(kWebContentsId, history_page_url),
 
-      // Button is visible once capabilities are loaded or defaulted.
-      WaitForButtonVisible(kWebContentsId, kDontSyncButton),
+        // Button is visible once capabilities are loaded or defaulted.
+        WaitForButtonVisible(kWebContentsId, kDontSyncHistoryButton),
 
-      EnsurePresent(kWebContentsId, kDontSyncButton),
-      PressJsButton(kWebContentsId, kDontSyncButton),
+        EnsurePresent(kWebContentsId, kDontSyncHistoryButton),
+        PressJsButton(kWebContentsId, kDontSyncHistoryButton),
 
-      CompleteSearchEngineChoiceStep(), CompleteDefaultBrowserStep());
+        CompleteSearchEngineChoiceStep(), CompleteDefaultBrowserStep());
+  } else {
+    RunTestSequenceInContext(
+        views::ElementTrackerViews::GetContextForView(view()),
+        WaitForWebContentsNavigation(kWebContentsId,
+                                     AppendSyncConfirmationQueryParams(
+                                         GURL("chrome://sync-confirmation/"),
+                                         SyncConfirmationStyle::kWindow,
+                                         /*is_sync_promo=*/true)),
+
+        // Button is visible once capabilities are loaded or defaulted.
+        WaitForButtonVisible(kWebContentsId, kDontSyncButton),
+
+        EnsurePresent(kWebContentsId, kDontSyncButton),
+        PressJsButton(kWebContentsId, kDontSyncButton),
+
+        CompleteSearchEngineChoiceStep(), CompleteDefaultBrowserStep());
+  }
 
   // Wait for the picker to be closed and deleted.
   WaitForPickerClosed();
@@ -980,15 +1052,20 @@
       "Signin.SignIn.Started", signin_metrics::AccessPoint::kForYouFre, 1);
   histogram_tester().ExpectUniqueSample(
       "Signin.SignIn.Completed", signin_metrics::AccessPoint::kForYouFre, 1);
-  histogram_tester().ExpectUniqueSample(
-      "Signin.SyncOptIn.Started", signin_metrics::AccessPoint::kForYouFre, 1);
-  histogram_tester().ExpectTotalCount("Signin.SyncOptIn.Completed", 0);
-  histogram_tester().ExpectUniqueSample(
-      "Signin.SyncButtons.Shown",
-      *ExpectedButtonShownMetric(SyncButtonsFeatureConfig()), 1);
-  histogram_tester().ExpectUniqueSample(
-      "Signin.SyncButtons.Clicked",
-      ExpectedDeclinedButtonClickedMetric(SyncButtonsFeatureConfig()), 1);
+  if (!base::FeatureList::IsEnabled(
+          syncer::kReplaceSyncPromosWithSignInPromos)) {
+    // TODO(crbug.com/445927205): Adapt these histograms for history optin.
+    histogram_tester().ExpectUniqueSample(
+        "Signin.SyncOptIn.Started", signin_metrics::AccessPoint::kForYouFre, 1);
+    histogram_tester().ExpectTotalCount("Signin.SyncOptIn.Completed", 0);
+    // TODO(crbug.com/435374353): Support equal weight buttons in history optin.
+    histogram_tester().ExpectUniqueSample(
+        "Signin.SyncButtons.Shown",
+        *ExpectedButtonShownMetric(SyncButtonsFeatureConfig()), 1);
+    histogram_tester().ExpectUniqueSample(
+        "Signin.SyncButtons.Clicked",
+        ExpectedDeclinedButtonClickedMetric(SyncButtonsFeatureConfig()), 1);
+  }
   histogram_tester().ExpectUniqueSample(
       "ProfilePicker.FirstRun.ExitStatus",
       ProfilePicker::FirstRunExitStatus::kCompleted, 1);
@@ -1002,6 +1079,11 @@
 }
 
 IN_PROC_BROWSER_TEST_P(FirstRunParameterizedInteractiveUiTest, GoToSettings) {
+  if (base::FeatureList::IsEnabled(
+          syncer::kReplaceSyncPromosWithSignInPromos)) {
+    GTEST_SKIP() << "History optin screen does not have a settings button";
+  }
+
   base::test::TestFuture<bool> proceed_future;
 
   ASSERT_TRUE(IsProfileNameDefault());
@@ -1197,7 +1279,8 @@
                                    GetSigninChromeSyncDiceUrl()));
 
   // Pulled out of the test sequence because it waits using `RunLoop`s.
-  SimulateSignIn(kTestEnterpriseEmail, kTestGivenName);
+  SimulateSignIn(kTestEnterpriseEmail, kTestGivenName,
+                 /*with_extended_info=*/false);
   ASSERT_TRUE(
       identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSignin));
 
@@ -1209,8 +1292,18 @@
           AppendSyncConfirmationQueryParams(
               GURL(chrome::kChromeUISyncConfirmationURL)
                   .Resolve(chrome::kChromeUISyncConfirmationLoadingPath),
-              SyncConfirmationStyle::kWindow, /*is_sync_promo=*/true)),
+              SyncConfirmationStyle::kWindow, /*is_sync_promo=*/true)));
 
+  AccountInfo account_info =
+      identity_manager->FindExtendedAccountInfoByAccountId(
+          identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSignin));
+  account_info = signin::WithGeneratedUserInfo(account_info, kTestGivenName);
+  account_info.hosted_domain = "chromium.org";
+  // Pulled out of the test sequence because it waits using `RunLoop`s.
+  signin::UpdateAccountInfoForAccount(identity_manager, account_info);
+
+  RunTestSequenceInContext(
+      views::ElementTrackerViews::GetContextForView(view()),
       // The FakeUserPolicySigninService resolves, indicating the the account
       // is managed and requiring to show the enterprise management opt-in.
       WaitForWebContentsNavigation(
@@ -1241,9 +1334,13 @@
       "Signin.SignIn.Started", signin_metrics::AccessPoint::kForYouFre, 1);
   histogram_tester().ExpectUniqueSample(
       "Signin.SignIn.Completed", signin_metrics::AccessPoint::kForYouFre, 1);
-  histogram_tester().ExpectUniqueSample(
-      "Signin.SyncOptIn.Started", signin_metrics::AccessPoint::kForYouFre, 1);
-  histogram_tester().ExpectTotalCount("Signin.SyncOptIn.Completed", 0);
+  if (!base::FeatureList::IsEnabled(
+          syncer::kReplaceSyncPromosWithSignInPromos)) {
+    // TODO(crbug.com/445927205): Adapt these histograms for history optin.
+    histogram_tester().ExpectUniqueSample(
+        "Signin.SyncOptIn.Started", signin_metrics::AccessPoint::kForYouFre, 1);
+    histogram_tester().ExpectTotalCount("Signin.SyncOptIn.Completed", 0);
+  }
   histogram_tester().ExpectUniqueSample(
       "ProfilePicker.FirstRun.ExitStatus",
       ProfilePicker::FirstRunExitStatus::kCompleted, 1);
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view.cc b/chrome/browser/ui/views/profiles/profile_menu_view.cc
index 586c349..4ae4a62 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view.cc
@@ -402,8 +402,6 @@
   }
   GetWidget()->CloseWithReason(views::Widget::ClosedReason::kUnspecified);
 
-  // TODO(crbug.com/418145883): Trigger the history sync optin
-  // screen for the case of a signed in with history sync off.
   // Pending while the HistorySyncPillExperiment is in progress.
   if (button_type == ActionableItem::kSigninReauthButton) {
     // The reauth button does not trigger a sync opt in.
@@ -769,6 +767,8 @@
             params.button_text = l10n_util::GetStringUTF16(
                 IDS_PROFILE_MENU_SYNC_PROMO_BUTTON_LABEL);
             button_type = ActionableItem::kHistorySyncButton;
+            signin_metrics::LogHistorySyncOptInOffered(
+                explicit_signin_access_point_.value_or(access_point));
             break;
           case signin::ProfileMenuAvatarButtonPromoInfo::Type::
               kBatchUploadPromo:
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
index 8c0c583..3b302b6 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
@@ -2790,11 +2790,11 @@
 
   if (base::FeatureList::IsEnabled(
           syncer::kReplaceSyncPromosWithSignInPromos)) {
-    // `Signin.SyncOptIn.Offered` is still recorded if
-    // `kReplaceSyncPromosWithSignInPromos` is enabled.
-    // TODO(crbug.com/418145883): This should not be recorded.
     histogram_tester.ExpectUniqueSample("Signin.SyncOptIn.Offered",
                                         explicit_access_point,
+                                        /*expected_bucket_count=*/0);
+    histogram_tester.ExpectUniqueSample("Signin.HistorySyncOptIn.Offered",
+                                        explicit_access_point,
                                         /*expected_bucket_count=*/1);
     EXPECT_CALL(
         mock_signin_ui_delegate_,
diff --git a/chrome/browser/ui/views/profiles/profile_picker_post_sign_in_adapter.cc b/chrome/browser/ui/views/profiles/profile_picker_post_sign_in_adapter.cc
index bcb3477..beb7ea5 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_post_sign_in_adapter.cc
+++ b/chrome/browser/ui/views/profiles/profile_picker_post_sign_in_adapter.cc
@@ -159,6 +159,9 @@
 
   // Finishes the sign-in process by moving to the history sync optin screen.
   CHECK(IsInitialized());
+  if (!step_switch_callback_->is_null()) {
+    std::move(step_switch_callback_.value()).Run(true);
+  }
   host_->ShowScreen(
       contents(), GetHistorySyncOptinURL(),
       /*navigation_finished_closure=*/
diff --git a/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.cc
index ad53260..ca24998 100644
--- a/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.cc
@@ -1440,32 +1440,8 @@
 
   std::vector<std::variant<std::unique_ptr<tabs::TabModel>,
                            std::unique_ptr<DetachedTabCollection>>>
-      owned_tabs_and_collections;
-  for (TabDragData& tab_drag_datum : drag_data_.tab_drag_data_) {
-    const int index =
-        attached_model->GetIndexOfWebContents(tab_drag_datum.contents);
-
-    if (index == TabStripModel::kNoTab) {
-      // If this is a tab, we already moved it as part of its group.
-      // If this is a header, we will move it when we get to its first tab.
-      continue;
-    }
-
-    const std::optional<tab_groups::TabGroupId> group =
-        attached_model->GetTabGroupForTab(index);
-    if (std::find(groups_to_move.begin(), groups_to_move.end(), group) !=
-        groups_to_move.end()) {
-      owned_tabs_and_collections.emplace_back(
-          attached_model->DetachTabGroupForInsertion(group.value()));
-    } else if (attached_model->GetTabAtIndex(index)->IsSplit()) {
-      owned_tabs_and_collections.emplace_back(
-          attached_model->DetachSplitTabForInsertion(
-              attached_model->GetTabAtIndex(index)->GetSplit().value()));
-    } else {
-      owned_tabs_and_collections.emplace_back(
-          attached_model->DetachTabAtForInsertion(index));
-    }
-  }
+      owned_tabs_and_collections =
+          attached_model->DetachTabsAndCollectionsForInsertion(dragged_indices);
 
   // If we've removed the last Tab from the TabDragContext, hide the
   // frame now.
diff --git a/chrome/browser/ui/views/tabs/tab_container_impl.cc b/chrome/browser/ui/views/tabs/tab_container_impl.cc
index 3451a18..99133e5 100644
--- a/chrome/browser/ui/views/tabs/tab_container_impl.cc
+++ b/chrome/browser/ui/views/tabs/tab_container_impl.cc
@@ -454,8 +454,10 @@
             ? CloseTabSource::kFromMouse
             : CloseTabSource::kFromTouch;
 
+    // Use actual last tab bounds instead of ideal_bounds to match
+    // current_group_width timing.
     EnterTabClosingMode(
-        tabs_view_model_.ideal_bounds(GetTabCount() - 1).right() -
+        tabs_view_model_.view_at(GetTabCount() - 1)->bounds().right() -
             current_group_width + collapsed_group_width,
         source);
   } else {
diff --git a/chrome/browser/ui/views/tabs/tab_container_unittest.cc b/chrome/browser/ui/views/tabs/tab_container_unittest.cc
index 0611f83a..3fcb334 100644
--- a/chrome/browser/ui/views/tabs/tab_container_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_container_unittest.cc
@@ -235,6 +235,14 @@
     tab_container_->RemoveTab(model_index, was_active);
   }
 
+  void ToggleTabGroup(const tab_groups::TabGroupId& group) {
+    bool is_collapsed = tab_strip_controller_->IsGroupCollapsed(group);
+    tab_strip_controller_->ToggleTabGroupCollapsedState(
+        group, ToggleTabGroupCollapsedStateOrigin::kMouse);
+    tab_container_->ToggleTabGroup(group, !is_collapsed,
+                                   ToggleTabGroupCollapsedStateOrigin::kMouse);
+  }
+
   void AddTabToGroup(int model_index, tab_groups::TabGroupId group) {
     tab_container_->GetTabAtModelIndex(model_index)->SetGroup(group);
     tab_strip_controller_->AddTabToGroup(model_index, group);
@@ -1227,3 +1235,34 @@
   tab_container_->CompleteAnimationAndLayout();
   ASSERT_TRUE(group_header->GetVisible());
 }
+
+// Test for crbug.com/378223017.
+TEST_F(TabContainerTest,
+       CollapseGroupWhileExpandingProducesCorrectOverrideWidth) {
+  tab_groups::TabGroupId group = tab_groups::TabGroupId::GenerateNew();
+
+  AddTab(0, std::nullopt, TabActive::kActive);
+  AddTab(1, group);
+  AddTab(2, group);
+  tab_container_->CompleteAnimationAndLayout();
+  ASSERT_EQ(tab_strip_controller_->IsGroupCollapsed(group), false);
+
+  // Collapse the group.
+  ToggleTabGroup(group);
+  tab_container_->CompleteAnimationAndLayout();
+
+  const int correct_collapsed_pref_width =
+      tab_container_->GetPreferredSize().width();
+
+  // Expanding the group without CompleteAnimationAndLayout()
+  // During animations, should get correct preferred width.
+  ToggleTabGroup(group);
+  tab_container_->AnimateToIdealBounds();
+
+  // Immediately collapse again while expansion is in progress.
+  ToggleTabGroup(group);
+  tab_container_->CompleteAnimationAndLayout();
+
+  EXPECT_EQ(tab_container_->GetPreferredSize().width(),
+            correct_collapsed_pref_width);
+}
diff --git a/chrome/browser/ui/webui/app_home/BUILD.gn b/chrome/browser/ui/webui/app_home/BUILD.gn
index 04decad..29cf8a5 100644
--- a/chrome/browser/ui/webui/app_home/BUILD.gn
+++ b/chrome/browser/ui/webui/app_home/BUILD.gn
@@ -87,6 +87,7 @@
     "//chrome/browser/resources/app_home:resources",
     "//chrome/browser/ui/extensions",
     "//chrome/browser/web_applications",
+    "//chrome/browser/web_applications/extensions",
     "//chrome/browser/web_applications/mojom:mojom_web_apps_enum",
     "//chrome/browser/web_applications/proto",
     "//chrome/common",
diff --git a/chrome/browser/ui/webui/app_home/app_home_page_handler.cc b/chrome/browser/ui/webui/app_home/app_home_page_handler.cc
index d36a4c2..4bb3d4e8 100644
--- a/chrome/browser/ui/webui/app_home/app_home_page_handler.cc
+++ b/chrome/browser/ui/webui/app_home/app_home_page_handler.cc
@@ -17,9 +17,6 @@
 #include "base/values.h"
 #include "chrome/browser/apps/app_service/app_icon_source.h"
 #include "chrome/browser/apps/app_service/app_launch_params.h"
-#include "chrome/browser/apps/app_service/app_service_proxy.h"
-#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
-#include "chrome/browser/apps/app_service/browser_app_launcher.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_ui_util.h"
 #include "chrome/browser/extensions/launch_util.h"
@@ -36,6 +33,7 @@
 #include "chrome/browser/ui/webui/app_home/app_home.mojom-shared.h"
 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
 #include "chrome/browser/web_applications/extension_status_utils.h"
+#include "chrome/browser/web_applications/extensions/launch.h"
 #include "chrome/browser/web_applications/locks/app_lock.h"
 #include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h"
 #include "chrome/browser/web_applications/proto/web_app_install_state.pb.h"
@@ -224,9 +222,8 @@
             : apps::LaunchContainer::kLaunchContainerTab,
         disposition, apps::LaunchSource::kFromAppHomePage);
     params.override_url = override_url;
-    apps::AppServiceProxyFactory::GetForProfile(profile_)
-        ->BrowserAppLauncher()
-        ->LaunchAppWithParams(std::move(params), base::DoNothing());
+    web_app::LaunchExtensionOrWebApp(profile_, std::move(params),
+                                     base::DoNothing());
   } else {
     // To give a more "launchy" experience when using the NTP launcher, we close
     // it automatically. However, if the chrome://apps page is the LAST page in
@@ -247,27 +244,25 @@
                      : WindowOpenDisposition::NEW_FOREGROUND_TAB,
         apps::LaunchSource::kFromAppHomePage);
     params.override_url = override_url;
-    apps::AppServiceProxyFactory::GetForProfile(profile_)
-        ->BrowserAppLauncher()
-        ->LaunchAppWithParams(
-            std::move(params),
-            base::BindOnce(
-                [](base::WeakPtr<Browser> apps_page_browser,
-                   base::WeakPtr<content::WebContents> old_contents,
-                   content::WebContents* new_web_contents) {
-                  if (!apps_page_browser || !old_contents) {
-                    return;
-                  }
-                  if (new_web_contents != old_contents.get() &&
-                      apps_page_browser->tab_strip_model()->count() > 1) {
-                    // This will also destroy the handler, so do not perform
-                    // any actions after.
-                    chrome::CloseWebContents(apps_page_browser.get(),
-                                             old_contents.get(),
-                                             /*add_to_history=*/true);
-                  }
-                },
-                browser_ptr, old_contents_ptr));
+    web_app::LaunchExtensionOrWebApp(
+        profile_, std::move(params),
+        base::BindOnce(
+            [](base::WeakPtr<Browser> apps_page_browser,
+               base::WeakPtr<content::WebContents> old_contents,
+               content::WebContents* new_web_contents) {
+              if (!apps_page_browser || !old_contents) {
+                return;
+              }
+              if (new_web_contents != old_contents.get() &&
+                  apps_page_browser->tab_strip_model()->count() > 1) {
+                // This will also destroy the handler, so do not perform
+                // any actions after.
+                chrome::CloseWebContents(apps_page_browser.get(),
+                                         old_contents.get(),
+                                         /*add_to_history=*/true);
+              }
+            },
+            browser_ptr, old_contents_ptr));
   }
 }
 
diff --git a/chrome/browser/ui/webui/app_home/app_home_page_handler_browsertest.cc b/chrome/browser/ui/webui/app_home/app_home_page_handler_browsertest.cc
index 38e1a04..515a9a0c1 100644
--- a/chrome/browser/ui/webui/app_home/app_home_page_handler_browsertest.cc
+++ b/chrome/browser/ui/webui/app_home/app_home_page_handler_browsertest.cc
@@ -221,7 +221,7 @@
         extensions::manifest_keys::kPlatformAppBackgroundPage,
         "background.html");
 
-    std::string error;
+    std::u16string error;
     scoped_refptr<extensions::Extension> extension =
         extensions::Extension::Create(
             base::FilePath(), extensions::mojom::ManifestLocation::kUnpacked,
@@ -238,7 +238,7 @@
                                      .Set(keys::kVersion, "1.0")
                                      .Set(keys::kManifestVersion, 2);
 
-    std::string error;
+    std::u16string error;
     scoped_refptr<extensions::Extension> extension =
         extensions::Extension::Create(
             base::FilePath(), extensions::mojom::ManifestLocation::kUnpacked,
diff --git a/chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.cc b/chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.cc
index 302292b2..ffdb12b 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.cc
@@ -505,7 +505,6 @@
       "onDeviceGrammarCheckEnabled",
       base::FeatureList::IsEnabled(features::kOnDeviceGrammarCheck));
 
-  html_source->AddBoolean("systemJapanesePhysicalTyping", true);
   html_source->AddBoolean(
       "languagePacksInSettingsEnabled",
       base::FeatureList::IsEnabled(features::kLanguagePacksInSettings));
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 77b6c4d4..b7fc482 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -103,7 +103,6 @@
 #include "ash/webui/print_preview_cros/url_constants.h"
 #include "ash/webui/recorder_app_ui/url_constants.h"
 #include "ash/webui/vc_background_ui/url_constants.h"
-#include "chrome/browser/ash/extensions/url_constants.h"
 #include "chromeos/ash/components/scalable_iph/scalable_iph_constants.h"
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc
index 9e88a16..8c77950 100644
--- a/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc
+++ b/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc
@@ -39,7 +39,7 @@
 #include "ui/webui/webui_util.h"
 
 TabStripUI::TabStripUI(content::WebUI* web_ui)
-    : ui::MojoWebUIController(web_ui, /* enable_chrome_send */ true),
+    : ui::MojoWebUIController(web_ui, /*enable_chrome_send*/ false),
       webui_load_timer_(web_ui->GetWebContents(),
                         "WebUITabStrip.LoadDocumentTime",
                         "WebUITabStrip.LoadCompletedTime") {
diff --git a/chrome/browser/web_applications/extensions/BUILD.gn b/chrome/browser/web_applications/extensions/BUILD.gn
index e18df45..279e896f 100644
--- a/chrome/browser/web_applications/extensions/BUILD.gn
+++ b/chrome/browser/web_applications/extensions/BUILD.gn
@@ -18,6 +18,12 @@
   if (is_mac) {
     sources += [ "web_app_extension_shortcut_mac.mm" ]
   }
+  if (!is_chromeos) {
+    sources += [
+      "launch.cc",
+      "launch.h",
+    ]
+  }
 
   # Enable the "exit_time_destructors" warning here to avoid accidentally
   # adding exit time destructors and because the flag is not enabled by default.
@@ -42,6 +48,13 @@
     "//extensions/browser",
     "//skia",
   ]
+
+  if (!is_chromeos) {
+    deps += [
+      "//chrome/browser/apps/app_service:constants",
+      "//chrome/browser/ui/extensions",
+    ]
+  }
 }
 
 source_set("unit_tests") {
diff --git a/chrome/browser/web_applications/extensions/launch.cc b/chrome/browser/web_applications/extensions/launch.cc
new file mode 100644
index 0000000..846562be
--- /dev/null
+++ b/chrome/browser/web_applications/extensions/launch.cc
@@ -0,0 +1,46 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/extensions/launch.h"
+
+#include <utility>
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/extensions/application_launch.h"
+#include "chrome/browser/web_applications/web_app_command_scheduler.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_util.h"
+#include "extensions/common/extension.h"
+
+namespace web_app {
+
+void LaunchExtensionOrWebApp(
+    Profile* profile,
+    apps::AppLaunchParams params,
+    base::OnceCallback<void(content::WebContents*)> callback) {
+  const extensions::Extension* extension =
+      extensions::ExtensionRegistry::Get(profile)->GetInstalledExtension(
+          params.app_id);
+  if (extension) {
+    std::move(callback).Run(::OpenApplication(profile, std::move(params)));
+    return;
+  }
+
+  web_app::WebAppProvider* provider =
+      web_app::WebAppProvider::GetForLocalAppsUnchecked(profile);
+  provider->scheduler().LaunchAppWithCustomParams(
+      std::move(params),
+      base::BindOnce(
+          [](base::OnceCallback<void(content::WebContents*)> callback,
+             base::WeakPtr<Browser> browser,
+             base::WeakPtr<content::WebContents> web_contents,
+             apps::LaunchContainer launch_container) {
+            std::move(callback).Run(web_contents.get());
+          },
+          std::move(callback)));
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/extensions/launch.h b/chrome/browser/web_applications/extensions/launch.h
new file mode 100644
index 0000000..d9a6008
--- /dev/null
+++ b/chrome/browser/web_applications/extensions/launch.h
@@ -0,0 +1,40 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_LAUNCH_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_LAUNCH_H_
+
+#include "base/functional/callback.h"
+#include "build/build_config.h"
+#include "chrome/browser/apps/app_service/app_launch_params.h"
+
+class Profile;
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+// TODO(hidehiko): Revisit here how can we do better for Chrome browser on
+// ChromeOS. Conceptually, this should be ok to use a part of web browser
+// implementation even on ChromeOS (as a cross platform implementation),
+// but should not be used as a part of OS system implementation.
+static_assert(!BUILDFLAG(IS_CHROMEOS),
+              "This should not be included in ChromeOS builds.");
+
+namespace web_app {
+
+// Launches an app for the given `app_id` in a way specified by `params`.
+// This first looks up Extension by the app id, and if there is an extension,
+// launches it. Otherwise, gives it a try to launch a WebApp.
+// Note: The Extension part is being deprecated and probably soon removed.
+// Then callers may be able to directly call into WebApps' scheduler.
+// Importantly, this should NOT depend on AppServiceProxy.
+void LaunchExtensionOrWebApp(
+    Profile* profile,
+    apps::AppLaunchParams params,
+    base::OnceCallback<void(content::WebContents*)> callback);
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_LAUNCH_H_
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index b2fa5194..54b562d 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1759427843-a4b74c4f2ef89337f28ffafef8969aea7c23a81a-872468c007761a0bfbefcb0daccc3c5f24f8c57d.profdata
+chrome-android32-main-1759471195-ed610a44cbd68c954648de9987b06558d133c998-df6ca5cbf01887a49eac5288d4c8ffcdcfdbd1d9.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 7c12ea7..b8d85286 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1759432691-877a6ed7fa8cf053b79f6bd58cd1277b90fa8f9a-6f79e7762d9ec3a0834f47bcdbe5354569269348.profdata
+chrome-android64-main-1759472896-ec3f58cfec95a1b6734f4e5bfdce5c9c9623eb3f-e382759fbb69a202f5ef09b83abc8978107bfe05.profdata
diff --git a/chrome/build/android-desktop-x64.pgo.txt b/chrome/build/android-desktop-x64.pgo.txt
index 84337ec..cd66d4f2 100644
--- a/chrome/build/android-desktop-x64.pgo.txt
+++ b/chrome/build/android-desktop-x64.pgo.txt
@@ -1 +1 @@
-chrome-android-desktop-x64-main-1759427843-37ec487e8cf1dc35d10bb30a7aa54091fb9db173-872468c007761a0bfbefcb0daccc3c5f24f8c57d.profdata
+chrome-android-desktop-x64-main-1759471195-c4a599c209e965c36370a76739ae140234ccef09-df6ca5cbf01887a49eac5288d4c8ffcdcfdbd1d9.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index d0360f4..51d7a3b4 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1759427843-6530e9f8964523f938d394fdda895286d1afc5a6-872468c007761a0bfbefcb0daccc3c5f24f8c57d.profdata
+chrome-linux-main-1759471195-7b4f8c72fe3516a08ad67cd3ae0cbe9dd6448b46-df6ca5cbf01887a49eac5288d4c8ffcdcfdbd1d9.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 8ece558..1e1e1eb3 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1759442206-5894081ced9b33dbe5eff7d5dc00a5240b14fdd2-d7d1864dc86108a3b5d115417dd6fc5e6b819658.profdata
+chrome-mac-arm-main-1759477610-c6275fb16083e3e9cb654c34bea896b9f970363d-82761d7a06d40681a27389747143d1f2ec045a03.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index b4d4d5c..622c6c03 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1759427843-1f180b0def2181f5471e6fc8a82acae2f296ec62-872468c007761a0bfbefcb0daccc3c5f24f8c57d.profdata
+chrome-mac-main-1759471195-6ca68d33eea05a217a1458d4fe432178330c039b-df6ca5cbf01887a49eac5288d4c8ffcdcfdbd1d9.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index f214aa9..218b12ca 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1759427843-fe049def3a9c9220b921b0c61b09719d28fb8f95-872468c007761a0bfbefcb0daccc3c5f24f8c57d.profdata
+chrome-win32-main-1759460225-2e93604f69927971692b8f50f8a6d96966d2274e-e4c9f39a224675de859df77b477f38057f11819e.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 21ff1125..83d74b7 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1759417109-5c64afd1d6dc0448c4d6b30da9e843d7fe9a4a42-7d79a09df7ee2cea6f3de99702199f150cc7dfc2.profdata
+chrome-win64-main-1759460225-a4ff3dc8aa5343c5f18949cafd211aaa5f5972fd-e4c9f39a224675de859df77b477f38057f11819e.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index ba4b9ea..a212ff2 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -83,6 +83,10 @@
 // When enabled, app shims used by PWAs will be signed with an ad-hoc signature
 // https://crbug.com/40276068
 BASE_FEATURE(kUseAdHocSigningForWebAppShims, base::FEATURE_DISABLED_BY_DEFAULT);
+
+// When enabled, the KeychainKeyProvider is used to provide the OS Crypt async
+// key.
+BASE_FEATURE(kUseKeychainKeyProvider, base::FEATURE_ENABLED_BY_DEFAULT);
 #endif  // BUILDFLAG(IS_MAC)
 
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index f3515ab1..3e7ad54 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -80,6 +80,8 @@
 BASE_DECLARE_FEATURE(kAppShimNotificationAttribution);
 COMPONENT_EXPORT(CHROME_FEATURES)
 BASE_DECLARE_FEATURE(kUseAdHocSigningForWebAppShims);
+COMPONENT_EXPORT(CHROME_FEATURES)
+BASE_DECLARE_FEATURE(kUseKeychainKeyProvider);
 #endif  // BUILDFLAG(IS_MAC)
 
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
diff --git a/chrome/common/extensions/api/common_extension_api_unittest.cc b/chrome/common/extensions/api/common_extension_api_unittest.cc
index d528ad63..2d7be89c 100644
--- a/chrome/common/extensions/api/common_extension_api_unittest.cc
+++ b/chrome/common/extensions/api/common_extension_api_unittest.cc
@@ -496,7 +496,7 @@
     manifest.Set("permissions", std::move(permissions_list));
   }
 
-  std::string error;
+  std::u16string error;
   scoped_refptr<Extension> extension(
       Extension::Create(base::FilePath(), mojom::ManifestLocation::kUnpacked,
                         manifest, Extension::NO_FLAGS, &error));
@@ -582,7 +582,7 @@
                          base::Value(base::Value::Type::LIST));
   values.SetByDottedPath(manifest_keys::kLaunchWebURL,
                          "http://www.example.com");
-  std::string error;
+  std::u16string error;
   scoped_refptr<Extension> extension(
       Extension::Create(base::FilePath(), mojom::ManifestLocation::kInternal,
                         values, Extension::NO_FLAGS, &error));
@@ -610,7 +610,7 @@
     manifest.Set("permissions", std::move(permissions_list));
   }
 
-  std::string error;
+  std::u16string error;
   scoped_refptr<Extension> extension(
       Extension::Create(base::FilePath(), mojom::ManifestLocation::kInternal,
                         manifest, Extension::NO_FLAGS, &error));
diff --git a/chrome/common/extensions/api/storage/storage_schema_manifest_handler_unittest.cc b/chrome/common/extensions/api/storage/storage_schema_manifest_handler_unittest.cc
index ec44b8c..2f2e2cc 100644
--- a/chrome/common/extensions/api/storage/storage_schema_manifest_handler_unittest.cc
+++ b/chrome/common/extensions/api/storage/storage_schema_manifest_handler_unittest.cc
@@ -39,7 +39,7 @@
   }
 
   scoped_refptr<Extension> CreateExtension(const std::string& schema) {
-    std::string error;
+    std::u16string error;
     scoped_refptr<Extension> extension = Extension::Create(
         temp_dir_.GetPath(), mojom::ManifestLocation::kUnpacked, manifest_,
         Extension::NO_FLAGS, "", &error);
diff --git a/chrome/common/extensions/extension_test_util.cc b/chrome/common/extensions/extension_test_util.cc
index 8740819..e839a04 100644
--- a/chrome/common/extensions/extension_test_util.cc
+++ b/chrome/common/extensions/extension_test_util.cc
@@ -10,6 +10,7 @@
 #include "base/files/file_path.h"
 #include "base/json/json_file_value_serializer.h"
 #include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
@@ -25,6 +26,8 @@
 
 namespace extension_test_util {
 
+// TODO(crbug.com/41317803): Continue removing std::string error and
+// replacing with std::u16string.
 scoped_refptr<Extension> LoadManifestUnchecked(const std::string& dir,
                                                const std::string& test_file,
                                                ManifestLocation location,
@@ -45,8 +48,10 @@
   const base::Value::Dict* dict = result->GetIfDict();
   CHECK(dict);
 
+  std::u16string utf16_error;
   scoped_refptr<Extension> extension = Extension::Create(
-      path.DirName(), location, *dict, extra_flags, id, error);
+      path.DirName(), location, *dict, extra_flags, id, &utf16_error);
+  *error = base::UTF16ToUTF8(utf16_error);
   return extension;
 }
 
diff --git a/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc b/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc
index 3a5fdfa..b6487c7 100644
--- a/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc
+++ b/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc
@@ -116,12 +116,16 @@
 using extensions::api::manifest_types::ChromeSettingsOverrides;
 namespace manifest_keys = extensions::manifest_keys;
 
+// TODO(crbug.com/41317803): Continue removing std::string error and
+// replacing with std::u16string.
 scoped_refptr<Extension> CreateExtension(const base::Value::Dict& manifest,
                                          std::string* error) {
+  std::u16string utf16_error;
   scoped_refptr<Extension> extension =
       Extension::Create(base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
                         extensions::mojom::ManifestLocation::kInvalidLocation,
-                        manifest, Extension::NO_FLAGS, error);
+                        manifest, Extension::NO_FLAGS, &utf16_error);
+  *error = base::UTF16ToUTF8(utf16_error);
   return extension;
 }
 
diff --git a/chrome/common/extensions/manifest_handlers/theme_handler_unittest.cc b/chrome/common/extensions/manifest_handlers/theme_handler_unittest.cc
index 1d3b257..bb552e44 100644
--- a/chrome/common/extensions/manifest_handlers/theme_handler_unittest.cc
+++ b/chrome/common/extensions/manifest_handlers/theme_handler_unittest.cc
@@ -26,6 +26,9 @@
 class ThemeHandlerTest : public testing::Test {
  protected:
   // Creates a dummy extension for the given theme dictionary.
+  // TODO(crbug.com/41317803): Continue removing std::string error and
+  // replacing with std::u16string. Once this is done, consider changing the
+  // return type to base::expected<scoped_refptr<Extension>, std::u16string>.
   scoped_refptr<Extension> CreateExtension(base::Value::Dict&& theme_dict,
                                            std::string& error) {
     base::Value::Dict manifest;
@@ -34,9 +37,12 @@
     manifest.Set(keys::kVersion, "1.0");
     manifest.Set(keys::kTheme, std::move(theme_dict));
 
-    return Extension::Create(base::FilePath(),
-                             mojom::ManifestLocation::kInternal, manifest,
-                             Extension::NO_FLAGS, &error);
+    std::u16string utf16_error;
+    scoped_refptr<Extension> extension =
+        Extension::Create(base::FilePath(), mojom::ManifestLocation::kInternal,
+                          manifest, Extension::NO_FLAGS, &utf16_error);
+    error = base::UTF16ToUTF8(utf16_error);
+    return extension;
   }
 };
 
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_side_panel_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_side_panel_unittest.cc
index 9af5231..0da7accd 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_side_panel_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_side_panel_unittest.cc
@@ -65,6 +65,8 @@
 
  protected:
   // Empty filepath doesn't exist test coverage.
+  // TODO(crbug.com/41317803): Continue removing std::string error and
+  // replacing with std::u16string.
   scoped_refptr<Extension> CreateExtension(const base::Value::Dict& manifest,
                                            std::string* error) {
     base::Value::Dict manifest_base;
@@ -72,9 +74,12 @@
     manifest_base.Set("version", "1.0");
     manifest_base.Set("manifest_version", 3);
     manifest_base.Merge(manifest.Clone());
-    return Extension::Create(temp_dir_.GetPath(),
-                             mojom::ManifestLocation::kUnpacked, manifest_base,
-                             Extension::NO_FLAGS, "", error);
+    std::u16string utf16_error;
+    scoped_refptr<Extension> extension = Extension::Create(
+        temp_dir_.GetPath(), mojom::ManifestLocation::kUnpacked, manifest_base,
+        Extension::NO_FLAGS, "", &utf16_error);
+    *error = base::UTF16ToUTF8(utf16_error);
+    return extension;
   }
 
  private:
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_theme_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_theme_unittest.cc
index 3e346f23..d719510 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_theme_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_theme_unittest.cc
@@ -24,6 +24,8 @@
   void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
 
  protected:
+  // TODO(crbug.com/41317803): Continue removing std::string error and
+  // replacing with std::u16string.
   scoped_refptr<Extension> CreateExtension(const base::Value::Dict& manifest,
                                            std::string* error) {
     base::Value::Dict manifest_base;
@@ -31,9 +33,12 @@
     manifest_base.Set("version", "1.0");
     manifest_base.Set("manifest_version", 3);
     manifest_base.Merge(manifest.Clone());
-    return Extension::Create(temp_dir_.GetPath(),
-                             mojom::ManifestLocation::kUnpacked, manifest_base,
-                             Extension::NO_FLAGS, "", error);
+    std::u16string utf16_error;
+    scoped_refptr<Extension> extension = Extension::Create(
+        temp_dir_.GetPath(), mojom::ManifestLocation::kUnpacked, manifest_base,
+        Extension::NO_FLAGS, "", &utf16_error);
+    *error = base::UTF16ToUTF8(utf16_error);
+    return extension;
   }
 
  private:
diff --git a/chrome/common/extensions/sync_type_unittest.cc b/chrome/common/extensions/sync_type_unittest.cc
index a09c178..e718249 100644
--- a/chrome/common/extensions/sync_type_unittest.cc
+++ b/chrome/common/extensions/sync_type_unittest.cc
@@ -53,7 +53,7 @@
     if (type != THEME)
       source.Set(keys::kConvertedFromUserScript, type == USER_SCRIPT);
 
-    std::string error;
+    std::u16string error;
     scoped_refptr<Extension> extension = Extension::Create(
         extension_path, location, source, creation_flags, &error);
     EXPECT_TRUE(extension.get());
@@ -152,11 +152,11 @@
   manifest.SetByDottedPath(keys::kPlatformAppBackgroundPage, "background.html");
 
   // Default to true.
-  std::string error;
+  std::u16string error;
   scoped_refptr<Extension> app =
       Extension::Create(base::FilePath(), mojom::ManifestLocation::kComponent,
                         manifest, 0, &error);
-  EXPECT_EQ(error, std::string());
+  EXPECT_EQ(error, std::u16string());
   EXPECT_TRUE(AppDisplayInfo::ShouldDisplayInAppLauncher(*app));
   EXPECT_TRUE(AppDisplayInfo::ShouldDisplayInNewTabPage(*app));
 
@@ -164,7 +164,7 @@
   manifest.Set(keys::kDisplayInLauncher, false);
   app = Extension::Create(base::FilePath(), mojom::ManifestLocation::kComponent,
                           manifest, 0, &error);
-  EXPECT_EQ(error, std::string());
+  EXPECT_EQ(error, std::u16string());
   EXPECT_FALSE(AppDisplayInfo::ShouldDisplayInAppLauncher(*app));
   EXPECT_FALSE(AppDisplayInfo::ShouldDisplayInNewTabPage(*app));
 
@@ -172,7 +172,7 @@
   manifest.Set(keys::kDisplayInNewTabPage, true);
   app = Extension::Create(base::FilePath(), mojom::ManifestLocation::kComponent,
                           manifest, 0, &error);
-  EXPECT_EQ(error, std::string());
+  EXPECT_EQ(error, std::u16string());
   EXPECT_FALSE(AppDisplayInfo::ShouldDisplayInAppLauncher(*app));
   EXPECT_TRUE(AppDisplayInfo::ShouldDisplayInNewTabPage(*app));
 
@@ -181,7 +181,7 @@
   manifest.Set(keys::kDisplayInNewTabPage, false);
   app = Extension::Create(base::FilePath(), mojom::ManifestLocation::kComponent,
                           manifest, 0, &error);
-  EXPECT_EQ(error, std::string());
+  EXPECT_EQ(error, std::u16string());
   EXPECT_TRUE(AppDisplayInfo::ShouldDisplayInAppLauncher(*app));
   EXPECT_FALSE(AppDisplayInfo::ShouldDisplayInNewTabPage(*app));
 
@@ -189,7 +189,7 @@
   manifest.Set(keys::kDisplayInNewTabPage, "invalid");
   app = Extension::Create(base::FilePath(), mojom::ManifestLocation::kComponent,
                           manifest, 0, &error);
-  EXPECT_EQ(error, base::UTF16ToUTF8(errors::kInvalidDisplayInNewTabPage));
+  EXPECT_EQ(error, errors::kInvalidDisplayInNewTabPage);
 }
 
 TEST_F(ExtensionSyncTypeTest, OnlySyncInternal) {
diff --git a/chrome/renderer/chrome_content_renderer_client_unittest.cc b/chrome/renderer/chrome_content_renderer_client_unittest.cc
index 160c189e..198146bb 100644
--- a/chrome/renderer/chrome_content_renderer_client_unittest.cc
+++ b/chrome/renderer/chrome_content_renderer_client_unittest.cc
@@ -75,7 +75,7 @@
                              std::move(url_list));
     manifest.SetByDottedPath(extensions::manifest_keys::kLaunchWebURL, app_url);
   }
-  std::string error;
+  std::u16string error;
   return extensions::Extension::Create(base::FilePath(), location, manifest,
                                        flags, &error);
 }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index cd8f5b27..f42f25f 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -11968,6 +11968,7 @@
         deps += [
           "//chrome/browser/accessibility:test_support",
           "//chrome/browser/profiles",
+          "//chrome/browser/web_applications/extensions",
         ]
         if (use_aura) {
           sources += [ "../browser/ui/views/tooltip/tooltip_aura_interactive_uitest_win.cc" ]
diff --git a/chrome/test/data/webui/cr_components/searchbox/searchbox_match_test.ts b/chrome/test/data/webui/cr_components/searchbox/searchbox_match_test.ts
index 5e5b270..2cb1100 100644
--- a/chrome/test/data/webui/cr_components/searchbox/searchbox_match_test.ts
+++ b/chrome/test/data/webui/cr_components/searchbox/searchbox_match_test.ts
@@ -166,12 +166,12 @@
     await microtasksFinished();
 
     // When a match is selected.
-    let selection = {
+    matchEl.selection = {
       line: 0,
       state: SelectionLineState.kNormal,
       actionIndex: 0,
     };
-    matchEl.updateSelection(selection);
+    await microtasksFinished();
     assertFalse(
         !!matchEl.shadowRoot.querySelector('#focus-indicator.selected-within'));
     assertFalse(!!matchEl.shadowRoot.querySelector('#keyword.selected'));
@@ -182,12 +182,12 @@
     assertFalse(!!matchEl.shadowRoot.querySelector('#remove.selected'));
 
     // When a match is unselected.
-    selection = {
+    matchEl.selection = {
       line: 1,
       state: SelectionLineState.kNormal,
       actionIndex: 0,
     };
-    matchEl.updateSelection(selection);
+    await microtasksFinished();
     assertFalse(
         !!matchEl.shadowRoot.querySelector('#focus-indicator.selected-within'));
     assertFalse(!!matchEl.shadowRoot.querySelector('#keyword.selected'));
@@ -198,12 +198,12 @@
     assertFalse(!!matchEl.$.remove.classList.contains('selected'));
 
     // When the keyword chip is selected.
-    selection = {
+    matchEl.selection = {
       line: 0,
       state: SelectionLineState.kKeywordMode,
       actionIndex: 0,
     };
-    matchEl.updateSelection(selection);
+    await microtasksFinished();
     assertTrue(
         !!matchEl.shadowRoot.querySelector('#focus-indicator.selected-within'));
     assertTrue(!!matchEl.shadowRoot.querySelector('#keyword.selected'));
@@ -214,12 +214,12 @@
     assertFalse(!!matchEl.shadowRoot.querySelector('#remove.selected'));
 
     // When the 1st action chip is selected.
-    selection = {
+    matchEl.selection = {
       line: 0,
       state: SelectionLineState.kFocusedButtonAction,
       actionIndex: 0,
     };
-    matchEl.updateSelection(selection);
+    await microtasksFinished();
     assertTrue(
         !!matchEl.shadowRoot.querySelector('#focus-indicator.selected-within'));
     assertFalse(!!matchEl.shadowRoot.querySelector('#keyword.selected'));
@@ -230,12 +230,12 @@
     assertFalse(!!matchEl.shadowRoot.querySelector('#remove.selected'));
 
     // When the 2nd action chip is selected.
-    selection = {
+    matchEl.selection = {
       line: 0,
       state: SelectionLineState.kFocusedButtonAction,
       actionIndex: 1,
     };
-    matchEl.updateSelection(selection);
+    await microtasksFinished();
     assertTrue(
         !!matchEl.shadowRoot.querySelector('#focus-indicator.selected-within'));
     assertFalse(!!matchEl.shadowRoot.querySelector('#keyword.selected'));
@@ -246,12 +246,12 @@
     assertFalse(!!matchEl.shadowRoot.querySelector('#remove.selected'));
 
     // When the remove button is selected.
-    selection = {
+    matchEl.selection = {
       line: 0,
       state: SelectionLineState.kFocusedButtonRemoveSuggestion,
       actionIndex: 0,
     };
-    matchEl.updateSelection(selection);
+    await microtasksFinished();
     assertTrue(
         !!matchEl.shadowRoot.querySelector('#focus-indicator.selected-within'));
     assertFalse(!!matchEl.shadowRoot.querySelector('#keyword.selected'));
diff --git a/chrome/updater/app/app_update_apps.cc b/chrome/updater/app/app_update_apps.cc
index bd2af9f..a7df907a 100644
--- a/chrome/updater/app/app_update_apps.cc
+++ b/chrome/updater/app/app_update_apps.cc
@@ -88,15 +88,17 @@
   }
 }
 
-void OnUpdateComplete(base::OnceCallback<void(int)> cb,
+void OnUpdateComplete(const std::string& app_id,
+                      base::OnceClosure cb,
                       UpdateService::Result result) {
   if (result == UpdateService::Result::kSuccess) {
-    std::cout << "Update apps completed successfully." << std::endl;
-    std::move(cb).Run(0);
+    std::cout << std::quoted(app_id) << ": update completed successfully"
+              << std::endl;
   } else {
-    std::cout << "Update apps failed, result: " << result << std::endl;
-    std::move(cb).Run(-1);
+    std::cout << std::quoted(app_id) << ": update failed, result = " << result
+              << std::endl;
   }
+  std::move(cb).Run();
 }
 
 }  // namespace
@@ -106,6 +108,10 @@
   ~AppUpdateApps() override = default;
   [[nodiscard]] int Initialize() override;
   void FirstTaskRun() override;
+  void DoUpdateApps(
+      const std::vector<updater::UpdateService::AppState>& states);
+
+  scoped_refptr<UpdateService> service_proxy_;
 };
 
 int AppUpdateApps::Initialize() {
@@ -129,21 +135,41 @@
   return kErrorOk;
 }
 
+void AppUpdateApps::DoUpdateApps(
+    const std::vector<updater::UpdateService::AppState>& states) {
+  if (states.empty()) {
+    std::cout << "Done running `--update-apps`" << std::endl;
+    Shutdown(kErrorOk);
+    return;
+  }
+
+  const std::string app_id = states.front().app_id;
+  service_proxy_->Update(
+      app_id, /*install_data_index=*/"", UpdateService::Priority::kForeground,
+      UpdateService::PolicySameVersionUpdate::kNotAllowed,
+      /*language=*/{}, base::BindRepeating(OnAppStateChanged),
+      base::BindOnce(
+          [](const std::string& app_id, base::OnceClosure cb,
+             UpdateService::Result result) {
+            OnUpdateComplete(app_id, std::move(cb), result);
+          },
+          app_id,
+          base::BindOnce(&AppUpdateApps::DoUpdateApps, this,
+                         std::vector<updater::UpdateService::AppState>(
+                             states.begin() + 1, states.end()))));
+}
+
 void AppUpdateApps::FirstTaskRun() {
   if (!IsSystemInstall(updater_scope()) && WrongUser(updater_scope())) {
-    std::cout << "The current user is not compatible with the current scope.";
+    std::cout << "The current user is not compatible with the current scope."
+              << std::endl;
     Shutdown(kErrorWrongUser);
     return;
   }
 
-  CreateUpdateServiceProxy(updater_scope())
-      ->UpdateAll(base::BindRepeating(OnAppStateChanged),
-                  base::BindOnce(
-                      [](base::OnceCallback<void(int)> cb,
-                         UpdateService::Result result) {
-                        OnUpdateComplete(std::move(cb), result);
-                      },
-                      base::BindOnce(&AppUpdateApps::Shutdown, this)));
+  service_proxy_ = CreateUpdateServiceProxy(updater_scope());
+  service_proxy_->GetAppStates(
+      base::BindOnce(&AppUpdateApps::DoUpdateApps, this));
 }
 
 scoped_refptr<App> MakeAppUpdateApps() {
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc
index 6342794..d66e7174 100644
--- a/chrome/updater/test/integration_tests.cc
+++ b/chrome/updater/test/integration_tests.cc
@@ -1610,14 +1610,16 @@
   base::Version v1("1");
   ScopedServer test_server(test_commands_);
   ASSERT_NO_FATAL_FAILURE(ExpectUpdateSequence(
-      &test_server, kAppId, "", UpdateService::Priority::kBackground,
+      &test_server, kAppId, "", UpdateService::Priority::kForeground,
       base::Version("0.1"), v1));
+  ASSERT_NO_FATAL_FAILURE(ExpectNoUpdateSequence(&test_server, kUpdaterAppId));
   ASSERT_NO_FATAL_FAILURE(RunUpdateApps(0));
 
   base::Version v2("2");
   ASSERT_NO_FATAL_FAILURE(ExpectUpdateSequence(
-      &test_server, kAppId, "", UpdateService::Priority::kBackground, v1, v2,
+      &test_server, kAppId, "", UpdateService::Priority::kForeground, v1, v2,
       false, true));
+  ASSERT_NO_FATAL_FAILURE(ExpectNoUpdateSequence(&test_server, kUpdaterAppId));
   ASSERT_NO_FATAL_FAILURE(RunUpdateApps(0));
 
   ASSERT_TRUE(WaitForUpdaterExit());
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index abfddcf..f635cf4 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-16437.0.0-1072127
\ No newline at end of file
+16437.0.0-1072140
\ No newline at end of file
diff --git a/chromeos/ash/experiences/arc/arc_features.cc b/chromeos/ash/experiences/arc/arc_features.cc
index 36b403de..25348aa 100644
--- a/chromeos/ash/experiences/arc/arc_features.cc
+++ b/chromeos/ash/experiences/arc/arc_features.cc
@@ -56,11 +56,6 @@
              "ArcBootCompletedBroadcast",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-// Controls experimental Custom Tabs feature for ARC.
-BASE_FEATURE(kCustomTabsExperimentFeature,
-             "ArcCustomTabsExperiment",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 // Defers the ARC actvation until the user session start up tasks
 // are completed to give more resources to critical tasks for user session
 // starting.
diff --git a/chromeos/ash/experiences/arc/arc_features.h b/chromeos/ash/experiences/arc/arc_features.h
index b1b6e4a..c54b447 100644
--- a/chromeos/ash/experiences/arc/arc_features.h
+++ b/chromeos/ash/experiences/arc/arc_features.h
@@ -23,7 +23,6 @@
 BASE_DECLARE_FEATURE(kBlockIoScheduler);
 BASE_DECLARE_FEATURE_PARAM(bool, kEnableDataBlockIoScheduler);
 BASE_DECLARE_FEATURE(kBootCompletedBroadcastFeature);
-BASE_DECLARE_FEATURE(kCustomTabsExperimentFeature);
 BASE_DECLARE_FEATURE(kDeferArcActivationUntilUserSessionStartUpTaskCompletion);
 BASE_DECLARE_FEATURE_PARAM(int, kDeferArcActivationHistoryWindow);
 BASE_DECLARE_FEATURE_PARAM(int, kDeferArcActivationHistoryThreshold);
diff --git a/chromeos/ash/experiences/arc/session/arc_session_impl.cc b/chromeos/ash/experiences/arc/session/arc_session_impl.cc
index 5ad81ec..24e00ee 100644
--- a/chromeos/ash/experiences/arc/session/arc_session_impl.cc
+++ b/chromeos/ash/experiences/arc/session/arc_session_impl.cc
@@ -421,12 +421,7 @@
   StartParams params;
   params.native_bridge_experiment =
       base::FeatureList::IsEnabled(arc::kNativeBridgeToggleFeature);
-  // Enable Custom Tabs only on Dev and Canary.
-  const bool is_custom_tab_enabled =
-      base::FeatureList::IsEnabled(arc::kCustomTabsExperimentFeature) &&
-      delegate_->GetChannel() != version_info::Channel::STABLE &&
-      delegate_->GetChannel() != version_info::Channel::BETA;
-  params.arc_custom_tabs_experiment = is_custom_tab_enabled;
+  params.arc_custom_tabs_experiment = false;
   params.lcd_density = lcd_density_;
   params.num_cores_disabled = num_cores_disabled;
   params.enable_tts_caching = true;
diff --git a/chromeos/ash/experiences/arc/session/arc_vm_client_adapter_unittest.cc b/chromeos/ash/experiences/arc/session/arc_vm_client_adapter_unittest.cc
index bc0e020..2a31042 100644
--- a/chromeos/ash/experiences/arc/session/arc_vm_client_adapter_unittest.cc
+++ b/chromeos/ash/experiences/arc/session/arc_vm_client_adapter_unittest.cc
@@ -82,7 +82,6 @@
   params.lcd_density = 240;
   params.play_store_auto_update =
       StartParams::PlayStoreAutoUpdate::AUTO_UPDATE_ON;
-  params.arc_custom_tabs_experiment = true;
   params.num_cores_disabled = 2;
   return params;
 }
@@ -2771,22 +2770,6 @@
   EXPECT_FALSE(request.enable_web_view_zygote_lazy_init());
 }
 
-TEST_F(ArcVmClientAdapterTest, ArcCustomTabsExperimentFalse) {
-  StartParams start_params(GetPopulatedStartParams());
-  start_params.arc_custom_tabs_experiment = false;
-  StartMiniArcWithParams(true, std::move(start_params));
-  const auto& request = GetTestConciergeClient()->start_arc_vm_request();
-  EXPECT_FALSE(request.mini_instance_request().arc_custom_tabs_experiment());
-}
-
-TEST_F(ArcVmClientAdapterTest, ArcCustomTabsExperimentTrue) {
-  StartParams start_params(GetPopulatedStartParams());
-  start_params.arc_custom_tabs_experiment = true;
-  StartMiniArcWithParams(true, std::move(start_params));
-  const auto& request = GetTestConciergeClient()->start_arc_vm_request();
-  EXPECT_TRUE(request.mini_instance_request().arc_custom_tabs_experiment());
-}
-
 TEST_F(ArcVmClientAdapterTest, StartMiniArc_ArcSignedIn) {
   StartParams start_params(GetPopulatedStartParams());
   start_params.arc_signed_in = true;
diff --git a/clank b/clank
index 8c25644..39126c5 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 8c25644608a17fa7f7a4ff87f9b99e9f2b5b1953
+Subproject commit 39126c5ac8a45b997af69d2be128b80acb112d5d
diff --git a/components/commerce/core/commerce_feature_list.cc b/components/commerce/core/commerce_feature_list.cc
index 1cd337ec..481a5353 100644
--- a/components/commerce/core/commerce_feature_list.cc
+++ b/components/commerce/core/commerce_feature_list.cc
@@ -153,9 +153,8 @@
 // Promotion in Magic Stack for Price Tracking users from other platforms.
 BASE_FEATURE(kPriceTrackingPromo, base::FEATURE_ENABLED_BY_DEFAULT);
 
-// ShopCard in Magic Stack, including shopping features like price drop,
-// reviews, etc.
-BASE_FEATURE(kShopCard, base::FEATURE_DISABLED_BY_DEFAULT);
+// Shopping variations to Tab resumption.
+BASE_FEATURE(kTabResumptionShopCard, base::FEATURE_DISABLED_BY_DEFAULT);
 
 // Impression limits on ShopCards
 BASE_FEATURE(kShopCardImpressionLimits, base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/commerce/core/commerce_feature_list.h b/components/commerce/core/commerce_feature_list.h
index 0ca30f6..bd190dc4 100644
--- a/components/commerce/core/commerce_feature_list.h
+++ b/components/commerce/core/commerce_feature_list.h
@@ -39,7 +39,7 @@
 extern const char kPriceInsightsUseCacheParam[];
 extern const base::FeatureParam<bool> kPriceInsightsUseCache;
 BASE_DECLARE_FEATURE(kPriceTrackingPromo);
-BASE_DECLARE_FEATURE(kShopCard);
+BASE_DECLARE_FEATURE(kTabResumptionShopCard);
 BASE_DECLARE_FEATURE(kShopCardImpressionLimits);
 
 std::string ShopCardExperiment();
@@ -161,9 +161,9 @@
     ""};
 
 inline constexpr base::FeatureParam<std::string> kShopCardVariation{
-    &kShopCard, "ShopCardVariant", ""};
+    &kTabResumptionShopCard, "ShopCardVariant", ""};
 inline constexpr base::FeatureParam<std::string> kShopCardPosition{
-    &kShopCard, "ShopCardPosition", ""};
+    &kTabResumptionShopCard, "ShopCardPosition", ""};
 
 extern const char kShopCardArm1[];
 extern const char kShopCardArm2[];
diff --git a/components/device_signals/core/common/signals_features.cc b/components/device_signals/core/common/signals_features.cc
index 44c8c96..95e6b866 100644
--- a/components/device_signals/core/common/signals_features.cc
+++ b/components/device_signals/core/common/signals_features.cc
@@ -26,6 +26,11 @@
 // Reports.
 BASE_FEATURE(kBrowserSignalsReportingEnabled,
              base::FEATURE_DISABLED_BY_DEFAULT);
+
+// Enables the improvements made during system signals collection in Chrome.
+BASE_FEATURE(kSystemSignalCollectionImprovementEnabled,
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Controls whether a signals-only profile report will be triggered when a valid
 // cookie change is observed.
 constexpr base::FeatureParam<bool> kTriggerOnCookieChange{
@@ -50,6 +55,11 @@
   return base::FeatureList::IsEnabled(kDetectedAgentSignalCollectionEnabled);
 }
 
+bool IsSystemSignalCollectionImprovementEnabled() {
+  return base::FeatureList::IsEnabled(
+      kSystemSignalCollectionImprovementEnabled);
+}
+
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || \
     BUILDFLAG(IS_CHROMEOS)
 // Enables the triggering of device signals consent dialog when conditions met
diff --git a/components/device_signals/core/common/signals_features.h b/components/device_signals/core/common/signals_features.h
index d966b3eb..7c119f8 100644
--- a/components/device_signals/core/common/signals_features.h
+++ b/components/device_signals/core/common/signals_features.h
@@ -16,6 +16,7 @@
 BASE_DECLARE_FEATURE(kProfileSignalsReportingEnabled);
 BASE_DECLARE_FEATURE(kBrowserSignalsReportingEnabled);
 BASE_DECLARE_FEATURE(kDetectedAgentSignalCollectionEnabled);
+BASE_DECLARE_FEATURE(kSystemSignalCollectionImprovementEnabled);
 
 // Signals reporting related feature parameters.
 extern const base::FeatureParam<bool> kTriggerOnCookieChange;
@@ -31,6 +32,9 @@
 // Returns true if detected agent signal collection has been
 // enabled.
 bool IsDetectedAgentSignalCollectionEnabled();
+// Returns true if system signal collection improvement feature has been
+// enabled.
+bool IsSystemSignalCollectionImprovementEnabled();
 
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || \
     BUILDFLAG(IS_CHROMEOS)
diff --git a/components/dom_distiller/core/javascript/dom_distiller_viewer.js b/components/dom_distiller/core/javascript/dom_distiller_viewer.js
index 6ebf821..f3fd4db 100644
--- a/components/dom_distiller/core/javascript/dom_distiller_viewer.js
+++ b/components/dom_distiller/core/javascript/dom_distiller_viewer.js
@@ -42,32 +42,24 @@
 /**
  * A utility class for classifying images in distilled content.
  *
- * This class uses a multi-stage heuristic to determine whether an image should
- * be displayed as a small inline element (e.g., an icon, symbol, or inline
- * formula) or as a full-width block element (e.g., a feature image). The
- * classification is density-aware to ensure consistent behavior across
- * different screen resolutions.
+ * Uses a prioritized cascade of heuristics to classify an image as either
+ * inline (e.g., icon) or full-width (e.g., feature image). The checks are:
+ * 1. Rendered size vs. viewport size (for visually dominant images).
+ * 2. Intrinsic size and metadata (for small or decorative images).
+ * 3. Structural context (e.g., inside a <figure>).
+ * 4. A final fallback based on intrinsic width.
  *
- * The primary entry point is the static method `processImagesIn()`, which finds
- * all images within a given DOM element and applies the appropriate CSS class
- * (`distilled-inline-img` or `distilled-full-width-img`).
+ * All checks use density-independent units (CSS pixels).
  */
 class ImageClassifier {
   static INLINE_CLASS = 'distilled-inline-img';
   static FULL_WIDTH_CLASS = 'distilled-full-width-img';
+  static DOMINANT_IMAGE_MIN_VIEWPORT_RATIO = 0.8;
 
   constructor() {
-    const density = window.devicePixelRatio || 1;
-
-    // Baseline thresholds in density-independent units (dp).
-    const SMALL_AREA_UPPER_BOUND_DP = 64 * 64;
-    const INLINE_WIDTH_FALLBACK_UPPER_BOUND_DP = 300;
-
-    // Calculate density-aware thresholds in pixels (px) once.
-    this.smallAreaUpperBoundPx =
-        SMALL_AREA_UPPER_BOUND_DP * (density * density);
-    this.inlineWidthFallbackUpperBoundPx =
-        INLINE_WIDTH_FALLBACK_UPPER_BOUND_DP * density;
+    // Baseline thresholds in density-independent units (CSS pixels).
+    this.smallAreaUpperBoundDp = 64 * 64;
+    this.inlineWidthFallbackUpperBoundDp = 300;
 
     // Matches common keywords for icons or mathematical formulas.
     const mathyKeywords =
@@ -83,15 +75,16 @@
   }
 
   /**
-   * Checks for strong signals that the image is INLINE.
+   * Checks for strong signals that the image is INLINE based on its intrinsic
+   * properties.
    * @param {HTMLImageElement} img The image element to check.
    * @return {boolean} True if the image should be inline.
    * @private
    */
   _isDefinitelyInline(img) {
-    // Accept small images, but skip unloaded or broken ones (area == 0).
-    const area = img.width * img.height;
-    if (area > 0 && area < this.smallAreaUpperBoundPx) {
+    // Use natural dimensions (in CSS pixels) to check for small area.
+    const area = img.naturalWidth * img.naturalHeight;
+    if (area > 0 && area < this.smallAreaUpperBoundDp) {
       return true;
     }
 
@@ -161,23 +154,34 @@
   }
 
   /**
-   * Classifies the image based on a simple width fallback.
+   * Classifies the image based on a simple intrinsic width fallback.
    * @param {HTMLImageElement} img The image element to check.
    * @return {string} The CSS class to apply.
    * @private
    */
   _classifyByFallback(img) {
-    return img.width > this.inlineWidthFallbackUpperBoundPx ?
+    // Use naturalWidth (in CSS pixels) and compare against the dp threshold.
+    return img.naturalWidth > this.inlineWidthFallbackUpperBoundDp ?
         ImageClassifier.FULL_WIDTH_CLASS :
         ImageClassifier.INLINE_CLASS;
   }
 
   /**
-   * Determines if an image should be displayed inline or as a full-width block.
+   * Determines an image's display style using a prioritized cascade of checks.
    * @param {HTMLImageElement} img The image element to classify.
    * @return {string} The CSS class to apply.
    */
   classify(img) {
+    // Check for visually dominant images first, as this is the most reliable
+    // signal and overrides all other heuristics.
+    const renderedWidth = img.getBoundingClientRect().width;
+    if (renderedWidth > 0 && window.innerWidth > 0 &&
+        (renderedWidth / window.innerWidth) >
+            ImageClassifier.DOMINANT_IMAGE_MIN_VIEWPORT_RATIO) {
+      return ImageClassifier.FULL_WIDTH_CLASS;
+    }
+
+    // Fall back to checks based on intrinsic properties and structure.
     if (this._isDefinitelyInline(img)) {
       return ImageClassifier.INLINE_CLASS;
     }
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal
index 121111e..20c4cc3 160000
--- a/components/optimization_guide/internal
+++ b/components/optimization_guide/internal
@@ -1 +1 @@
-Subproject commit 121111e1da731354279a3a26eba358d38f4a34f9
+Subproject commit 20c4cc39d64f47cd19ec46b550ec6cbbf0951ed7
diff --git a/components/os_crypt/async/browser/BUILD.gn b/components/os_crypt/async/browser/BUILD.gn
index e7b19d7..45836a6 100644
--- a/components/os_crypt/async/browser/BUILD.gn
+++ b/components/os_crypt/async/browser/BUILD.gn
@@ -42,6 +42,23 @@
   ]
 }
 
+if (is_apple) {
+  source_set("keychain_key_provider") {
+    sources = [
+      "keychain_key_provider.h",
+      "keychain_key_provider.mm",
+    ]
+    deps = [
+      ":key_provider_interface",
+      "//base",
+      "//components/os_crypt/async/common",
+      "//components/os_crypt/sync",
+      "//crypto",
+      "//crypto:mock_apple_keychain",
+    ]
+  }
+}
+
 if (is_win) {
   source_set("dpapi_key_provider") {
     sources = [
@@ -136,6 +153,19 @@
     "//testing/gtest",
   ]
 
+  if (is_apple) {
+    sources += [
+      "keychain_key_provider_compat_unittest.mm",
+      "keychain_key_provider_unittest.mm",
+    ]
+    deps += [
+      ":keychain_key_provider",
+      "//components/os_crypt/sync:test_support",
+      "//components/os_crypt/sync:unit_tests",
+      "//crypto:mock_apple_keychain",
+    ]
+  }
+
   if (is_win) {
     sources += [ "dpapi_key_provider_unittest.cc" ]
     deps += [
diff --git a/components/os_crypt/async/browser/DEPS b/components/os_crypt/async/browser/DEPS
index 7e796c80..207f67c 100644
--- a/components/os_crypt/async/browser/DEPS
+++ b/components/os_crypt/async/browser/DEPS
@@ -6,7 +6,11 @@
 ]
 
 specific_include_rules = {
-  ".*_unittest\.cc": [
+  ".*_unittest\.*": [
     "+components/os_crypt/sync",
   ],
+  "keychain_key_provider.mm": [
+    "+components/os_crypt/sync/keychain_password_mac.h",
+    "+components/os_crypt/sync/os_crypt_switches.h",
+  ],
 }
diff --git a/components/os_crypt/async/browser/keychain_key_provider.h b/components/os_crypt/async/browser/keychain_key_provider.h
new file mode 100644
index 0000000..15fbe74
--- /dev/null
+++ b/components/os_crypt/async/browser/keychain_key_provider.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 COMPONENTS_OS_CRYPT_ASYNC_BROWSER_KEYCHAIN_KEY_PROVIDER_H_
+#define COMPONENTS_OS_CRYPT_ASYNC_BROWSER_KEYCHAIN_KEY_PROVIDER_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/raw_ptr.h"
+#include "base/types/expected.h"
+#include "components/os_crypt/async/browser/key_provider.h"
+
+namespace crypto::apple {
+class Keychain;
+}
+
+namespace os_crypt_async {
+
+// Provides an encryption key derived from a password stored in the macOS/iOS
+// Keychain. This is compatible with the synchronous OSCrypt implementation.
+class COMPONENT_EXPORT(OS_CRYPT_ASYNC) KeychainKeyProvider
+    : public KeyProvider {
+ public:
+  KeychainKeyProvider();
+  KeychainKeyProvider(const KeychainKeyProvider&) = delete;
+  KeychainKeyProvider& operator=(const KeychainKeyProvider&) = delete;
+  ~KeychainKeyProvider() override;
+
+ private:
+  friend class KeychainKeyProviderCompatTest;
+  FRIEND_TEST_ALL_PREFIXES(KeychainKeyProviderTest, GetKey_Success);
+  FRIEND_TEST_ALL_PREFIXES(KeychainKeyProviderTest, GetKey_NotFound);
+  FRIEND_TEST_ALL_PREFIXES(KeychainKeyProviderTest, GetKey_Failure_AuthFailed);
+  FRIEND_TEST_ALL_PREFIXES(KeychainKeyProviderTest, GetKey_Failure_OtherError);
+
+  // For testing.
+  explicit KeychainKeyProvider(crypto::apple::Keychain* keychain);
+
+  // os_crypt_async::KeyProvider interface.
+  void GetKey(KeyCallback callback) override;
+  bool UseForEncryption() override;
+  bool IsCompatibleWithOsCryptSync() override;
+
+  raw_ptr<crypto::apple::Keychain> keychain_for_testing_ = nullptr;
+};
+
+}  // namespace os_crypt_async
+
+#endif  // COMPONENTS_OS_CRYPT_ASYNC_BROWSER_KEYCHAIN_KEY_PROVIDER_H_
diff --git a/components/os_crypt/async/browser/keychain_key_provider.mm b/components/os_crypt/async/browser/keychain_key_provider.mm
new file mode 100644
index 0000000..4d6898b
--- /dev/null
+++ b/components/os_crypt/async/browser/keychain_key_provider.mm
@@ -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 "components/os_crypt/async/browser/keychain_key_provider.h"
+
+#include <array>
+#include <memory>
+
+#include "base/apple/osstatus_logging.h"
+#include "base/command_line.h"
+#include "base/functional/bind.h"
+#include "base/task/thread_pool.h"
+#include "base/types/expected.h"
+#include "components/os_crypt/async/common/algorithm.mojom.h"
+#include "components/os_crypt/sync/keychain_password_mac.h"
+#include "components/os_crypt/sync/os_crypt_switches.h"
+#include "crypto/apple/keychain.h"
+#include "crypto/apple/mock_keychain.h"
+#include "crypto/kdf.h"
+#include "crypto/subtle_passkey.h"
+
+namespace os_crypt_async {
+
+namespace {
+
+// These constants are duplicated from the sync backend os_crypt_mac.mm.
+constexpr char kKeyTag[] = "v10";
+constexpr size_t kDerivedKeySize = 16;
+constexpr auto kSalt =
+    std::to_array<uint8_t>({'s', 'a', 'l', 't', 'y', 's', 'a', 'l', 't'});
+constexpr size_t kIterations = 1003;
+
+// This function runs on a worker thread and performs blocking Keychain IO.
+base::expected<Encryptor::Key, KeyProvider::KeyError> GetKeyTask(
+    crypto::SubtlePassKey subtle_passkey,
+    crypto::apple::Keychain* keychain_for_testing) {
+  std::unique_ptr<crypto::apple::Keychain> default_keychain;
+  if (!keychain_for_testing) {
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+            os_crypt::switches::kUseMockKeychain)) {
+      default_keychain = std::make_unique<crypto::apple::MockKeychain>();
+    } else {
+      default_keychain = crypto::apple::Keychain::DefaultKeychain();
+    }
+  }
+
+  KeychainPassword keychain_password(
+      keychain_for_testing ? *keychain_for_testing : *default_keychain);
+  std::string password = keychain_password.GetPassword();
+
+  // `password` can be an empty string if keychain access is denied by the user
+  // or some other error occurs.
+  if (password.empty()) {
+    return base::unexpected(KeyProvider::KeyError::kTemporarilyUnavailable);
+  }
+
+  std::array<uint8_t, kDerivedKeySize> key_bytes;
+  crypto::kdf::DeriveKeyPbkdf2HmacSha1({.iterations = kIterations},
+                                       base::as_byte_span(password), kSalt,
+                                       key_bytes, subtle_passkey);
+
+  return Encryptor::Key(key_bytes, mojom::Algorithm::kAES128CBC);
+}
+
+}  // namespace
+
+KeychainKeyProvider::KeychainKeyProvider() = default;
+
+KeychainKeyProvider::KeychainKeyProvider(
+    crypto::apple::Keychain* keychain_for_testing)
+    : keychain_for_testing_(keychain_for_testing) {}
+
+KeychainKeyProvider::~KeychainKeyProvider() = default;
+
+void KeychainKeyProvider::GetKey(KeyCallback callback) {
+  // Apple's documentation [1] recommends accessing the keychain on a worker
+  // thread. [1]
+  // https://developer.apple.com/documentation/security/secitemcopymatching%28_%3A_%3A%29#Performance-considerations
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::TaskPriority::USER_BLOCKING, base::MayBlock()},
+      base::BindOnce(&GetKeyTask, crypto::SubtlePassKey{},
+                     keychain_for_testing_),
+      base::BindOnce(std::move(callback), kKeyTag));
+}
+
+bool KeychainKeyProvider::UseForEncryption() {
+  return true;
+}
+
+bool KeychainKeyProvider::IsCompatibleWithOsCryptSync() {
+  return true;
+}
+
+}  // namespace os_crypt_async
diff --git a/components/os_crypt/async/browser/keychain_key_provider_compat_unittest.mm b/components/os_crypt/async/browser/keychain_key_provider_compat_unittest.mm
new file mode 100644
index 0000000..c9cec53
--- /dev/null
+++ b/components/os_crypt/async/browser/keychain_key_provider_compat_unittest.mm
@@ -0,0 +1,82 @@
+// 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 <utility>
+#include <vector>
+
+#include "base/memory/ptr_util.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_future.h"
+#include "components/os_crypt/async/browser/keychain_key_provider.h"
+#include "components/os_crypt/async/browser/os_crypt_async.h"
+#include "components/os_crypt/async/common/encryptor.h"
+#include "components/os_crypt/sync/os_crypt.h"
+#include "components/os_crypt/sync/os_crypt_mocker.h"
+#include "crypto/apple/mock_keychain.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace os_crypt_async {
+
+class KeychainKeyProviderCompatTest : public ::testing::Test {
+ protected:
+  void SetUp() override { OSCryptMocker::SetUp(); }
+
+  void TearDown() override { OSCryptMocker::TearDown(); }
+
+  Encryptor GetEncryptor(crypto::apple::Keychain* keychain) {
+    std::vector<
+        std::pair<OSCryptAsync::Precedence, std::unique_ptr<KeyProvider>>>
+        providers;
+    providers.emplace_back(std::make_pair(
+        /*precedence=*/10u,
+        base::WrapUnique(new KeychainKeyProvider(keychain))));
+    OSCryptAsync factory(std::move(providers));
+
+    base::test::TestFuture<Encryptor> future;
+    factory.GetInstance(future.GetCallback());
+    return future.Take();
+  }
+
+  base::test::TaskEnvironment task_environment_{
+      base::test::TaskEnvironment::MainThreadType::UI,
+      base::test::TaskEnvironment::ThreadPoolExecutionMode::ASYNC};
+};
+
+TEST_F(KeychainKeyProviderCompatTest, EncryptOldDecryptNew) {
+  crypto::apple::MockKeychain mock_keychain;
+  mock_keychain.set_find_generic_result(noErr);
+
+  // 1. Encrypt with old sync backend.
+  const std::string plaintext = "secrets";
+  std::string ciphertext;
+  ASSERT_TRUE(OSCrypt::EncryptString(plaintext, &ciphertext));
+
+  // 2. Get an encryptor from the new async interface.
+  Encryptor encryptor = GetEncryptor(&mock_keychain);
+
+  // 3. Decrypt with the new async interface.
+  std::string decrypted;
+  EXPECT_TRUE(encryptor.DecryptString(ciphertext, &decrypted));
+  EXPECT_EQ(plaintext, decrypted);
+}
+
+TEST_F(KeychainKeyProviderCompatTest, EncryptNewDecryptOld) {
+  crypto::apple::MockKeychain mock_keychain;
+  mock_keychain.set_find_generic_result(noErr);
+
+  // 1. Get an encryptor from the new async interface.
+  Encryptor encryptor = GetEncryptor(&mock_keychain);
+
+  // 2. Encrypt with the new async interface.
+  const std::string plaintext = "secrets";
+  std::string ciphertext;
+  ASSERT_TRUE(encryptor.EncryptString(plaintext, &ciphertext));
+
+  // 3. Decrypt with old sync backend.
+  std::string decrypted;
+  EXPECT_TRUE(OSCrypt::DecryptString(ciphertext, &decrypted));
+  EXPECT_EQ(plaintext, decrypted);
+}
+
+}  // namespace os_crypt_async
diff --git a/components/os_crypt/async/browser/keychain_key_provider_unittest.mm b/components/os_crypt/async/browser/keychain_key_provider_unittest.mm
new file mode 100644
index 0000000..da9e75f
--- /dev/null
+++ b/components/os_crypt/async/browser/keychain_key_provider_unittest.mm
@@ -0,0 +1,97 @@
+// 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/os_crypt/async/browser/keychain_key_provider.h"
+
+#include <vector>
+
+#include "base/test/task_environment.h"
+#include "base/test/test_future.h"
+#include "components/os_crypt/async/common/encryptor.h"
+#include "crypto/apple/mock_keychain.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace os_crypt_async {
+
+class KeychainKeyProviderTest : public ::testing::Test {
+ protected:
+  base::test::TaskEnvironment task_environment_{
+      base::test::TaskEnvironment::MainThreadType::UI,
+      base::test::TaskEnvironment::ThreadPoolExecutionMode::ASYNC};
+};
+
+TEST_F(KeychainKeyProviderTest, GetKey_Success) {
+  crypto::apple::MockKeychain mock_keychain;
+  mock_keychain.set_find_generic_result(noErr);
+
+  KeychainKeyProvider provider(&mock_keychain);
+  base::test::TestFuture<const std::string&,
+                         base::expected<Encryptor::Key, KeyProvider::KeyError>>
+      future;
+  provider.GetKey(future.GetCallback());
+
+  auto& [tag, key_result] = future.Get();
+  EXPECT_EQ(tag, "v10");
+  ASSERT_TRUE(key_result.has_value());
+  EXPECT_FALSE(mock_keychain.called_add_generic());
+
+  // Known answer test for key derivation.
+  // This value is from PBKDF2-HMAC-SHA1("mock_password", "saltysalt", 1003).
+  const std::vector<uint8_t> expected_key = {0xAF, 0x0F, 0x76, 0x2A, 0xAF, 0x6D,
+                                             0x7D, 0x11, 0x58, 0x1B, 0x7A, 0xA8,
+                                             0xCE, 0x72, 0x18, 0xDE};
+  EXPECT_EQ(key_result.value().key_, expected_key);
+}
+
+TEST_F(KeychainKeyProviderTest, GetKey_NotFound) {
+  crypto::apple::MockKeychain mock_keychain;
+  mock_keychain.set_find_generic_result(errSecItemNotFound);
+
+  KeychainKeyProvider provider(&mock_keychain);
+  base::test::TestFuture<const std::string&,
+                         base::expected<Encryptor::Key, KeyProvider::KeyError>>
+      future;
+  provider.GetKey(future.GetCallback());
+
+  auto& [tag, key_result] = future.Get();
+  EXPECT_EQ(tag, "v10");
+  ASSERT_TRUE(key_result.has_value());
+  EXPECT_TRUE(mock_keychain.called_add_generic());
+}
+
+TEST_F(KeychainKeyProviderTest, GetKey_Failure_AuthFailed) {
+  crypto::apple::MockKeychain mock_keychain;
+  mock_keychain.set_find_generic_result(errSecAuthFailed);
+
+  KeychainKeyProvider provider(&mock_keychain);
+  base::test::TestFuture<const std::string&,
+                         base::expected<Encryptor::Key, KeyProvider::KeyError>>
+      future;
+  provider.GetKey(future.GetCallback());
+
+  auto& [tag, key_result] = future.Get();
+  EXPECT_EQ(tag, "v10");
+  ASSERT_FALSE(key_result.has_value());
+  EXPECT_EQ(key_result.error(), KeyProvider::KeyError::kTemporarilyUnavailable);
+  EXPECT_FALSE(mock_keychain.called_add_generic());
+}
+
+TEST_F(KeychainKeyProviderTest, GetKey_Failure_OtherError) {
+  crypto::apple::MockKeychain mock_keychain;
+  mock_keychain.set_find_generic_result(errSecNotAvailable);
+
+  KeychainKeyProvider provider(&mock_keychain);
+  base::test::TestFuture<const std::string&,
+                         base::expected<Encryptor::Key, KeyProvider::KeyError>>
+      future;
+  provider.GetKey(future.GetCallback());
+
+  auto& [tag, key_result] = future.Get();
+  EXPECT_EQ(tag, "v10");
+  ASSERT_FALSE(key_result.has_value());
+  EXPECT_EQ(key_result.error(), KeyProvider::KeyError::kTemporarilyUnavailable);
+  EXPECT_FALSE(mock_keychain.called_add_generic());
+}
+
+}  // namespace os_crypt_async
diff --git a/components/os_crypt/async/common/encryptor.h b/components/os_crypt/async/common/encryptor.h
index 968f5b2..ceae1492 100644
--- a/components/os_crypt/async/common/encryptor.h
+++ b/components/os_crypt/async/common/encryptor.h
@@ -70,6 +70,7 @@
                                      os_crypt_async::Encryptor::Key>;
     FRIEND_TEST_ALL_PREFIXES(EncryptorTestWithOSCrypt, MultipleKeys);
     FRIEND_TEST_ALL_PREFIXES(EncryptorTraitsTest, TraitsRoundTrip);
+    FRIEND_TEST_ALL_PREFIXES(KeychainKeyProviderTest, GetKey_Success);
 
     Key(base::span<const uint8_t> key,
         const mojom::Algorithm& algo,
diff --git a/components/os_crypt/sync/BUILD.gn b/components/os_crypt/sync/BUILD.gn
index bbaf114..45d8e77 100644
--- a/components/os_crypt/sync/BUILD.gn
+++ b/components/os_crypt/sync/BUILD.gn
@@ -20,6 +20,7 @@
     "//components/gcm_driver",
     "//components/os_crypt/async/browser:dpapi_key_provider",
     "//components/os_crypt/async/browser:freedesktop_secret_key_provider",
+    "//components/os_crypt/async/browser:keychain_key_provider",
     "//components/os_crypt/async/browser:secret_portal_key_provider",
     "//components/os_crypt/async/browser:unit_tests",
     "//components/os_crypt/async/common",
diff --git a/components/persistent_cache/persistent_cache_unittest.cc b/components/persistent_cache/persistent_cache_unittest.cc
index 44809ab..9eb76fe 100644
--- a/components/persistent_cache/persistent_cache_unittest.cc
+++ b/components/persistent_cache/persistent_cache_unittest.cc
@@ -10,7 +10,12 @@
 #include "base/containers/span.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "base/test/bind.h"
 #include "base/test/gmock_expected_support.h"
+#include "base/test/task_environment.h"
 #include "components/persistent_cache/backend_params.h"
 #include "components/persistent_cache/mock/mock_backend_impl.h"
 #include "components/persistent_cache/sqlite/sqlite_backend_impl.h"
@@ -335,6 +340,33 @@
   }
 }
 
+TEST_P(PersistentCacheTest, ThreadSafeAccess) {
+  base::test::TaskEnvironment env;
+
+  BackendParams backend_params =
+      params_provider_.CreateBackendFilesAndBuildParams(GetParam());
+
+  // Create the cache and insert on this sequence.
+  auto value = base::byte_span_from_cstring("1");
+  auto cache = OpenCache(backend_params.Copy());
+  cache->Insert(kKey, value);
+
+  // Find() on ThreadPool. Result should be expected and there are no sequence
+  // checkers tripped.
+  base::WaitableEvent event;
+  std::unique_ptr<Entry> entry;
+  base::ThreadPool::PostTask(FROM_HERE, {base::MayBlock()},
+                             base::BindLambdaForTesting([&]() {
+                               entry = cache->Find(kKey);
+                               event.Signal();
+                             }));
+
+  // Wait for result availability and check.
+  event.Wait();
+  ASSERT_NE(entry, nullptr);
+  EXPECT_EQ(entry->GetContentSpan(), value);
+}
+
 INSTANTIATE_TEST_SUITE_P(All,
                          PersistentCacheTest,
                          testing::Values(BackendType::kSqlite));
diff --git a/components/persistent_cache/sqlite/sqlite_backend_impl.cc b/components/persistent_cache/sqlite/sqlite_backend_impl.cc
index e9b3079cf..1370b4c 100644
--- a/components/persistent_cache/sqlite/sqlite_backend_impl.cc
+++ b/components/persistent_cache/sqlite/sqlite_backend_impl.cc
@@ -22,7 +22,7 @@
 
 namespace {
 
-constexpr const char kSqliteHistogramTag[] = "PersistentCache";
+constexpr char kTag[] = "PersistentCache";
 
 }  // namespace
 
@@ -63,35 +63,44 @@
       unregister_runner_(
           SqliteSandboxedVfsDelegate::GetInstance()->RegisterSandboxedFiles(
               vfs_file_set_)),
-      db_(sql::DatabaseOptions()
+      db_(std::in_place,
+          sql::DatabaseOptions()
               .set_exclusive_locking(false)
               .set_vfs_name_discouraged(
                   SqliteSandboxedVfsDelegate::kSqliteVfsName)
               // Prevent SQLite from trying to use mmap, as SandboxedVfs does
               // not currently support this.
               .set_mmap_enabled(false),
-          kSqliteHistogramTag) {}
+          sql::Database::Tag(kTag)) {}
 
-SqliteBackendImpl::~SqliteBackendImpl() = default;
+SqliteBackendImpl::~SqliteBackendImpl() {
+  base::AutoLock lock(lock_, base::subtle::LockTracking::kEnabled);
+  db_.reset();
+}
 
 bool SqliteBackendImpl::Initialize() {
   CHECK(!initialized_);
   TRACE_EVENT0("persistent_cache", "initialize");
 
-  if (!db_.Open(database_path_)) {
+  // Open  `db_` under `lock_` with lock tracking enabled. This allows this
+  // class to be usable from multiple threads even though `sql::Database` is
+  // sequence bound.
+  base::AutoLock lock(lock_, base::subtle::LockTracking::kEnabled);
+
+  if (!db_->Open(database_path_)) {
     TRACE_EVENT_INSTANT1("persistent_cache", "open_failed",
                          TRACE_EVENT_SCOPE_THREAD, "error_code",
-                         db_.GetErrorCode());
+                         db_->GetErrorCode());
     return false;
   }
 
-  if (!db_.Execute(
+  if (!db_->Execute(
           "CREATE TABLE IF NOT EXISTS entries(key TEXT PRIMARY KEY UNIQUE NOT "
           "NULL, content BLOB NOT NULL, input_signature INTEGER, "
           "write_timestamp INTEGER)")) {
     TRACE_EVENT_INSTANT1("persistent_cache", "create_failed",
                          TRACE_EVENT_SCOPE_THREAD, "error_code",
-                         db_.GetErrorCode());
+                         db_->GetErrorCode());
     return false;
   }
 
@@ -100,19 +109,21 @@
 }
 
 std::unique_ptr<Entry> SqliteBackendImpl::Find(std::string_view key) {
+  base::AutoLock lock(lock_, base::subtle::LockTracking::kEnabled);
+
   CHECK(initialized_);
   CHECK_GT(key.length(), 0ull);
   TRACE_EVENT0("persistent_cache", "Find");
 
-  sql::Statement stm = sql::Statement(
-      db_.GetCachedStatement(SQL_FROM_HERE,
-                             "SELECT content, input_signature, write_timestamp "
-                             "FROM entries WHERE key = ?"));
+  sql::Statement stm = sql::Statement(db_->GetCachedStatement(
+      SQL_FROM_HERE,
+      "SELECT content, input_signature, write_timestamp "
+      "FROM entries WHERE key = ?"));
   stm.BindString(0, key);
 
   DCHECK(stm.is_valid());
   if (!stm.Step()) {
-    const int error_code = db_.GetErrorCode();
+    const int error_code = db_->GetErrorCode();
     // If the last error code is SQLITE_DONE then `Step()` failed because the
     // row was not found which is not a reportable error.
     if (error_code != SQLITE_DONE) {
@@ -132,6 +143,8 @@
 void SqliteBackendImpl::Insert(std::string_view key,
                                base::span<const uint8_t> content,
                                EntryMetadata metadata) {
+  base::AutoLock lock(lock_, base::subtle::LockTracking::kEnabled);
+
   CHECK(initialized_);
   CHECK_GT(key.length(), 0ull);
   TRACE_EVENT0("persistent_cache", "insert");
@@ -140,7 +153,7 @@
       << "Write timestamp is generated by SQLite so it should not be specified "
          "manually";
 
-  sql::Statement stm(db_.GetCachedStatement(
+  sql::Statement stm(db_->GetCachedStatement(
       SQL_FROM_HERE,
       "REPLACE INTO entries (key, content, input_signature, write_timestamp) "
       "VALUES (?, ?, ?, strftime(\'%s\', \'now\'))"));
@@ -153,7 +166,7 @@
   if (!stm.Run()) {
     TRACE_EVENT_INSTANT1("persistent_cache", "insert_failed",
                          TRACE_EVENT_SCOPE_THREAD, "error_code",
-                         db_.GetErrorCode());
+                         db_->GetErrorCode());
   }
 }
 
diff --git a/components/persistent_cache/sqlite/sqlite_backend_impl.h b/components/persistent_cache/sqlite/sqlite_backend_impl.h
index 4b2b8d5..a03e503 100644
--- a/components/persistent_cache/sqlite/sqlite_backend_impl.h
+++ b/components/persistent_cache/sqlite/sqlite_backend_impl.h
@@ -10,6 +10,8 @@
 
 #include "base/component_export.h"
 #include "base/files/file_path.h"
+#include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
 #include "base/types/pass_key.h"
 #include "components/persistent_cache/backend.h"
 #include "components/persistent_cache/backend_params.h"
@@ -48,11 +50,11 @@
 
   std::optional<BackendParams> ExportParams(bool read_write);
 
-  base::FilePath database_path_;
+  const base::FilePath database_path_;
 
   // The set of of `SanboxedFiles` accessible by this backend. This class owns
   // the `SandboxedFiles`.
-  SqliteVfsFileSet vfs_file_set_;
+  const SqliteVfsFileSet vfs_file_set_;
 
   // Owns the registration / unregistration of the `SanboxedFiles` own by this
   // backend to the `SqliteSandboxedVfsDelegate`. Must be defined after
@@ -62,8 +64,10 @@
 
   // Defined after `unregister_runner_` to ensure that files remain available
   // through the VFS throughout the database's lifetime.
-  sql::Database db_;
+  std::optional<sql::Database> db_ GUARDED_BY(lock_);
   bool initialized_ = false;
+
+  base::Lock lock_;
 };
 
 }  // namespace persistent_cache
diff --git a/components/persistent_cache/sqlite/vfs/sqlite_database_vfs_file_set.cc b/components/persistent_cache/sqlite/vfs/sqlite_database_vfs_file_set.cc
index e950b6b..35431c4 100644
--- a/components/persistent_cache/sqlite/vfs/sqlite_database_vfs_file_set.cc
+++ b/components/persistent_cache/sqlite/vfs/sqlite_database_vfs_file_set.cc
@@ -46,7 +46,8 @@
       base::StrCat({virtual_fs_path_, kPathSeperator, kDbFileName}));
 }
 
-std::array<base::File, 2> SqliteVfsFileSet::DuplicateFiles(bool read_write) {
+std::array<base::File, 2> SqliteVfsFileSet::DuplicateFiles(
+    bool read_write) const {
   // Can't upgrade from read-only to read-write.
   CHECK(!read_write || !read_only_);
   const auto access_rights = read_write
@@ -56,7 +57,7 @@
           journal_file_->DuplicateFile(access_rights)};
 }
 
-base::UnsafeSharedMemoryRegion SqliteVfsFileSet::DuplicateLock() {
+base::UnsafeSharedMemoryRegion SqliteVfsFileSet::DuplicateLock() const {
   return shared_lock_.Duplicate();
 }
 
diff --git a/components/persistent_cache/sqlite/vfs/sqlite_database_vfs_file_set.h b/components/persistent_cache/sqlite/vfs/sqlite_database_vfs_file_set.h
index ffaab37ad..147cc82 100644
--- a/components/persistent_cache/sqlite/vfs/sqlite_database_vfs_file_set.h
+++ b/components/persistent_cache/sqlite/vfs/sqlite_database_vfs_file_set.h
@@ -43,11 +43,11 @@
 
   // Returns handles to the files in the set with either read-write or read-only
   // access. Either may be an invalid file in case of error.
-  std::array<base::File, 2> DuplicateFiles(bool read_write);
+  std::array<base::File, 2> DuplicateFiles(bool read_write) const;
 
   // Returns a handle to the shared memory region holding the database's shared
   // lock.
-  base::UnsafeSharedMemoryRegion DuplicateLock();
+  base::UnsafeSharedMemoryRegion DuplicateLock() const;
 
  private:
   base::FilePath GetJournalVirtualFilePath() const;
diff --git a/components/previous_session_info/previous_session_info.mm b/components/previous_session_info/previous_session_info.mm
index e472e0f..bff2c4d1 100644
--- a/components/previous_session_info/previous_session_info.mm
+++ b/components/previous_session_info/previous_session_info.mm
@@ -257,7 +257,7 @@
         lastSystemStartTime;
 
     NSString* lastRanLanguage = [defaults stringForKey:kLastRanLanguage];
-    NSString* currentLanguage = [[NSLocale preferredLanguages] objectAtIndex:0];
+    NSString* currentLanguage = [[NSLocale preferredLanguages] firstObject];
     gSharedInstance.isFirstSessionAfterLanguageChange =
         ![lastRanLanguage isEqualToString:currentLanguage];
 
@@ -323,8 +323,8 @@
   [defaults setObject:currentOSVersion forKey:kPreviousSessionInfoOSVersion];
 
   // Set the current language.
-  NSString* currentLanguage = [[NSLocale preferredLanguages] objectAtIndex:0];
-  [defaults setObject:currentLanguage forKey:kLastRanLanguage];
+  NSString* currentLanguage = [[NSLocale preferredLanguages] firstObject];
+  [defaults setObject:(currentLanguage ?: @"") forKey:kLastRanLanguage];
 
   // Clear the memory warning flag.
   [defaults
diff --git a/components/services/storage/service_worker/service_worker_storage_control_impl_unittest.cc b/components/services/storage/service_worker/service_worker_storage_control_impl_unittest.cc
index 30ef4c4..792f16e 100644
--- a/components/services/storage/service_worker/service_worker_storage_control_impl_unittest.cc
+++ b/components/services/storage/service_worker/service_worker_storage_control_impl_unittest.cc
@@ -628,6 +628,10 @@
     return return_value;
   }
 
+  void PerformStorageCleanup(base::OnceClosure callback) {
+    storage()->PerformStorageCleanup(std::move(callback));
+  }
+
   GetUsageForStorageKeyResult GetUsageForStorageKey(
       const blink::StorageKey& key) {
     GetUsageForStorageKeyResult result;
@@ -1778,6 +1782,43 @@
   }
 }
 
+TEST_F(ServiceWorkerStorageControlImplTest, PerformStorageCleanup) {
+  const GURL kScope("https://www.example.com/scope/");
+  const blink::StorageKey kKey =
+      blink::StorageKey::CreateFirstParty(url::Origin::Create(kScope));
+  const GURL kScriptUrl("https://www.example.com/scope/sw.js");
+  const GURL kClientUrl("https://www.example.com/scope/document.html");
+  const int64_t kScriptSize = 10;
+
+  LazyInitializeForTest();
+
+  const int64_t kResourceId = GetNewResourceId();
+  const int64_t kVersionId = GetNewVersionId().version_id;
+  const int64_t kRegistrationId = GetNewRegistrationId();
+
+  // Create and store a registration, and a resource.
+  DatabaseStatus status =
+      CreateAndStoreRegistration(kRegistrationId, kVersionId, kResourceId,
+                                  kScope, kKey, kScriptUrl, kScriptSize);
+  ASSERT_EQ(status, DatabaseStatus::kOk);
+
+  // Delete the registration. This should make the resource purgeable.
+  DeleteRegistrationResult delete_result =
+      DeleteRegistration(kRegistrationId, kKey);
+  ASSERT_EQ(delete_result.status, DatabaseStatus::kOk);
+
+  // Call PerformStorageCleanup. This is async.
+  base::RunLoop loop;
+  PerformStorageCleanup(loop.QuitClosure());
+  loop.Run();
+
+  // The resource should be purged.
+  ReadDataResult read_resource_result =
+      ReadResource(kResourceId, kScriptSize);
+  ASSERT_EQ(read_resource_result.status, net::ERR_CACHE_MISS);
+  ASSERT_EQ(read_resource_result.data, "");
+}
+
 // Tests that apply policy updates work.
 TEST_F(ServiceWorkerStorageControlImplTest, ApplyPolicyUpdates) {
   const GURL kScope1("https://foo.example.com/");
diff --git a/components/signin/public/base/signin_metrics.cc b/components/signin/public/base/signin_metrics.cc
index 8258f0f..9e035d1 100644
--- a/components/signin/public/base/signin_metrics.cc
+++ b/components/signin/public/base/signin_metrics.cc
@@ -191,6 +191,11 @@
   base::UmaHistogramEnumeration("Signin.SyncOptIn.Offered", access_point);
 }
 
+void LogHistorySyncOptInOffered(AccessPoint access_point) {
+  base::UmaHistogramEnumeration("Signin.HistorySyncOptIn.Offered",
+                                access_point);
+}
+
 void LogSyncSettingsOpened(AccessPoint access_point) {
   base::UmaHistogramEnumeration("Signin.SyncOptIn.OpenedSyncSettings",
                                 access_point);
diff --git a/components/signin/public/base/signin_metrics.h b/components/signin/public/base/signin_metrics.h
index cf9ee04..86ff656 100644
--- a/components/signin/public/base/signin_metrics.h
+++ b/components/signin/public/base/signin_metrics.h
@@ -690,6 +690,10 @@
 // and its associated access point.
 void LogSyncOptInOffered(AccessPoint access_point);
 
+// Logs a sync opt-in offered event (`Signin.HistorySyncOptIn.Offered`
+// histogram) and its associated access point.
+void LogHistorySyncOptInOffered(AccessPoint access_point);
+
 // Logs that the sync settings were opened at the end of the sync opt-in flow,
 // and the associated access points.
 void LogSyncSettingsOpened(AccessPoint access_point);
diff --git a/components/signin/public/base/signin_switches.cc b/components/signin/public/base/signin_switches.cc
index 64040d59..7d6f1aff0 100644
--- a/components/signin/public/base/signin_switches.cc
+++ b/components/signin/public/base/signin_switches.cc
@@ -92,6 +92,10 @@
              base::FEATURE_ENABLED_BY_DEFAULT);
 #endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
 
+#if BUILDFLAG(IS_IOS)
+BASE_FEATURE(kCacheIdentityListInChrome, base::FEATURE_DISABLED_BY_DEFAULT);
+#endif
+
 #if BUILDFLAG(IS_ANDROID)
 BASE_FEATURE(kCctSignInPrompt, base::FEATURE_ENABLED_BY_DEFAULT);
 #endif  // BUILDFLAG(IS_ANDROID)
diff --git a/components/signin/public/base/signin_switches.h b/components/signin/public/base/signin_switches.h
index 5904f1a..98b4fc19 100644
--- a/components/signin/public/base/signin_switches.h
+++ b/components/signin/public/base/signin_switches.h
@@ -72,6 +72,12 @@
 BASE_DECLARE_FEATURE(kBrowserSigninInSyncHeaderOnGaiaIntegration);
 #endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
 
+#if BUILDFLAG(IS_IOS)
+// Feature flag to enable caching identities in ios_internal.
+COMPONENT_EXPORT(SIGNIN_SWITCHES)
+BASE_DECLARE_FEATURE(kCacheIdentityListInChrome);
+#endif
+
 #if BUILDFLAG(IS_ANDROID)
 COMPONENT_EXPORT(SIGNIN_SWITCHES)
 BASE_DECLARE_FEATURE(kCctSignInPrompt);
diff --git a/components/test/data/dom_distiller/image_classifier_tester.js b/components/test/data/dom_distiller/image_classifier_tester.js
index 8178d6c..71294a89 100644
--- a/components/test/data/dom_distiller/image_classifier_tester.js
+++ b/components/test/data/dom_distiller/image_classifier_tester.js
@@ -10,49 +10,53 @@
 suite('ImageClassifier', function() {
   let testContainer;
 
-  // A solid red 1x1 pixel is used so that test images are visible, which
-  // aids in visual debugging of the test harness.
-  const RED_1X1_PIXEL = 'data:image/gif;base64,R0lGODlhAQABAIABAP8AAP///' +
-                        'yH5BAEAAAEALAAAAAABAAEAAAICRAEAOw==';
-
   /**
-   * Helper to create an image, append it to the container, and return a promise
-   * that resolves when the image is ready for classification.
+   * Helper to create an image with specific natural dimensions, append it to
+   * the container, and return a promise that resolves when the image is ready
+   * for classification.
    * @param {string} id A unique ID for the image.
-   * @param {number} widthDp The width of the image in DP.
-   * @param {number} heightDp The height of the image in DP.
+   * @param {number} naturalWidth The desired natural width of the image in CSS
+   *     pixels.
+   * @param {number} naturalHeight The desired natural height of the image in
+   *     CSS pixels.
    * @param {string} parentTag The tag of the parent element (e.g., 'p', 'div').
    * @param {string} parentContent The innerHTML of the parent element, with
    *     '<img>' as a placeholder for the image.
    * @param {Object} attributes An object of attributes to set on the image.
    * @return {Promise<HTMLImageElement>}
    */
-  function createImageTest(id, widthDp, heightDp, parentTag, parentContent,
-                           attributes = {}) {
+  function createImageTest(
+      id, naturalWidth, naturalHeight, parentTag, parentContent,
+      attributes = {}) {
     return new Promise((resolve) => {
-      const density = window.devicePixelRatio || 1;
       const parent = document.createElement(parentTag);
-      const img = document.createElement('img');
-      img.id = id;
-      // Scale the density-independent dimensions to CSS pixels.
-      img.width = widthDp * density;
-      img.height = heightDp * density;
+      // Create a placeholder for replacement.
+      parent.innerHTML = parentContent.replace('<img>', `<img id="${id}">`);
+      testContainer.appendChild(parent);
 
-      for (const [key, value] of Object.entries(attributes)) {
-        img.setAttribute(key, value);
-      }
+      const img = document.getElementById(id);
 
       // The promise resolves when the image is loaded or has failed to load.
       img.onload = () => resolve(img);
       img.onerror = () => resolve(img);
 
-      parent.innerHTML = parentContent.replace('<img>', img.outerHTML);
-      testContainer.appendChild(parent);
+      // Apply all attributes *except* `src` to avoid triggering a network
+      // request before the load/error handlers are attached.
+      const imgSrc = attributes.src;
+      for (const [key, value] of Object.entries(attributes)) {
+        if (key !== 'src') {
+          img.setAttribute(key, value);
+        }
+      }
 
-      // Set src last to ensure handlers are attached. Use the data URI only if
-      // no src was provided in the test attributes.
-      if (!img.hasAttribute('src')) {
-        img.src = RED_1X1_PIXEL;
+      // Set `src` last to ensure handlers are ready.
+      if (imgSrc) {
+        img.src = imgSrc;
+      } else {
+        // Generate an SVG `src` to control dimensions if one wasn't provided.
+        const svg = `<svg width="${naturalWidth}" height="${naturalHeight}"
+                          xmlns="http://www.w3.org/2000/svg"></svg>`;
+        img.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
       }
     });
   }
@@ -72,21 +76,40 @@
     // Define all test dimensions in density-independent units (DP).
     const INLINE_WIDTH_FALLBACK_UPPER_BOUND_DP = 300;
 
-    const imagePromises = [
-      // Definitely Inline.
-      createImageTest('small_icon', 50, 50, 'p', '<img>'),
-      createImageTest('math_class', 100, 100, 'p', '<img>', {class: 'tex'}),
-      createImageTest('math_filename', 100, 100, 'p', '<img>',
-                      {src: '/foo/icon.svg'}),
-      createImageTest('math_alt', 100, 100, 'p', '<img>', {alt: 'E=mc^2'}),
+    // For metadata tests, use a width that is large but guaranteed to not
+    // trigger the dominant image guardrail.
+    const safeNonDominantWidth = Math.floor(window.innerWidth * 0.7);
 
-      // Definitely Full-width.
+    const imagePromises = [
+      // New Guardrail Test: A visually dominant "hero" image.
+      createImageTest(
+          'hero_image', 200, 100, 'p', '<img>', {
+            style: 'width: 90vw;',
+            // Add a misleading keyword to prove the guardrail overrides it.
+            class: 'icon-class',
+          }),
+
+      // Definitely Inline (based on intrinsic properties).
+      createImageTest('small_area', 50, 50, 'p', '<img>'),
+      // These should be inline due to metadata, using a width that is
+      // guaranteed to not be visually dominant.
+      createImageTest(
+          'math_class', safeNonDominantWidth, 100, 'p', '<img>',
+          {class: 'tex'}),
+      createImageTest(
+          'math_filename', safeNonDominantWidth, 100, 'p', '<img>',
+          {src: '/foo/icon.svg'}),
+      createImageTest(
+          'math_alt', safeNonDominantWidth, 100, 'p', '<img>',
+          {alt: 'E=mc^2'}),
+
+      // Definitely Full-width (based on structure).
       createImageTest('figure_with_caption', 400, 300, 'figure',
                       '<img><figcaption>Test</figcaption>'),
       createImageTest('sole_content_in_p', 400, 300, 'p', '<img>'),
       createImageTest('sole_content_with_br', 400, 300, 'p', '<img><br>'),
 
-      // Fallback.
+      // Fallback (based on intrinsic width).
       createImageTest(
           'fallback_wide', INLINE_WIDTH_FALLBACK_UPPER_BOUND_DP + 50, 200, 'p',
           'Some text <img>'),
@@ -98,13 +121,15 @@
     // Wait for all images to be created and loaded into the DOM.
     await Promise.all(imagePromises);
 
-    // Run the classifier on the container. This may attach new onload handlers.
-    ImageClassifier.processImagesIn(testContainer);
-
-    // Wait one more event loop turn for the classifier's onload handlers to
-    // fire.
+    // Yield to the browser's event loop with a `setTimeout` to ensure a layout
+    // pass occurs before the classifier runs. This is critical for
+    // getBoundingClientRect() to return a non-zero width.
     await new Promise(resolve => setTimeout(resolve, 0));
 
+    // Run the classifier on the container. For cached images, this will
+    // synchronously apply the classification classes.
+    ImageClassifier.processImagesIn(testContainer);
+
     // Run the assertions.
     const assertHasClass = (id, expectedClass) => {
       const el = document.getElementById(id);
@@ -112,7 +137,9 @@
           `Image #${id} should have class ${expectedClass}`);
     };
 
-    assertHasClass('small_icon', ImageClassifier.INLINE_CLASS);
+    assertHasClass('hero_image', ImageClassifier.FULL_WIDTH_CLASS);
+
+    assertHasClass('small_area', ImageClassifier.INLINE_CLASS);
     assertHasClass('math_class', ImageClassifier.INLINE_CLASS);
     assertHasClass('math_filename', ImageClassifier.INLINE_CLASS);
     assertHasClass('math_alt', ImageClassifier.INLINE_CLASS);
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h
index 6682710..66c416f4 100644
--- a/content/browser/bad_message.h
+++ b/content/browser/bad_message.h
@@ -357,6 +357,7 @@
   RFH_ORIGIN_TO_COMMIT_MISMATCH = 329,
   RFH_CRASH_REPORT_STORAGE_SIZE_TOO_LARGE = 330,
   RFH_CRASH_REPORT_STORAGE_ALREADY_INITIALIZED = 331,
+  RFH_INVALID_DOCUMENT_SEQUENCE_NUMBER = 332,
 
   // Please add new elements here. The naming convention is abbreviated class
   // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc
index 386238b5..c9a73853 100644
--- a/content/browser/browser_child_process_host_impl.cc
+++ b/content/browser/browser_child_process_host_impl.cc
@@ -223,12 +223,10 @@
 
 void BrowserChildProcessHostImpl::Launch(
     std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
-    std::unique_ptr<base::CommandLine> cmd_line,
-    bool terminate_on_shutdown) {
+    std::unique_ptr<base::CommandLine> cmd_line) {
   LaunchWithFileData(
       std::move(delegate), std::move(cmd_line),
-      /*file_data=*/std::make_unique<ChildProcessLauncherFileData>(),
-      terminate_on_shutdown);
+      /*file_data=*/std::make_unique<ChildProcessLauncherFileData>());
 }
 
 const ChildProcessData& BrowserChildProcessHostImpl::GetData() {
@@ -271,20 +269,17 @@
 void BrowserChildProcessHostImpl::LaunchWithFileData(
     std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
     std::unique_ptr<base::CommandLine> cmd_line,
-    std::unique_ptr<ChildProcessLauncherFileData> file_data,
-    bool terminate_on_shutdown) {
+    std::unique_ptr<ChildProcessLauncherFileData> file_data) {
   GetContentClient()->browser()->AppendExtraCommandLineSwitches(cmd_line.get(),
                                                                 data_.id);
   LaunchWithoutExtraCommandLineSwitches(
-      std::move(delegate), std::move(cmd_line), std::move(file_data),
-      terminate_on_shutdown);
+      std::move(delegate), std::move(cmd_line), std::move(file_data));
 }
 
 void BrowserChildProcessHostImpl::LaunchWithoutExtraCommandLineSwitches(
     std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
     std::unique_ptr<base::CommandLine> cmd_line,
-    std::unique_ptr<ChildProcessLauncherFileData> file_data,
-    bool terminate_on_shutdown) {
+    std::unique_ptr<ChildProcessLauncherFileData> file_data) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!in_process_);
 
@@ -338,8 +333,7 @@
           data_.process_type)
           ? metrics_shared_region_
           : nullptr,
-      tracing_config_memory_region_, tracing_output_memory_region_,
-      terminate_on_shutdown);
+      tracing_config_memory_region_, tracing_output_memory_region_);
   ShareMetricsAllocatorToProcess();
 
   if (!has_legacy_ipc_channel_)
diff --git a/content/browser/browser_child_process_host_impl.h b/content/browser/browser_child_process_host_impl.h
index 2fe70bf0..f98edecc 100644
--- a/content/browser/browser_child_process_host_impl.h
+++ b/content/browser/browser_child_process_host_impl.h
@@ -78,8 +78,7 @@
 
   // BrowserChildProcessHost implementation:
   void Launch(std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
-              std::unique_ptr<base::CommandLine> cmd_line,
-              bool terminate_on_shutdown) override;
+              std::unique_ptr<base::CommandLine> cmd_line) override;
   const ChildProcessData& GetData() override;
   ChildProcessHost* GetHost() override;
   ChildProcessTerminationInfo GetTerminationInfo(bool known_dead) override;
@@ -113,8 +112,7 @@
   void LaunchWithFileData(
       std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
       std::unique_ptr<base::CommandLine> cmd_line,
-      std::unique_ptr<ChildProcessLauncherFileData> file_data,
-      bool terminate_on_shutdown);
+      std::unique_ptr<ChildProcessLauncherFileData> file_data);
 
   // Unlike Launch(), AppendExtraCommandLineSwitches will not be called
   // in this function. If AppendExtraCommandLineSwitches has been called before
@@ -123,8 +121,7 @@
   void LaunchWithoutExtraCommandLineSwitches(
       std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
       std::unique_ptr<base::CommandLine> cmd_line,
-      std::unique_ptr<ChildProcessLauncherFileData> file_data,
-      bool terminate_on_shutdown);
+      std::unique_ptr<ChildProcessLauncherFileData> file_data);
 
 #if !BUILDFLAG(IS_ANDROID)
   void SetProcessPriority(base::Process::Priority priority);
diff --git a/content/browser/browser_child_process_observer_browsertest.cc b/content/browser/browser_child_process_observer_browsertest.cc
index f22b19da..be7a827 100644
--- a/content/browser/browser_child_process_observer_browsertest.cc
+++ b/content/browser/browser_child_process_observer_browsertest.cc
@@ -243,10 +243,9 @@
     process_->SetName(u"Test utility process");
 
     auto command_line = GetChildCommandLine();
-    bool terminate_on_shutdown = true;
 
     process_->Launch(std::move(sandboxed_process_launcher_delegate),
-                     std::move(command_line), terminate_on_shutdown);
+                     std::move(command_line));
 
     test_service_ = BindTestService();
   }
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc
index dd098ae..f57b4c3 100644
--- a/content/browser/child_process_launcher.cc
+++ b/content/browser/child_process_launcher.cc
@@ -113,8 +113,7 @@
     scoped_refptr<base::RefCountedData<base::ReadOnlySharedMemoryRegion>>
         tracing_config_memory_region,
     scoped_refptr<base::RefCountedData<base::UnsafeSharedMemoryRegion>>
-        tracing_output_memory_region,
-    bool terminate_on_shutdown)
+        tracing_output_memory_region)
     : client_(client),
       starting_(true),
 #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) ||  \
@@ -122,7 +121,7 @@
     defined(UNDEFINED_SANITIZER) || BUILDFLAG(CLANG_PROFILING)
       terminate_child_on_shutdown_(false)
 #else
-      terminate_child_on_shutdown_(terminate_on_shutdown)
+      terminate_child_on_shutdown_(true)
 #endif
 {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -135,7 +134,7 @@
 
   helper_ = base::MakeRefCounted<ChildProcessLauncherHelper>(
       child_process_id, std::move(command_line), std::move(delegate),
-      weak_factory_.GetWeakPtr(), terminate_on_shutdown,
+      weak_factory_.GetWeakPtr(), terminate_child_on_shutdown_,
 #if BUILDFLAG(IS_ANDROID)
       client_->CanUseWarmUpConnection(), client_->HasSpareRendererPriority(),
 #endif
diff --git a/content/browser/child_process_launcher.h b/content/browser/child_process_launcher.h
index 969cd3d..dbbf190 100644
--- a/content/browser/child_process_launcher.h
+++ b/content/browser/child_process_launcher.h
@@ -267,8 +267,7 @@
       scoped_refptr<base::RefCountedData<base::ReadOnlySharedMemoryRegion>>
           trace_config_memory_region = nullptr,
       scoped_refptr<base::RefCountedData<base::UnsafeSharedMemoryRegion>>
-          trace_output_memory_region = nullptr,
-      bool terminate_on_shutdown = true);
+          trace_output_memory_region = nullptr);
 
   ChildProcessLauncher(const ChildProcessLauncher&) = delete;
   ChildProcessLauncher& operator=(const ChildProcessLauncher&) = delete;
diff --git a/content/browser/form_controls_browsertest.cc b/content/browser/form_controls_browsertest.cc
index 3b67742..075a3f91 100644
--- a/content/browser/form_controls_browsertest.cc
+++ b/content/browser/form_controls_browsertest.cc
@@ -353,9 +353,11 @@
 // TODO(crbug.com/377986468) : Flaky on Windows. Seems to lose focus of top
 // <select> in some runs which causes the results to be different from
 // expectations.
-// TODO(crbug.com/448656594): The test fails on Android. Either the test is flaky or the
-// baseline is wrong.
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
+// TODO(crbug.com/448656594): The test fails on Android. Either the test is
+// flaky or the baseline is wrong.
+// TODO(crbug.com/449053040): Re-enable the test on Linux.
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \
+    BUILDFLAG(IS_LINUX)
 #define MAYBE_MultiSelect DISABLED_MultiSelect
 #else
 #define MAYBE_MultiSelect MultiSelect
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 7b4269c..b62fa886 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -1382,7 +1382,7 @@
   process_->LaunchWithoutExtraCommandLineSwitches(
       std::move(delegate), std::move(cmd_line),
       /*file_data=*/
-      std::make_unique<ChildProcessLauncherFileData>(), true);
+      std::make_unique<ChildProcessLauncherFileData>());
   process_launched_ = true;
 
   if (kind_ == GPU_PROCESS_KIND_SANDBOXED) {
diff --git a/content/browser/renderer_host/navigation_controller_android.cc b/content/browser/renderer_host/navigation_controller_android.cc
index ceafb11e..56c496d4 100644
--- a/content/browser/renderer_host/navigation_controller_android.cc
+++ b/content/browser/renderer_host/navigation_controller_android.cc
@@ -485,6 +485,10 @@
   return navigation_controller_->GetLastCommittedEntryIndex();
 }
 
+jboolean NavigationControllerAndroid::CanViewSource(JNIEnv* env) {
+  return navigation_controller_->CanViewSource();
+}
+
 jboolean NavigationControllerAndroid::RemoveEntryAtIndex(JNIEnv* env,
                                                          jint index) {
   return navigation_controller_->RemoveEntryAtIndex(index);
diff --git a/content/browser/renderer_host/navigation_controller_android.h b/content/browser/renderer_host/navigation_controller_android.h
index 9f51c35..c3ba610a 100644
--- a/content/browser/renderer_host/navigation_controller_android.h
+++ b/content/browser/renderer_host/navigation_controller_android.h
@@ -101,6 +101,7 @@
       jint max_entries);
   void ClearHistory(JNIEnv* env);
   int GetLastCommittedEntryIndex(JNIEnv* env);
+  jboolean CanViewSource(JNIEnv* env);
   jboolean RemoveEntryAtIndex(JNIEnv* env,
                               jint index);
   void PruneForwardEntries(JNIEnv* env);
diff --git a/content/browser/renderer_host/render_frame_host_android.cc b/content/browser/renderer_host/render_frame_host_android.cc
index 07cea008..1550be0 100644
--- a/content/browser/renderer_host/render_frame_host_android.cc
+++ b/content/browser/renderer_host/render_frame_host_android.cc
@@ -332,4 +332,8 @@
   return false;
 }
 
+void RenderFrameHostAndroid::ViewSource(JNIEnv* env) {
+  render_frame_host()->ViewSource();
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_frame_host_android.h b/content/browser/renderer_host/render_frame_host_android.h
index 21c828f..12d3eaa6 100644
--- a/content/browser/renderer_host/render_frame_host_android.h
+++ b/content/browser/renderer_host/render_frame_host_android.h
@@ -106,6 +106,8 @@
 
   bool HasHitTestDataForTesting(JNIEnv* env);
 
+  void ViewSource(JNIEnv* env);
+
   RenderFrameHostImpl* render_frame_host() const { return render_frame_host_; }
 
  private:
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index bbf1fa5..65b5ec38 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -15361,11 +15361,6 @@
   DCHECK_EQ(ui::PageTransitionIsMainFrame(params->transition),
             !GetParent() && !IsFencedFrameRoot());
   // TODO(https://crbug.com/445585641): Make this enforceable on Android.
-#if !BUILDFLAG(IS_ANDROID)
-  if (base::FeatureList::IsEnabled(kCheckDocumentSequenceNumber)) {
-    CHECK_NE(params->document_sequence_number, -1);
-  }
-#endif
   if (navigation_request &&
       navigation_request->commit_params().navigation_token !=
           params->navigation_token) {
@@ -16553,6 +16548,17 @@
   // kInBackForwardCache state.
   DCHECK(!IsInBackForwardCache());
 
+  // TODO(https://crbug.com/445585641): Make this enforceable on Android.
+#if !BUILDFLAG(IS_ANDROID)
+  if (base::FeatureList::IsEnabled(kCheckDocumentSequenceNumber)) {
+    if (params->document_sequence_number == -1) {
+      bad_message::ReceivedBadMessage(
+          GetProcess(), bad_message::RFH_INVALID_DOCUMENT_SEQUENCE_NUMBER);
+      return;
+    }
+  }
+#endif
+
   std::unique_ptr<NavigationRequest> request;
   // TODO(crbug.com/40546539): a `committing_navigation_request` is not
   // present if and only if this is a synchronous re-navigation to about:blank
diff --git a/content/browser/service_host/utility_process_host.cc b/content/browser/service_host/utility_process_host.cc
index f8265ac..b4d84672 100644
--- a/content/browser/service_host/utility_process_host.cc
+++ b/content/browser/service_host/utility_process_host.cc
@@ -548,7 +548,7 @@
 #endif  // BUILDFLAG(USE_ZYGOTE)
 
   process_->LaunchWithFileData(std::move(delegate), std::move(cmd_line),
-                               std::move(options_.file_data_), true);
+                               std::move(options_.file_data_));
 
   return true;
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java
index 1f95b5d..ad6c28d 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java
@@ -197,16 +197,13 @@
                     if (pid > 0) {
                         sLauncherByPid.put(pid, ChildProcessLauncherHelperImpl.this);
                         if (mRanking != null) {
-                            // TODO(crbug.com/409703175): Set isSpareRenderer once the
-                            // spare renderer information is passed when launching the
-                            // process.
                             mRanking.addConnection(
                                     connection,
                                     /* visible= */ false,
                                     /* frameDepth= */ 1,
                                     /* intersectsViewport= */ false,
-                                    /* isSpareRenderer= */ false,
-                                    ChildProcessImportance.MODERATE);
+                                    mIsSpareRenderer,
+                                    mEffectiveImportance);
                             if (mBindingManager != null) mBindingManager.rankingChanged();
                         }
                         if (mSandboxed) {
diff --git a/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
index df2c586..3b5e8184 100644
--- a/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
@@ -321,6 +321,15 @@
     }
 
     @Override
+    public boolean canViewSource() {
+        if (mNativeNavigationControllerAndroid != 0) {
+            return NavigationControllerImplJni.get()
+                    .canViewSource(mNativeNavigationControllerAndroid);
+        }
+        return false;
+    }
+
+    @Override
     public boolean removeEntryAtIndex(int index) {
         if (mNativeNavigationControllerAndroid != 0) {
             return NavigationControllerImplJni.get()
@@ -473,6 +482,8 @@
 
         int getLastCommittedEntryIndex(long nativeNavigationControllerAndroid);
 
+        boolean canViewSource(long nativeNavigationControllerAndroid);
+
         boolean removeEntryAtIndex(long nativeNavigationControllerAndroid, int index);
 
         void pruneForwardEntries(long nativeNavigationControllerAndroid);
diff --git a/content/public/android/java/src/org/chromium/content/browser/framehost/RenderFrameHostImpl.java b/content/public/android/java/src/org/chromium/content/browser/framehost/RenderFrameHostImpl.java
index b4bea98..e84a55f 100644
--- a/content/public/android/java/src/org/chromium/content/browser/framehost/RenderFrameHostImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/framehost/RenderFrameHostImpl.java
@@ -302,6 +302,11 @@
                 .hasHitTestDataForTesting(mNativeRenderFrameHostAndroid); // IN-TEST
     }
 
+    @Override
+    public void viewSource() {
+        RenderFrameHostImplJni.get().viewSource(mNativeRenderFrameHostAndroid);
+    }
+
     @NativeMethods
     interface Natives {
         GURL getLastCommittedURL(long nativeRenderFrameHostAndroid);
@@ -367,5 +372,7 @@
                 @Nullable JavaScriptCallback callback);
 
         boolean hasHitTestDataForTesting(long nativeRenderFrameHostAndroid);
+
+        void viewSource(long nativeRenderFrameHostAndroid);
     }
 }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/NavigationController.java b/content/public/android/java/src/org/chromium/content_public/browser/NavigationController.java
index 233a16ed..4d4d44b 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/NavigationController.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/NavigationController.java
@@ -151,6 +151,11 @@
     int getLastCommittedEntryIndex();
 
     /**
+     * @return true, if the source for the current entry can be viewed.
+     */
+    boolean canViewSource();
+
+    /**
      * Removes the entry at the specified |index|.
      *
      * @return false, if the index is the last committed index or the pending entry. Otherwise this
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/RenderFrameHost.java b/content/public/android/java/src/org/chromium/content_public/browser/RenderFrameHost.java
index 2d160fc..92396dc8 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/RenderFrameHost.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/RenderFrameHost.java
@@ -247,4 +247,7 @@
      * @return whether hit test data is available for this Frame.
      */
     boolean hasHitTestDataForTesting();
+
+    /** Opens view-source tab for the document last committed in this RenderFrameHost. */
+    void viewSource();
 }
diff --git a/content/public/browser/browser_child_process_host.h b/content/public/browser/browser_child_process_host.h
index 428b0ac..c8a6e2d 100644
--- a/content/public/browser/browser_child_process_host.h
+++ b/content/public/browser/browser_child_process_host.h
@@ -55,8 +55,7 @@
   // Derived classes call this to launch the child process asynchronously.
   virtual void Launch(
       std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
-      std::unique_ptr<base::CommandLine> cmd_line,
-      bool terminate_on_shutdown) = 0;
+      std::unique_ptr<base::CommandLine> cmd_line) = 0;
 
   virtual const ChildProcessData& GetData() = 0;
 
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockNavigationController.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockNavigationController.java
index 2476303..b667e99 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockNavigationController.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockNavigationController.java
@@ -117,6 +117,11 @@
     }
 
     @Override
+    public boolean canViewSource() {
+        return false;
+    }
+
+    @Override
     public boolean removeEntryAtIndex(int index) {
         return false;
     }
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockRenderFrameHost.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockRenderFrameHost.java
index 0dad1b0..396c2f0 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockRenderFrameHost.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockRenderFrameHost.java
@@ -131,4 +131,7 @@
     public boolean hasHitTestDataForTesting() {
         return true;
     }
+
+    @Override
+    public void viewSource() {}
 }
diff --git a/crypto/subtle_passkey.h b/crypto/subtle_passkey.h
index e5a7f27a..588b741 100644
--- a/crypto/subtle_passkey.h
+++ b/crypto/subtle_passkey.h
@@ -30,6 +30,7 @@
 
 namespace os_crypt_async {
 class FreedesktopSecretKeyProvider;
+class KeychainKeyProvider;
 }
 
 class OSCryptImpl;
@@ -74,6 +75,7 @@
   // compatibility with existing persisted data.
   friend class ::OSCryptImpl;
   friend class os_crypt_async::FreedesktopSecretKeyProvider;
+  friend class os_crypt_async::KeychainKeyProvider;
 
   // This class uses custom PBKDF2 parameters which cannot be changed for
   // compatibility with persisted data.
diff --git a/device/gamepad/gamepad_service_unittest.cc b/device/gamepad/gamepad_service_unittest.cc
index a9a2c703..1445df3 100644
--- a/device/gamepad/gamepad_service_unittest.cc
+++ b/device/gamepad/gamepad_service_unittest.cc
@@ -1000,7 +1000,8 @@
   service()->SimulateInputFrame(random_token);
 }
 
-TEST_F(GamepadServiceSimulationTest, RemoveGamepadTwice) {
+// TODO(crbug.com/448993918): Re-enable this test
+TEST_F(GamepadServiceSimulationTest, DISABLED_RemoveGamepadTwice) {
   // Mark `consumer` active.
   auto* consumer = CreateConsumer();
   EXPECT_TRUE(service()->ConsumerBecameActive(consumer));
diff --git a/extensions/browser/api/management/management_api.cc b/extensions/browser/api/management/management_api.cc
index f76b487..476a9bc 100644
--- a/extensions/browser/api/management/management_api.cc
+++ b/extensions/browser/api/management/management_api.cc
@@ -388,7 +388,7 @@
       return Error(keys::kManifestParseError);
     }
 
-    std::string error;
+    std::u16string error;
     scoped_refptr<Extension> extension =
         Extension::Create(base::FilePath(), ManifestLocation::kInvalidLocation,
                           *parsed_manifest, Extension::NO_FLAGS, &error);
diff --git a/extensions/browser/api/storage/settings_test_util.cc b/extensions/browser/api/storage/settings_test_util.cc
index f5c36fb..1dc8fa21 100644
--- a/extensions/browser/api/storage/settings_test_util.cc
+++ b/extensions/browser/api/storage/settings_test_util.cc
@@ -99,7 +99,7 @@
       NOTREACHED();
   }
 
-  std::string error;
+  std::u16string error;
   scoped_refptr<const Extension> extension(
       Extension::Create(base::FilePath(), mojom::ManifestLocation::kInternal,
                         manifest, Extension::NO_FLAGS, id, &error));
diff --git a/extensions/browser/content_verifier/content_verifier_unittest.cc b/extensions/browser/content_verifier/content_verifier_unittest.cc
index b702a95..f9e47e0 100644
--- a/extensions/browser/content_verifier/content_verifier_unittest.cc
+++ b/extensions/browser/content_verifier/content_verifier_unittest.cc
@@ -241,7 +241,7 @@
     base::FilePath path;
     EXPECT_TRUE(base::PathService::Get(DIR_TEST_DATA, &path));
 
-    std::string error;
+    std::u16string error;
     scoped_refptr<Extension> extension(
         Extension::Create(path, mojom::ManifestLocation::kInternal, manifest,
                           Extension::NO_FLAGS, &error));
diff --git a/extensions/browser/delayed_install_manager.cc b/extensions/browser/delayed_install_manager.cc
index 009e6b6..df7cae1d 100644
--- a/extensions/browser/delayed_install_manager.cc
+++ b/extensions/browser/delayed_install_manager.cc
@@ -59,7 +59,7 @@
   for (const auto& info : delayed_info) {
     scoped_refptr<const Extension> extension;
     if (info.extension_manifest) {
-      std::string error;
+      std::u16string error;
       extension = Extension::Create(
           info.extension_path, info.extension_location,
           *info.extension_manifest,
diff --git a/extensions/browser/extension_icon_image_unittest.cc b/extensions/browser/extension_icon_image_unittest.cc
index 2719e51a..90e6fd2 100644
--- a/extensions/browser/extension_icon_image_unittest.cc
+++ b/extensions/browser/extension_icon_image_unittest.cc
@@ -123,8 +123,9 @@
       return nullptr;
     }
 
+    std::u16string utf16_error;
     return Extension::Create(test_file, location, *valid_dict,
-                             Extension::NO_FLAGS, &error);
+                             Extension::NO_FLAGS, &utf16_error);
   }
 
   // IconImage::Delegate overrides:
diff --git a/extensions/browser/extension_icon_manager_unittest.cc b/extensions/browser/extension_icon_manager_unittest.cc
index 8b32b87..0c4b952 100644
--- a/extensions/browser/extension_icon_manager_unittest.cc
+++ b/extensions/browser/extension_icon_manager_unittest.cc
@@ -140,7 +140,7 @@
   ASSERT_TRUE(manifest.get());
   ASSERT_TRUE(manifest->is_dict());
 
-  std::string error;
+  std::u16string error;
   scoped_refptr<Extension> extension(Extension::Create(
       manifest_path.DirName(), mojom::ManifestLocation::kInvalidLocation,
       manifest->GetDict(), Extension::NO_FLAGS, &error));
@@ -182,7 +182,7 @@
       deserializer.Deserialize(nullptr, nullptr);
   ASSERT_TRUE(manifest.get());
   ASSERT_TRUE(manifest->is_dict());
-  std::string error;
+  std::u16string error;
   scoped_refptr<Extension> extension(Extension::Create(
       manifest_path.DirName(), mojom::ManifestLocation::kComponent,
       manifest->GetDict(), Extension::NO_FLAGS, &error));
@@ -227,7 +227,7 @@
   ASSERT_TRUE(manifest.get());
   ASSERT_TRUE(manifest->is_dict());
 
-  std::string error;
+  std::u16string error;
   scoped_refptr<Extension> extension(Extension::Create(
       manifest_path.DirName(), mojom::ManifestLocation::kInvalidLocation,
       manifest->GetDict(), Extension::NO_FLAGS, &error));
diff --git a/extensions/browser/image_loader_unittest.cc b/extensions/browser/image_loader_unittest.cc
index 38f9059..5b0a79e 100644
--- a/extensions/browser/image_loader_unittest.cc
+++ b/extensions/browser/image_loader_unittest.cc
@@ -100,8 +100,9 @@
       return nullptr;
     }
 
+    std::u16string utf16_error;
     return Extension::Create(extension_dir, location, valid_value->GetDict(),
-                             Extension::NO_FLAGS, &error);
+                             Extension::NO_FLAGS, &utf16_error);
   }
 
   gfx::Image image_;
diff --git a/extensions/browser/requirements_checker_unittest.cc b/extensions/browser/requirements_checker_unittest.cc
index 6144d89..5a0f2f0 100644
--- a/extensions/browser/requirements_checker_unittest.cc
+++ b/extensions/browser/requirements_checker_unittest.cc
@@ -50,7 +50,7 @@
     manifest_dict_.Set("version", "1");
     manifest_dict_.Set("manifest_version", 2);
 
-    std::string error;
+    std::u16string error;
     extension_ =
         Extension::Create(base::FilePath(), mojom::ManifestLocation::kUnpacked,
                           manifest_dict_, Extension::NO_FLAGS, &error);
diff --git a/extensions/browser/sandboxed_unpacker.cc b/extensions/browser/sandboxed_unpacker.cc
index 7932666..aa12bc8 100644
--- a/extensions/browser/sandboxed_unpacker.cc
+++ b/extensions/browser/sandboxed_unpacker.cc
@@ -502,15 +502,18 @@
     return;
   }
 
-  std::string error_msg;
+  // TODO(crbug.com/41317803): Continue removing std::string errors and
+  // replacing with std::u16string.
+  std::u16string utf16_error;
   scoped_refptr<Extension> extension(
       Extension::Create(extension_root_, location_, *dict, creation_flags_,
-                        extension_id_, &error_msg));
+                        extension_id_, &utf16_error));
   if (!extension) {
-    ReportUnpackExtensionFailed(error_msg);
+    ReportUnpackExtensionFailed(base::UTF16ToUTF8(utf16_error));
     return;
   }
 
+  std::string error_msg;
   std::vector<InstallWarning> warnings;
   if (!file_util::ValidateExtension(extension.get(), &error_msg, &warnings)) {
     ReportUnpackExtensionFailed(error_msg);
@@ -551,13 +554,14 @@
     return;
   }
 
+  std::u16string utf16_error;
   extension_ =
       Extension::Create(extension_root_, location_, final_manifest.value(),
-                        Extension::REQUIRE_KEY | creation_flags_, &utf8_error);
+                        Extension::REQUIRE_KEY | creation_flags_, &utf16_error);
 
   if (!extension_.get()) {
     ReportFailure(SandboxedUnpackerFailureReason::INVALID_MANIFEST,
-                  u"Manifest is invalid: " + ASCIIToUTF16(utf8_error));
+                  u"Manifest is invalid: " + utf16_error);
     return;
   }
 
diff --git a/extensions/common/api/declarative_net_request/dnr_manifest_unittest.cc b/extensions/common/api/declarative_net_request/dnr_manifest_unittest.cc
index b69130a..200c645a 100644
--- a/extensions/common/api/declarative_net_request/dnr_manifest_unittest.cc
+++ b/extensions/common/api/declarative_net_request/dnr_manifest_unittest.cc
@@ -337,7 +337,7 @@
 TEST_F(DNRManifestTest, EmptyExtensionRootPath) {
   TestRulesetInfo ruleset("foo", "1.json", base::Value::List());
 
-  std::string error;
+  std::u16string error;
   scoped_refptr<Extension> extension = Extension::Create(
       base::FilePath(), mojom::ManifestLocation::kInternal,
       CreateManifest({ruleset}), Extension::FROM_WEBSTORE, &error);
diff --git a/extensions/common/extension.cc b/extensions/common/extension.cc
index b03ca66b..c5b49b63 100644
--- a/extensions/common/extension.cc
+++ b/extensions/common/extension.cc
@@ -240,32 +240,25 @@
                                            ManifestLocation location,
                                            const base::Value::Dict& value,
                                            int flags,
-                                           std::string* utf8_error) {
-  return Extension::Create(path,
-                           location,
-                           value,
-                           flags,
+                                           std::u16string* error) {
+  return Extension::Create(path, location, value, flags,
                            std::string(),  // ID is ignored if empty.
-                           utf8_error);
+                           error);
 }
 
-// TODO(crbug.com/41317803): Continue removing std::string errors and replacing
-// with std::u16string.
 scoped_refptr<Extension> Extension::Create(const base::FilePath& path,
                                            ManifestLocation location,
                                            const base::Value::Dict& value,
                                            int flags,
                                            const ExtensionId& explicit_id,
-                                           std::string* utf8_error) {
+                                           std::u16string* error) {
   base::ElapsedTimer timer;
-  DCHECK(utf8_error);
-  std::u16string error;
+  DCHECK(error);
 
   ExtensionId extension_id;
   if (!explicit_id.empty()) {
     extension_id = explicit_id;
-  } else if (!ComputeExtensionID(value, path, flags, &error, &extension_id)) {
-    *utf8_error = base::UTF16ToUTF8(error);
+  } else if (!ComputeExtensionID(value, path, flags, error, &extension_id)) {
     return nullptr;
   }
 
@@ -290,8 +283,7 @@
   extension->dynamic_url_ = Extension::GetBaseURLFromExtensionId(
       extension->guid_.AsLowercaseString());
 
-  if (!extension->InitFromValue(flags, &error)) {
-    *utf8_error = base::UTF16ToUTF8(error);
+  if (!extension->InitFromValue(flags, error)) {
     return nullptr;
   }
 
diff --git a/extensions/common/extension.h b/extensions/common/extension.h
index 35b8fbe..34de441b 100644
--- a/extensions/common/extension.h
+++ b/extensions/common/extension.h
@@ -136,7 +136,7 @@
                                          mojom::ManifestLocation location,
                                          const base::Value::Dict& value,
                                          int flags,
-                                         std::string* error);
+                                         std::u16string* error);
 
   // In a few special circumstances, we want to create an Extension and give it
   // an explicit id. Most consumers should just use the other Create() method.
@@ -145,7 +145,7 @@
                                          const base::Value::Dict& value,
                                          int flags,
                                          const ExtensionId& explicit_id,
-                                         std::string* error);
+                                         std::u16string* error);
 
   // Valid schemes for web extent URLPatterns.
   static const int kValidWebExtentSchemes;
diff --git a/extensions/common/extension_builder.cc b/extensions/common/extension_builder.cc
index 89738a0..6a97c740 100644
--- a/extensions/common/extension_builder.cc
+++ b/extensions/common/extension_builder.cc
@@ -191,7 +191,7 @@
   if (id_.empty() && manifest_data_)
     id_ = crx_file::id_util::GenerateId(manifest_data_->name);
 
-  std::string error;
+  std::u16string error;
 
   // This allows `*manifest_value` to be passed as a reference instead of
   // needing to be cloned.
diff --git a/extensions/common/extension_set_unittest.cc b/extensions/common/extension_set_unittest.cc
index a593787..4139198 100644
--- a/extensions/common/extension_set_unittest.cc
+++ b/extensions/common/extension_set_unittest.cc
@@ -43,7 +43,7 @@
     manifest.SetByDottedPath("app.urls", std::move(urls));
   }
 
-  std::string error;
+  std::u16string error;
   scoped_refptr<Extension> extension(
       Extension::Create(path, mojom::ManifestLocation::kInternal, manifest,
                         Extension::NO_FLAGS, &error));
diff --git a/extensions/common/extension_unittest.cc b/extensions/common/extension_unittest.cc
index 8be0fbd..b33b1e5 100644
--- a/extensions/common/extension_unittest.cc
+++ b/extensions/common/extension_unittest.cc
@@ -36,7 +36,7 @@
     std::string_view expected_warning = "",
     Extension::InitFromValueFlags custom_flag = Extension::NO_FLAGS,
     ManifestLocation manifest_location = ManifestLocation::kInternal) {
-  std::string error;
+  std::u16string error;
   scoped_refptr<const Extension> extension = Extension::Create(
       base::FilePath(), manifest_location, manifest, custom_flag, &error);
   if (!extension) {
@@ -74,7 +74,7 @@
 testing::AssertionResult RunManifestVersionFailure(
     base::Value::Dict manifest,
     Extension::InitFromValueFlags custom_flag = Extension::NO_FLAGS) {
-  std::string error;
+  std::u16string error;
   scoped_refptr<const Extension> extension =
       Extension::Create(base::FilePath(), ManifestLocation::kInternal, manifest,
                         custom_flag, &error);
@@ -89,7 +89,7 @@
     mojom::ManifestLocation location,
     Manifest::Type expected_type,
     Extension::InitFromValueFlags custom_flag = Extension::NO_FLAGS) {
-  std::string error;
+  std::u16string error;
   scoped_refptr<const Extension> extension = Extension::Create(
       base::FilePath(), location, manifest, custom_flag, &error);
   if (!extension) {
diff --git a/extensions/common/features/simple_feature_unittest.cc b/extensions/common/features/simple_feature_unittest.cc
index 2e723cb..293b146 100644
--- a/extensions/common/features/simple_feature_unittest.cc
+++ b/extensions/common/features/simple_feature_unittest.cc
@@ -353,11 +353,11 @@
                       .Set("manifest_version", 21);
   manifest.SetByDottedPath("app.launch.local_path", "foo.html");
 
-  std::string error;
+  std::u16string error;
   scoped_refptr<const Extension> extension(
       Extension::Create(base::FilePath(), ManifestLocation::kInternal, manifest,
                         Extension::NO_FLAGS, &error));
-  EXPECT_EQ("", error);
+  EXPECT_EQ(u"", error);
   ASSERT_TRUE(extension.get());
 
   feature.set_allowlist({"monkey"});
@@ -456,11 +456,11 @@
                       .Set("manifest_version", 2);
   manifest.SetByDottedPath("app.launch.local_path", "foo.html");
 
-  std::string error;
+  std::u16string error;
   scoped_refptr<const Extension> extension(
       Extension::Create(base::FilePath(), ManifestLocation::kInternal, manifest,
                         Extension::NO_FLAGS, &error));
-  EXPECT_EQ("", error);
+  EXPECT_EQ(u"", error);
   ASSERT_TRUE(extension.get());
 
   const auto kTestData = std::to_array<FeatureSessionTypeTestData>({
diff --git a/extensions/common/file_util.cc b/extensions/common/file_util.cc
index 1bb689be..dc9f84d 100644
--- a/extensions/common/file_util.cc
+++ b/extensions/common/file_util.cc
@@ -243,6 +243,8 @@
                        error);
 }
 
+// TODO(crbug.com/41317803): Continue removing std::string errors and replacing
+// with std::u16string.
 scoped_refptr<Extension> LoadExtension(
     const base::FilePath& extension_path,
     const base::FilePath::CharType* manifest_file,
@@ -268,9 +270,11 @@
     return nullptr;
   }
 
+  std::u16string utf16_error;
   scoped_refptr<Extension> extension(Extension::Create(
-      extension_path, location, *manifest, flags, extension_id, error));
+      extension_path, location, *manifest, flags, extension_id, &utf16_error));
   if (!extension.get()) {
+    *error = base::UTF16ToUTF8(utf16_error);
     return nullptr;
   }
 
diff --git a/extensions/common/file_util_unittest.cc b/extensions/common/file_util_unittest.cc
index 01f5fd5..ef4a4c23 100644
--- a/extensions/common/file_util_unittest.cc
+++ b/extensions/common/file_util_unittest.cc
@@ -59,7 +59,7 @@
     const base::FilePath& manifest_dir,
     ManifestLocation location,
     int extra_flags,
-    std::string* error) {
+    std::u16string* error) {
   scoped_refptr<Extension> extension =
       Extension::Create(manifest_dir, location, manifest, extra_flags, error);
   return extension;
@@ -70,7 +70,7 @@
     const base::FilePath& manifest_dir,
     ManifestLocation location,
     int extra_flags,
-    std::string* error) {
+    std::u16string* error) {
   std::optional<base::Value::Dict> result = base::JSONReader::ReadDict(
       manifest_value, base::JSON_PARSE_CHROMIUM_EXTENSIONS);
   if (!result) {
@@ -465,11 +465,12 @@
       "  \"theme\": { \"images\": { \"theme_frame\": \"%s\" } }"
       "}",
       non_ascii_file.c_str());
-  std::string error;
+  std::u16string utf16_error;
   scoped_refptr<Extension> extension = LoadExtensionManifest(
-      kManifest, temp.GetPath(), ManifestLocation::kUnpacked, 0, &error);
-  ASSERT_TRUE(extension.get()) << error;
+      kManifest, temp.GetPath(), ManifestLocation::kUnpacked, 0, &utf16_error);
+  ASSERT_TRUE(extension.get()) << utf16_error;
 
+  std::string error;
   std::vector<InstallWarning> warnings;
   EXPECT_TRUE(file_util::ValidateExtension(extension.get(), &error, &warnings))
       << error;
@@ -489,12 +490,13 @@
       value.EnsureDict("background")->EnsureList("scripts");
   scripts->Append("foo.js");
 
+  std::u16string utf16_error;
+  scoped_refptr<Extension> extension = LoadExtensionManifest(
+      value, temp.GetPath(), ManifestLocation::kUnpacked, 0, &utf16_error);
+  ASSERT_TRUE(extension.get()) << utf16_error;
+
   std::string error;
   std::vector<InstallWarning> warnings;
-  scoped_refptr<Extension> extension = LoadExtensionManifest(
-      value, temp.GetPath(), ManifestLocation::kUnpacked, 0, &error);
-  ASSERT_TRUE(extension.get()) << error;
-
   EXPECT_FALSE(
       file_util::ValidateExtension(extension.get(), &error, &warnings));
   EXPECT_EQ(l10n_util::GetStringFUTF8(
@@ -505,14 +507,14 @@
   scripts->clear();
   scripts->Append("http://google.com/foo.js");
 
-  extension = LoadExtensionManifest(value, temp.GetPath(),
-                                    ManifestLocation::kUnpacked, 0, &error);
+  extension = LoadExtensionManifest(
+      value, temp.GetPath(), ManifestLocation::kUnpacked, 0, &utf16_error);
   ASSERT_FALSE(extension.get());
-  ASSERT_FALSE(error.empty());
+  ASSERT_FALSE(utf16_error.empty());
   ASSERT_EQ(
       ErrorUtils::FormatErrorMessage(manifest_errors::kInvalidBackgroundScript,
                                      base::NumberToString(0)),
-      error);
+      base::UTF16ToUTF8(utf16_error));
 }
 
 // Private key, generated by Chrome specifically for this test, and
diff --git a/extensions/common/manifest_handler_unittest.cc b/extensions/common/manifest_handler_unittest.cc
index 56f03d0..9df9ac85 100644
--- a/extensions/common/manifest_handler_unittest.cc
+++ b/extensions/common/manifest_handler_unittest.cc
@@ -217,7 +217,7 @@
                                    .Set("a", 1));
 
   // Succeeds when "a" is not recognized.
-  std::string error;
+  std::u16string error;
   scoped_refptr<Extension> extension = Extension::Create(
       base::FilePath(), mojom::ManifestLocation::kInvalidLocation, manifest_a,
       Extension::NO_FLAGS, &error);
@@ -233,7 +233,7 @@
                                 mojom::ManifestLocation::kInvalidLocation,
                                 manifest_a, Extension::NO_FLAGS, &error);
   EXPECT_FALSE(extension.get());
-  EXPECT_EQ("A", error);
+  EXPECT_EQ(u"A", error);
 }
 
 TEST_F(ManifestHandlerTest, Validate) {
diff --git a/extensions/common/manifest_handlers/chrome_url_overrides_unittest.cc b/extensions/common/manifest_handlers/chrome_url_overrides_unittest.cc
index 016b065f..934df446 100644
--- a/extensions/common/manifest_handlers/chrome_url_overrides_unittest.cc
+++ b/extensions/common/manifest_handlers/chrome_url_overrides_unittest.cc
@@ -65,12 +65,13 @@
                       .Set("chrome_url_overrides",
                            base::Value::Dict().Set("newtab", "newtab.html"));
   std::string error;
+  std::u16string utf16_error;
   std::vector<InstallWarning> warnings;
   base::ScopedTempDir dir;
   ASSERT_TRUE(dir.CreateUniqueTempDir());
-  scoped_refptr<Extension> extension =
-      Extension::Create(dir.GetPath(), mojom::ManifestLocation::kInternal,
-                        manifest, Extension::NO_FLAGS, std::string(), &error);
+  scoped_refptr<Extension> extension = Extension::Create(
+      dir.GetPath(), mojom::ManifestLocation::kInternal, manifest,
+      Extension::NO_FLAGS, std::string(), &utf16_error);
   ASSERT_TRUE(extension);
   EXPECT_FALSE(
       file_util::ValidateExtension(extension.get(), &error, &warnings));
diff --git a/extensions/common/manifest_handlers/devtools_page_unittest.cc b/extensions/common/manifest_handlers/devtools_page_unittest.cc
index 4bfb5811..537bd98 100644
--- a/extensions/common/manifest_handlers/devtools_page_unittest.cc
+++ b/extensions/common/manifest_handlers/devtools_page_unittest.cc
@@ -55,7 +55,7 @@
                             const std::string& devtools_page,
                             const std::string& parsed_devtools_page) {
     base::ScopedTempDir dir;
-    std::string error;
+    std::u16string error;
     base::Value::Dict manifest = CreateManifest(devtools_page);
     ASSERT_TRUE(dir.CreateUniqueTempDir());
     scoped_refptr<Extension> extension =
@@ -76,14 +76,14 @@
                           const std::string& devtools_page,
                           const std::u16string& expected_error) {
     base::ScopedTempDir dir;
-    std::string error;
+    std::u16string error;
     base::Value::Dict manifest = CreateManifest(devtools_page);
     ASSERT_TRUE(dir.CreateUniqueTempDir());
     scoped_refptr<Extension> extension =
         Extension::Create(dir.GetPath(), mojom::ManifestLocation::kInternal,
                           manifest, Extension::NO_FLAGS, id, &error);
     ASSERT_FALSE(extension);
-    ASSERT_EQ(base::UTF16ToUTF8(expected_error), error);
+    ASSERT_EQ(expected_error, error);
   }
 
   void LoadAndExpectError(const std::string& devtools_page,
@@ -96,12 +96,13 @@
                                 const std::string& expected_warning) {
     base::ScopedTempDir dir;
     std::string error;
+    std::u16string utf16_error;
     std::vector<InstallWarning> warnings;
     base::Value::Dict manifest = CreateManifest(devtools_page);
     ASSERT_TRUE(dir.CreateUniqueTempDir());
     scoped_refptr<Extension> extension =
         Extension::Create(dir.GetPath(), mojom::ManifestLocation::kInternal,
-                          manifest, Extension::NO_FLAGS, id, &error);
+                          manifest, Extension::NO_FLAGS, id, &utf16_error);
     ASSERT_TRUE(extension);
     EXPECT_TRUE(
         ManifestHandler::ValidateExtension(extension.get(), &error, &warnings));
diff --git a/extensions/common/manifest_handlers/trial_tokens_unittest.cc b/extensions/common/manifest_handlers/trial_tokens_unittest.cc
index d55f7ac..e7aabeb 100644
--- a/extensions/common/manifest_handlers/trial_tokens_unittest.cc
+++ b/extensions/common/manifest_handlers/trial_tokens_unittest.cc
@@ -48,7 +48,7 @@
 
   scoped_refptr<Extension> LoadExtension(
       const std::string& manifest_trial_tokens) {
-    std::string error;
+    std::u16string error;
     base::FilePath test_data_dir = GetTestDataDir();
     scoped_refptr<Extension> extension = Extension::Create(
         test_data_dir.DirName(), mojom::ManifestLocation::kInternal,
diff --git a/extensions/common/manifest_test.cc b/extensions/common/manifest_test.cc
index 459accb..b84bfab 100644
--- a/extensions/common/manifest_test.cc
+++ b/extensions/common/manifest_test.cc
@@ -122,6 +122,8 @@
   return LoadManifestFile(manifest_path, error);
 }
 
+// TODO(crbug.com/41317803): Continue removing std::string error and
+// replacing with std::u16string.
 scoped_refptr<Extension> ManifestTest::LoadExtension(
     const ManifestData& manifest,
     std::string* error,
@@ -133,8 +135,12 @@
   if (!dict) {
     return nullptr;
   }
-  return Extension::Create(test_data_dir.DirName(), location, *dict, flags,
-                           GetTestExtensionID(), error);
+  std::u16string utf16_error;
+  scoped_refptr<Extension> extension =
+      Extension::Create(test_data_dir.DirName(), location, *dict, flags,
+                        GetTestExtensionID(), &utf16_error);
+  *error = base::UTF16ToUTF8(utf16_error);
+  return extension;
 }
 
 scoped_refptr<Extension> ManifestTest::LoadAndExpectSuccess(
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index 3d7030c8..7b5398b4 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -241,7 +241,7 @@
 scoped_refptr<Extension> ConvertToExtension(
     mojom::ExtensionLoadedParamsPtr params,
     int context_id,
-    std::string* error) {
+    std::u16string* error) {
   // We pass in the |id| to the create call because it will save work in the
   // normal case, and because in tests, extensions may not have paths or keys,
   // but it's important to retain the same id.
@@ -1088,7 +1088,7 @@
 void Dispatcher::LoadExtensions(
     std::vector<mojom::ExtensionLoadedParamsPtr> loaded_extensions) {
   for (auto& param : loaded_extensions) {
-    std::string error;
+    std::u16string error;
     ExtensionId id = param->id;
     std::optional<base::UnguessableToken> worker_activation_token =
         param->worker_activation_token;
diff --git a/extensions/renderer/extension_localization_throttle_unittest.cc b/extensions/renderer/extension_localization_throttle_unittest.cc
index 3125872..e5bbb6ac5 100644
--- a/extensions/renderer/extension_localization_throttle_unittest.cc
+++ b/extensions/renderer/extension_localization_throttle_unittest.cc
@@ -517,7 +517,7 @@
   // Return an extension when provided with a valid json manifest.
   scoped_refptr<const Extension> GetExtension(
       const std::string& manifest_json) {
-    std::string error;
+    std::u16string error;
     base::Value::Dict manifest_dict;
     auto manifest_value =
         base::JSONReader::ReadDict(manifest_json, base::JSON_PARSE_RFC);
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index 12324099..8e9e026 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -478,7 +478,6 @@
     "command_buffer/service/renderbuffer_manager_unittest.cc",
     "command_buffer/service/retaining_one_shot_timer_holder_unittest.cc",
     "command_buffer/service/scheduler_unittest.cc",
-    "command_buffer/service/service_discardable_manager_unittest.cc",
     "command_buffer/service/service_transfer_cache_unittest.cc",
     "command_buffer/service/shader_manager_unittest.cc",
     "command_buffer/service/shader_translator_cache_unittest.cc",
diff --git a/gpu/command_buffer/client/client_shared_image.cc b/gpu/command_buffer/client/client_shared_image.cc
index 77a42c4..4dd2adf 100644
--- a/gpu/command_buffer/client/client_shared_image.cc
+++ b/gpu/command_buffer/client/client_shared_image.cc
@@ -56,128 +56,6 @@
 
 namespace {
 
-class TestMappableBuffer : public MappableBuffer {
- public:
-  TestMappableBuffer(const gfx::Size& size, viz::SharedImageFormat format)
-      : size_(size), format_(format) {
-    size_t allocation_size = 0;
-    for (int plane_index = 0; plane_index < format_.NumberOfPlanes();
-         plane_index++) {
-      size_t height_in_pixels =
-          format_.GetPlaneSize(plane_index, size_).height();
-      CHECK(height_in_pixels);
-      allocation_size += stride(plane_index) * height_in_pixels;
-    }
-
-    data_ = std::vector<uint8_t>(allocation_size);
-  }
-
-  ~TestMappableBuffer() override = default;
-
-  // MappableBuffer:
-  bool Map() override { return true; }
-  void MapAsync(base::OnceCallback<void(bool)> result_cb) override {
-    NOTREACHED();
-  }
-  bool AsyncMappingIsNonBlocking() const override { return false; }
-  void* memory(size_t plane) override {
-    auto* data_ptr = data_.data();
-    return data_ptr +
-           viz::SharedMemoryOffsetForSharedImageFormat(format_, plane, size_);
-  }
-  void Unmap() override {}
-  int stride(size_t plane) const override {
-    DCHECK_LT(static_cast<int>(plane), format_.NumberOfPlanes());
-    return viz::SharedMemoryRowSizeForSharedImageFormat(format_, plane,
-                                                        size_.width())
-        .value();
-  }
-  gfx::GpuMemoryBufferType GetType() const override {
-    return gfx::SHARED_MEMORY_BUFFER;
-  }
-  gfx::GpuMemoryBufferHandle CloneHandle() const override { NOTREACHED(); }
-#if BUILDFLAG(IS_WIN)
-  void SetUsePreMappedMemory(bool use_premapped_memory) override {
-    NOTREACHED();
-  }
-#endif
-
- private:
-  gfx::Size size_;
-  viz::SharedImageFormat format_;
-  std::vector<uint8_t> data_;
-};
-
-class ScopedMappingMappableBuffer : public ClientSharedImage::ScopedMapping {
- public:
-  ScopedMappingMappableBuffer(const gfx::Size& size,
-                              viz::SharedImageFormat format)
-      : size_(size), format_(format) {}
-  ~ScopedMappingMappableBuffer() override {
-    if (buffer_) {
-      buffer_->Unmap();
-    }
-  }
-
-  // ClientSharedImage::ScopedMapping:
-  base::span<uint8_t> GetMemoryForPlane(const uint32_t plane_index) override {
-    CHECK(buffer_);
-
-    size_t height_in_pixels =
-        format_.GetPlaneSize(plane_index, Size()).height();
-    size_t row_size_in_bytes = viz::SharedMemoryRowSizeForSharedImageFormat(
-                                   format_, plane_index, Size().width())
-                                   .value();
-
-    CHECK(height_in_pixels);
-    CHECK(row_size_in_bytes);
-
-    // Note that the stride might be larger than the row size due to padding.
-    // For all rows other than the last, this is legal data for the client to
-    // access as it's part of the buffer.  However, the final row is not
-    // guaranteed to have padding (it's a system-dependent internal detail).
-    // Thus, the data that is legal for the client to access should *not*
-    // include any bytes beyond the actual end of the final row.
-    size_t span_length =
-        Stride(plane_index) * (height_in_pixels - 1) + row_size_in_bytes;
-
-    // SAFETY: The underlying platform-specific buffer generation mechanisms
-    // guarantee that the buffer contains at least `span_length` bytes following
-    // the start of the plane, as that region is by definition the memory
-    // storing the data of the plane.
-    return UNSAFE_BUFFERS(base::span<uint8_t>(
-        reinterpret_cast<uint8_t*>(buffer_->memory(plane_index)), span_length));
-  }
-  size_t Stride(const uint32_t plane_index) override {
-    CHECK(buffer_);
-    return buffer_->stride(plane_index);
-  }
-  gfx::Size Size() override { return size_; }
-  bool IsSharedMemory() override {
-    CHECK(buffer_);
-    return buffer_->GetType() == gfx::GpuMemoryBufferType::SHARED_MEMORY_BUFFER;
-  }
-  bool Init(MappableBuffer* mappable_buffer, bool is_already_mapped) {
-    if (!mappable_buffer) {
-      LOG(ERROR) << "No MappableBuffer.";
-      return false;
-    }
-
-    if (!is_already_mapped && !mappable_buffer->Map()) {
-      LOG(ERROR) << "Failed to map the buffer.";
-      return false;
-    }
-    buffer_ = mappable_buffer;
-    return true;
-  }
-
- private:
-  // RAW_PTR_EXCLUSION: Performance reasons (based on analysis of MotionMark).
-  RAW_PTR_EXCLUSION MappableBuffer* buffer_ = nullptr;
-  gfx::Size size_;
-  viz::SharedImageFormat format_;
-};
-
 #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_OZONE)
 bool GMBIsNative(gfx::GpuMemoryBufferType gmb_type) {
   return gmb_type != gfx::EMPTY_BUFFER && gmb_type != gfx::SHARED_MEMORY_BUFFER;
@@ -244,6 +122,74 @@
 
 }  // namespace
 
+ClientSharedImage::ScopedMapping::ScopedMapping(const gfx::Size& size,
+                                                viz::SharedImageFormat format)
+    : size_(size), format_(format) {}
+
+ClientSharedImage::ScopedMapping::~ScopedMapping() {
+  if (buffer_) {
+    buffer_->Unmap();
+  }
+}
+
+base::span<uint8_t> ClientSharedImage::ScopedMapping::GetMemoryForPlane(
+    const uint32_t plane_index) {
+  CHECK(buffer_);
+
+  size_t height_in_pixels = format_.GetPlaneSize(plane_index, Size()).height();
+  size_t row_size_in_bytes = viz::SharedMemoryRowSizeForSharedImageFormat(
+                                 format_, plane_index, Size().width())
+                                 .value();
+
+  CHECK(height_in_pixels);
+  CHECK(row_size_in_bytes);
+
+  // Note that the stride might be larger than the row size due to padding.
+  // For all rows other than the last, this is legal data for the client to
+  // access as it's part of the buffer.  However, the final row is not
+  // guaranteed to have padding (it's a system-dependent internal detail).
+  // Thus, the data that is legal for the client to access should *not*
+  // include any bytes beyond the actual end of the final row.
+  size_t span_length =
+      Stride(plane_index) * (height_in_pixels - 1) + row_size_in_bytes;
+
+  // SAFETY: The underlying platform-specific buffer generation mechanisms
+  // guarantee that the buffer contains at least `span_length` bytes following
+  // the start of the plane, as that region is by definition the memory
+  // storing the data of the plane.
+  return UNSAFE_BUFFERS(base::span<uint8_t>(
+      reinterpret_cast<uint8_t*>(buffer_->memory(plane_index)), span_length));
+}
+
+size_t ClientSharedImage::ScopedMapping::Stride(const uint32_t plane_index) {
+  CHECK(buffer_);
+  return buffer_->stride(plane_index);
+}
+
+gfx::Size ClientSharedImage::ScopedMapping::Size() {
+  return size_;
+}
+
+bool ClientSharedImage::ScopedMapping::IsSharedMemory() {
+  CHECK(buffer_);
+  return buffer_->GetType() == gfx::GpuMemoryBufferType::SHARED_MEMORY_BUFFER;
+}
+
+bool ClientSharedImage::ScopedMapping::Init(MappableBuffer* mappable_buffer,
+                                            bool is_already_mapped) {
+  if (!mappable_buffer) {
+    LOG(ERROR) << "No MappableBuffer.";
+    return false;
+  }
+
+  if (!is_already_mapped && !mappable_buffer->Map()) {
+    LOG(ERROR) << "Failed to map the buffer.";
+    return false;
+  }
+  buffer_ = mappable_buffer;
+  return true;
+}
+
 // static
 std::unique_ptr<MappableBuffer>
 ClientSharedImage::CreateMappableBufferFromHandle(
@@ -300,8 +246,8 @@
 ClientSharedImage::ScopedMapping::Create(SharedImageMetadata metadata,
                                          MappableBuffer* mappable_buffer,
                                          bool is_already_mapped) {
-  auto scoped_mapping = base::WrapUnique(
-      new ScopedMappingMappableBuffer(metadata.size, metadata.format));
+  auto scoped_mapping =
+      base::WrapUnique(new ScopedMapping(metadata.size, metadata.format));
   if (!scoped_mapping->Init(mappable_buffer, is_already_mapped)) {
     LOG(ERROR) << "ScopedMapping init failed.";
     return nullptr;
@@ -779,11 +725,9 @@
     scoped_refptr<SharedImageInterfaceHolder> sii_holder) {
   SharedImageInfo info(metadata, "CSICreateForTesting");
 
-  auto client_si = base::MakeRefCounted<ClientSharedImage>(
-      mailbox, info, sync_token, sii_holder, gfx::SHARED_MEMORY_BUFFER);
+  auto client_si =
+      CreateForTesting(mailbox, metadata, sync_token, buffer_usage, sii_holder);
   client_si->async_map_invoked_callback_for_testing_ = callback;
-  client_si->mappable_buffer_ =
-      std::make_unique<TestMappableBuffer>(info.meta.size, info.meta.format);
   client_si->premapped_for_testing_ = premapped;
   client_si->buffer_usage_ = buffer_usage;
   return client_si;
diff --git a/gpu/command_buffer/client/client_shared_image.h b/gpu/command_buffer/client/client_shared_image.h
index 5f413e5..635d744 100644
--- a/gpu/command_buffer/client/client_shared_image.h
+++ b/gpu/command_buffer/client/client_shared_image.h
@@ -94,22 +94,22 @@
   // plane.
   class GPU_COMMAND_BUFFER_CLIENT_EXPORT ScopedMapping {
    public:
-    virtual ~ScopedMapping() = default;
+    ScopedMapping(const gfx::Size& size, viz::SharedImageFormat format);
+    ~ScopedMapping();
 
-    virtual base::span<uint8_t> GetMemoryForPlane(
-        const uint32_t plane_index) = 0;
+    base::span<uint8_t> GetMemoryForPlane(const uint32_t plane_index);
 
     SkPixmap GetSkPixmapForPlane(const uint32_t plane_index,
                                  SkImageInfo sk_image_info);
 
     // Returns plane stride.
-    virtual size_t Stride(const uint32_t plane_index) = 0;
+    size_t Stride(const uint32_t plane_index);
 
     // Returns the size of the buffer.
-    virtual gfx::Size Size() = 0;
+    gfx::Size Size();
 
     // Returns whether the underlying resource is shared memory.
-    virtual bool IsSharedMemory() = 0;
+    bool IsSharedMemory();
 
    private:
     friend class ClientSharedImage;
@@ -127,6 +127,13 @@
         MappableBuffer* mappable_buffer,
         base::OnceCallback<void(std::unique_ptr<ScopedMapping>)> result_cb,
         bool success);
+
+    bool Init(MappableBuffer* mappable_buffer, bool is_already_mapped);
+
+    // RAW_PTR_EXCLUSION: Performance reasons (based on analysis of MotionMark).
+    RAW_PTR_EXCLUSION MappableBuffer* buffer_ = nullptr;
+    gfx::Size size_;
+    viz::SharedImageFormat format_;
   };
 
   // `sii_holder` must not be null.
diff --git a/gpu/command_buffer/service/service_discardable_manager.cc b/gpu/command_buffer/service/service_discardable_manager.cc
index a4c8ae71..ced6b8c 100644
--- a/gpu/command_buffer/service/service_discardable_manager.cc
+++ b/gpu/command_buffer/service/service_discardable_manager.cc
@@ -82,11 +82,7 @@
     default;
 
 ServiceDiscardableManager::ServiceDiscardableManager(
-    const GpuPreferences& preferences)
-    : entries_(EntryCache::NO_AUTO_EVICT),
-      cache_size_limit_(preferences.force_gpu_mem_discardable_limit_bytes
-                            ? preferences.force_gpu_mem_discardable_limit_bytes
-                            : DiscardableCacheSizeLimit()) {
+    const GpuPreferences& preferences) {
   // In certain cases, SingleThreadTaskRunner::CurrentDefaultHandle isn't set
   // (Android Webview).  Don't register a dump provider in these cases.
   if (base::SingleThreadTaskRunner::HasCurrentDefault()) {
@@ -97,11 +93,6 @@
 }
 
 ServiceDiscardableManager::~ServiceDiscardableManager() {
-#if DCHECK_IS_ON()
-  for (const auto& entry : entries_) {
-    DCHECK(nullptr == entry.second.unlocked_texture_ref);
-  }
-#endif
   base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
       this);
 }
@@ -118,191 +109,38 @@
                            reinterpret_cast<uintptr_t>(this));
     MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(dump_name);
     dump->AddScalar(MemoryAllocatorDump::kNameSize,
-                    MemoryAllocatorDump::kUnitsBytes, total_size_);
-
-    if (!entries_.empty()) {
-      MemoryAllocatorDump* dump_avg_size =
-          pmd->CreateAllocatorDump(dump_name + "/avg_image_size");
-      dump_avg_size->AddScalar("average_size", MemoryAllocatorDump::kUnitsBytes,
-                               total_size_ / entries_.size());
-    }
+                    MemoryAllocatorDump::kUnitsBytes, 0);
 
     // Early out, no need for more detail in a BACKGROUND dump.
     return true;
   }
 
-  for (const auto& entry : entries_) {
-    std::string dump_name = base::StringPrintf(
-        "gpu/discardable_cache/cache_0x%" PRIXPTR "/entry_0x%" PRIXPTR,
-        reinterpret_cast<uintptr_t>(this),
-        reinterpret_cast<uintptr_t>(entry.second.unlocked_texture_ref.get()));
-    MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(dump_name);
-    dump->AddScalar(MemoryAllocatorDump::kNameSize,
-                    MemoryAllocatorDump::kUnitsBytes, entry.second.size);
-  }
-
-  return true;
-}
-
-void ServiceDiscardableManager::InsertLockedTexture(
-    uint32_t texture_id,
-    size_t texture_size,
-    gles2::TextureManager* texture_manager,
-    ServiceDiscardableHandle handle) {
-  auto found = entries_.Get({texture_id, texture_manager});
-  if (found != entries_.end()) {
-    // We have somehow initialized a texture twice. The client *shouldn't* send
-    // this command, but if it does, we will clean up the old entry and use
-    // the new one.
-    total_size_ -= found->second.size;
-    if (found->second.unlocked_texture_ref) {
-      texture_manager->ReturnTexture(
-          std::move(found->second.unlocked_texture_ref));
-    }
-    entries_.Erase(found);
-  }
-
-  total_size_ += texture_size;
-  entries_.Put(GpuDiscardableEntryKey{texture_id, texture_manager},
-               GpuDiscardableEntry{handle, texture_size});
-  EnforceCacheSizeLimit(cache_size_limit_);
-}
-
-bool ServiceDiscardableManager::UnlockTexture(
-    uint32_t texture_id,
-    gles2::TextureManager* texture_manager,
-    gles2::TextureRef** texture_to_unbind) {
-  *texture_to_unbind = nullptr;
-
-  auto found = entries_.Get({texture_id, texture_manager});
-  if (found == entries_.end())
-    return false;
-
-  found->second.handle.Unlock();
-  if (--found->second.service_ref_count_ == 0) {
-    found->second.unlocked_texture_ref =
-        texture_manager->TakeTexture(texture_id);
-    *texture_to_unbind = found->second.unlocked_texture_ref.get();
-  }
-
-  return true;
-}
-
-bool ServiceDiscardableManager::LockTexture(
-    uint32_t texture_id,
-    gles2::TextureManager* texture_manager) {
-  auto found = entries_.Peek({texture_id, texture_manager});
-  if (found == entries_.end())
-    return false;
-
-  ++found->second.service_ref_count_;
-  if (found->second.unlocked_texture_ref) {
-    texture_manager->ReturnTexture(
-        std::move(found->second.unlocked_texture_ref));
-  }
-
   return true;
 }
 
 void ServiceDiscardableManager::OnTextureManagerDestruction(
     gles2::TextureManager* texture_manager) {
-  for (auto& entry : entries_) {
-    if (entry.first.texture_manager == texture_manager &&
-        entry.second.unlocked_texture_ref) {
-      texture_manager->ReturnTexture(
-          std::move(entry.second.unlocked_texture_ref));
-    }
-  }
 }
 
 void ServiceDiscardableManager::OnTextureDeleted(
     uint32_t texture_id,
     gles2::TextureManager* texture_manager) {
-  auto found = entries_.Get({texture_id, texture_manager});
-  if (found == entries_.end())
-    return;
-
-  found->second.handle.ForceDelete();
-  total_size_ -= found->second.size;
-  entries_.Erase(found);
 }
 
 void ServiceDiscardableManager::OnContextLost() {
-  auto iter = entries_.begin();
-  while (iter != entries_.end()) {
-    iter->second.handle.ForceDelete();
-    if (iter->second.unlocked_texture_ref)
-      iter->second.unlocked_texture_ref->ForceContextLost();
-
-    total_size_ -= iter->second.size;
-    iter = entries_.Erase(iter);
-  }
 }
 
 void ServiceDiscardableManager::OnTextureSizeChanged(
     uint32_t texture_id,
     gles2::TextureManager* texture_manager,
     size_t new_size) {
-  auto found = entries_.Get({texture_id, texture_manager});
-  if (found == entries_.end())
-    return;
-
-  total_size_ -= found->second.size;
-  found->second.size = new_size;
-  total_size_ += found->second.size;
-
-  EnforceCacheSizeLimit(cache_size_limit_);
 }
 
 void ServiceDiscardableManager::HandleMemoryPressure(
     base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
-  size_t limit = DiscardableCacheSizeLimitForPressure(cache_size_limit_,
-                                                      memory_pressure_level);
-  EnforceCacheSizeLimit(limit);
 }
 
 void ServiceDiscardableManager::EnforceCacheSizeLimit(size_t limit) {
-  for (auto it = entries_.rbegin(); it != entries_.rend();) {
-    if (total_size_ <= limit) {
-      return;
-    }
-    if (!it->second.handle.Delete()) {
-      ++it;
-      continue;
-    }
-
-    total_size_ -= it->second.size;
-
-    gles2::TextureManager* texture_manager = it->first.texture_manager;
-    uint32_t texture_id = it->first.texture_id;
-
-    // While unlocked, we hold the texture ref. Return this to the texture
-    // manager for cleanup.
-    texture_manager->ReturnTexture(std::move(it->second.unlocked_texture_ref));
-
-    // Erase before calling texture_manager->RemoveTexture, to avoid attempting
-    // to remove the texture from entries_ twice.
-    it = entries_.Erase(it);
-    texture_manager->RemoveTexture(texture_id);
-  }
-}
-
-bool ServiceDiscardableManager::IsEntryLockedForTesting(
-    uint32_t texture_id,
-    gles2::TextureManager* texture_manager) const {
-  auto found = entries_.Peek({texture_id, texture_manager});
-  CHECK(found != entries_.end());
-
-  return found->second.handle.IsLockedForTesting();
-}
-
-gles2::TextureRef* ServiceDiscardableManager::UnlockedTextureRefForTesting(
-    uint32_t texture_id,
-    gles2::TextureManager* texture_manager) const {
-  auto found = entries_.Peek({texture_id, texture_manager});
-  CHECK(found != entries_.end());
-
-  return found->second.unlocked_texture_ref.get();
 }
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/service_discardable_manager.h b/gpu/command_buffer/service/service_discardable_manager.h
index 6c66eb4..08fe57a 100644
--- a/gpu/command_buffer/service/service_discardable_manager.h
+++ b/gpu/command_buffer/service/service_discardable_manager.h
@@ -42,24 +42,6 @@
   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
                     base::trace_event::ProcessMemoryDump* pmd) override;
 
-  void InsertLockedTexture(uint32_t texture_id,
-                           size_t texture_size,
-                           gles2::TextureManager* texture_manager,
-                           ServiceDiscardableHandle handle);
-
-  // Unlocks the indicated texture. If *|texture_to_unbind| is not nullptr,
-  // ServiceDiscardableManager has taken ownership of the given texture, and
-  // it is the callers responsibility to unbind it from any other objects.
-  // Returns false if the given texture_id has not been initialized for use
-  // with discardable.
-  bool UnlockTexture(uint32_t texture_id,
-                     gles2::TextureManager* texture_manager,
-                     gles2::TextureRef** texture_to_unbind);
-  // Locks the indicated texture, allowing it to be used in future GL commands.
-  // Returns false if the given texture_id has not been initialized for use
-  // with discardable.
-  bool LockTexture(uint32_t texture_id, gles2::TextureManager* texture_manager);
-
   // Returns all unlocked texture refs to the texture_manager for deletion.
   // After this point, this class will have no references to the given
   // |texture_manager|.
@@ -77,19 +59,6 @@
   // Called when all contexts with cached textures in this manager are lost.
   void OnContextLost();
 
-  // Test only functions:
-  size_t NumCacheEntriesForTesting() const { return entries_.size(); }
-  bool IsEntryLockedForTesting(uint32_t texture_id,
-                               gles2::TextureManager* texture_manager) const;
-  size_t TotalSizeForTesting() const { return total_size_; }
-  gles2::TextureRef* UnlockedTextureRefForTesting(
-      uint32_t texture_id,
-      gles2::TextureManager* texture_manager) const;
-
-  void SetCacheSizeLimitForTesting(size_t cache_size_limit) {
-    cache_size_limit_ = cache_size_limit;
-  }
-
   void HandleMemoryPressure(
       base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
 
@@ -125,14 +94,6 @@
   using EntryCache = base::LRUCache<GpuDiscardableEntryKey,
                                     GpuDiscardableEntry,
                                     GpuDiscardableEntryKeyCompare>;
-  EntryCache entries_;
-
-  // Total size of all |entries_|. The same as summing
-  // GpuDiscardableEntry::size for each entry.
-  size_t total_size_ = 0;
-
-  // The limit above which the cache will start evicting resources.
-  size_t cache_size_limit_ = 0;
 };
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/service_discardable_manager_unittest.cc b/gpu/command_buffer/service/service_discardable_manager_unittest.cc
deleted file mode 100644
index 7f33234a..0000000
--- a/gpu/command_buffer/service/service_discardable_manager_unittest.cc
+++ /dev/null
@@ -1,535 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "gpu/command_buffer/service/service_discardable_manager.h"
-
-#include <memory>
-
-#include "base/memory/raw_ptr.h"
-#include "gpu/command_buffer/client/client_test_helper.h"
-#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
-#include "gpu/command_buffer/service/gpu_service_test.h"
-#include "gpu/command_buffer/service/gpu_tracer.h"
-#include "gpu/command_buffer/service/memory_tracking.h"
-#include "gpu/command_buffer/service/mocks.h"
-#include "gpu/command_buffer/service/shared_image/shared_image_manager.h"
-#include "gpu/command_buffer/service/test_helper.h"
-#include "gpu/command_buffer/service/texture_manager.h"
-#include "gpu/config/gpu_preferences.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gl/gl_mock.h"
-#include "ui/gl/gl_switches.h"
-
-using ::testing::Pointee;
-using ::testing::_;
-using ::testing::Mock;
-using ::testing::InSequence;
-
-namespace gpu {
-namespace gles2 {
-namespace {
-
-void CreateLockedHandlesForTesting(
-    std::unique_ptr<ServiceDiscardableHandle>* service_handle,
-    std::unique_ptr<ClientDiscardableHandle>* client_handle) {
-  const size_t kShmemSize = sizeof(uint32_t);
-  base::UnsafeSharedMemoryRegion shared_mem =
-      base::UnsafeSharedMemoryRegion::Create(kShmemSize);
-  base::WritableSharedMemoryMapping shared_mem_mapping = shared_mem.Map();
-  scoped_refptr<gpu::Buffer> buffer = MakeBufferFromSharedMemory(
-      std::move(shared_mem), std::move(shared_mem_mapping));
-
-  *client_handle = std::make_unique<ClientDiscardableHandle>(buffer, 0, 0);
-  *service_handle = std::make_unique<ServiceDiscardableHandle>(buffer, 0, 0);
-}
-
-ServiceDiscardableHandle CreateLockedServiceHandleForTesting() {
-  std::unique_ptr<ServiceDiscardableHandle> service_handle;
-  std::unique_ptr<ClientDiscardableHandle> client_handle;
-  CreateLockedHandlesForTesting(&service_handle, &client_handle);
-  return *service_handle;
-}
-
-class MockDestructionObserver : public TextureManager::DestructionObserver {
- public:
-  MOCK_METHOD1(OnTextureManagerDestroying, void(TextureManager* manager));
-  MOCK_METHOD1(OnTextureRefDestroying, void(TextureRef* ref));
-};
-
-// A small texture that should never run up against our limits.
-static const uint32_t kSmallTextureDim = 16;
-static const size_t kSmallTextureSize = 4 * kSmallTextureDim * kSmallTextureDim;
-
-}  // namespace
-
-class ServiceDiscardableManagerTest : public GpuServiceTest {
- public:
-  ServiceDiscardableManagerTest() : discardable_manager_(GpuPreferences()) {}
-  ~ServiceDiscardableManagerTest() override = default;
-
- protected:
-  void SetUp() override {
-    GpuServiceTest::SetUp();
-    decoder_ = std::make_unique<MockGLES2Decoder>(
-        &client_, &command_buffer_service_, &outputter_);
-    feature_info_ = new FeatureInfo();
-    context_group_ = MakeRefCounted<ContextGroup>(
-        gpu_preferences_,
-        /*memory_tracker=*/nullptr,
-        /*shader_translator_cache=*/nullptr,
-        /*framebuffer_completeness_cache=*/nullptr, feature_info_,
-        /*progress_reporter=*/nullptr, GpuFeatureInfo(), &discardable_manager_,
-        &shared_image_manager_);
-    TestHelper::SetupContextGroupInitExpectations(
-        gl_.get(), DisallowedFeatures(), "GL_EXT_framebuffer_object",
-        "OpenGL ES 2.0", CONTEXT_TYPE_OPENGLES2);
-    context_group_->Initialize(decoder_.get(), CONTEXT_TYPE_OPENGLES2,
-                               DisallowedFeatures());
-    texture_manager_ = context_group_->texture_manager();
-    texture_manager_->AddObserver(&destruction_observer_);
-  }
-
-  void TearDown() override {
-    EXPECT_CALL(destruction_observer_, OnTextureManagerDestroying(_))
-        .RetiresOnSaturation();
-    // Texture manager will destroy the 6 black/default textures.
-    EXPECT_CALL(*gl_, DeleteTextures(TextureManager::kNumDefaultTextures, _));
-
-    texture_manager_ = nullptr;
-    context_group_->Destroy(decoder_.get(), true);
-    context_group_ = nullptr;
-    EXPECT_EQ(0u, discardable_manager_.NumCacheEntriesForTesting());
-    GpuServiceTest::TearDown();
-  }
-
-  void ExpectUnlockedTextureDeletion(uint32_t client_id) {
-    TextureRef* ref = discardable_manager_.UnlockedTextureRefForTesting(
-        client_id, texture_manager_);
-    ExpectTextureRefDeletion(ref);
-  }
-
-  void ExpectTextureDeletion(uint32_t client_id) {
-    TextureRef* ref = texture_manager_->GetTexture(client_id);
-    ExpectTextureRefDeletion(ref);
-  }
-
-  void ExpectTextureRefDeletion(TextureRef* ref) {
-    EXPECT_NE(nullptr, ref);
-    ref->AddObserver();
-    EXPECT_CALL(destruction_observer_, OnTextureRefDestroying(ref))
-        .WillOnce([](TextureRef* ref) { ref->RemoveObserver(); });
-    EXPECT_CALL(*gl_, DeleteTextures(1, Pointee(ref->service_id())))
-        .RetiresOnSaturation();
-  }
-
-  TraceOutputter outputter_;
-  ServiceDiscardableManager discardable_manager_;
-  SharedImageManager shared_image_manager_;
-  GpuPreferences gpu_preferences_;
-  scoped_refptr<FeatureInfo> feature_info_;
-  MockDestructionObserver destruction_observer_;
-  // This is owned by |context_group_|.
-  raw_ptr<TextureManager> texture_manager_;
-  FakeCommandBufferServiceBase command_buffer_service_;
-  FakeDecoderClient client_;
-  std::unique_ptr<MockGLES2Decoder> decoder_;
-  scoped_refptr<gles2::ContextGroup> context_group_;
-};
-
-TEST_F(ServiceDiscardableManagerTest, BasicUsage) {
-  const GLuint kClientId = 1;
-  const GLuint kServiceId = 2;
-
-  // Create and insert a new texture.
-  texture_manager_->CreateTexture(kClientId, kServiceId);
-  auto handle = CreateLockedServiceHandleForTesting();
-  discardable_manager_.InsertLockedTexture(kClientId, kSmallTextureSize,
-                                           texture_manager_, handle);
-  EXPECT_EQ(1u, discardable_manager_.NumCacheEntriesForTesting());
-  EXPECT_TRUE(discardable_manager_.IsEntryLockedForTesting(kClientId,
-                                                           texture_manager_));
-  EXPECT_NE(nullptr, texture_manager_->GetTexture(kClientId));
-
-  // Unlock the texture, ServiceDiscardableManager should take ownership of the
-  // TextureRef.
-  gles2::TextureRef* texture_to_unbind;
-  EXPECT_TRUE(discardable_manager_.UnlockTexture(kClientId, texture_manager_,
-                                                 &texture_to_unbind));
-  EXPECT_NE(nullptr, texture_to_unbind);
-  EXPECT_FALSE(discardable_manager_.IsEntryLockedForTesting(kClientId,
-                                                            texture_manager_));
-  EXPECT_EQ(nullptr, texture_manager_->GetTexture(kClientId));
-
-  // Re-lock the texture, the TextureManager should now resume ownership of
-  // the TextureRef.
-  discardable_manager_.LockTexture(kClientId, texture_manager_);
-  EXPECT_NE(nullptr, texture_manager_->GetTexture(kClientId));
-
-  // Delete the texture from the TextureManager, it should also be removed from
-  // the ServiceDiscardableManager.
-  ExpectTextureDeletion(kClientId);
-  texture_manager_->RemoveTexture(kClientId);
-  EXPECT_EQ(0u, discardable_manager_.NumCacheEntriesForTesting());
-}
-
-TEST_F(ServiceDiscardableManagerTest, DeleteAtShutdown) {
-  // Create 8 small textures (which will not hit memory limits), leaving every
-  // other one unlocked.
-  for (int i = 1; i <= 8; ++i) {
-    texture_manager_->CreateTexture(i, i);
-    auto handle = CreateLockedServiceHandleForTesting();
-    discardable_manager_.InsertLockedTexture(i, kSmallTextureSize,
-                                             texture_manager_, handle);
-    if (i % 2) {
-      TextureRef* texture_to_unbind;
-      EXPECT_TRUE(discardable_manager_.UnlockTexture(i, texture_manager_,
-                                                     &texture_to_unbind));
-      EXPECT_NE(nullptr, texture_to_unbind);
-    }
-  }
-
-  // Expect that all 8 will be deleted at shutdown, regardless of
-  // locked/unlocked state.
-  for (int i = 1; i <= 8; ++i) {
-    if (i % 2) {
-      ExpectUnlockedTextureDeletion(i);
-    } else {
-      ExpectTextureDeletion(i);
-    }
-  }
-
-  // Let the test shut down, the expectations should be fulfilled.
-}
-
-TEST_F(ServiceDiscardableManagerTest, UnlockInvalid) {
-  const GLuint kClientId = 1;
-  gles2::TextureRef* texture_to_unbind;
-  EXPECT_FALSE(discardable_manager_.UnlockTexture(kClientId, texture_manager_,
-                                                  &texture_to_unbind));
-  EXPECT_EQ(nullptr, texture_to_unbind);
-}
-
-TEST_F(ServiceDiscardableManagerTest, Limits) {
-  // Size textures so that four fit in the discardable manager.
-  const size_t cache_size_limit = 4 * 1024 * 1024;
-  const size_t texture_size = cache_size_limit / 4;
-  const size_t large_texture_size = 3 * texture_size;
-
-  discardable_manager_.SetCacheSizeLimitForTesting(cache_size_limit);
-
-  // Create 4 textures, this should fill up the discardable cache.
-  for (int i = 1; i < 5; ++i) {
-    texture_manager_->CreateTexture(i, i);
-    auto handle = CreateLockedServiceHandleForTesting();
-    discardable_manager_.InsertLockedTexture(i, texture_size, texture_manager_,
-                                             handle);
-  }
-
-  gles2::TextureRef* texture_to_unbind;
-  EXPECT_TRUE(discardable_manager_.UnlockTexture(3, texture_manager_,
-                                                 &texture_to_unbind));
-  EXPECT_NE(nullptr, texture_to_unbind);
-  EXPECT_TRUE(discardable_manager_.UnlockTexture(1, texture_manager_,
-                                                 &texture_to_unbind));
-  EXPECT_NE(nullptr, texture_to_unbind);
-  EXPECT_TRUE(discardable_manager_.UnlockTexture(2, texture_manager_,
-                                                 &texture_to_unbind));
-  EXPECT_NE(nullptr, texture_to_unbind);
-  EXPECT_TRUE(discardable_manager_.UnlockTexture(4, texture_manager_,
-                                                 &texture_to_unbind));
-  EXPECT_NE(nullptr, texture_to_unbind);
-
-  // Allocate four more textures - the previous 4 should be evicted / deleted in
-  // LRU order.
-  {
-    InSequence s;
-    ExpectUnlockedTextureDeletion(3);
-    ExpectUnlockedTextureDeletion(1);
-    ExpectUnlockedTextureDeletion(2);
-    ExpectUnlockedTextureDeletion(4);
-  }
-
-  for (int i = 5; i < 9; ++i) {
-    texture_manager_->CreateTexture(i, i);
-    auto handle = CreateLockedServiceHandleForTesting();
-    discardable_manager_.InsertLockedTexture(i, texture_size, texture_manager_,
-                                             handle);
-  }
-
-  // Ensure that the above expectations are handled by this point.
-  Mock::VerifyAndClearExpectations(gl_.get());
-  Mock::VerifyAndClearExpectations(&destruction_observer_);
-
-  // Unlock the next four textures:
-  EXPECT_TRUE(discardable_manager_.UnlockTexture(5, texture_manager_,
-                                                 &texture_to_unbind));
-  EXPECT_NE(nullptr, texture_to_unbind);
-  EXPECT_TRUE(discardable_manager_.UnlockTexture(6, texture_manager_,
-                                                 &texture_to_unbind));
-  EXPECT_NE(nullptr, texture_to_unbind);
-  EXPECT_TRUE(discardable_manager_.UnlockTexture(8, texture_manager_,
-                                                 &texture_to_unbind));
-  EXPECT_NE(nullptr, texture_to_unbind);
-  EXPECT_TRUE(discardable_manager_.UnlockTexture(7, texture_manager_,
-                                                 &texture_to_unbind));
-  EXPECT_NE(nullptr, texture_to_unbind);
-
-  // Allocate one more *large* texture, it should evict the LRU 3 textures.
-  {
-    InSequence s;
-    ExpectUnlockedTextureDeletion(5);
-    ExpectUnlockedTextureDeletion(6);
-    ExpectUnlockedTextureDeletion(8);
-  }
-
-  texture_manager_->CreateTexture(9, 9);
-  auto handle = CreateLockedServiceHandleForTesting();
-  discardable_manager_.InsertLockedTexture(9, large_texture_size,
-                                           texture_manager_, handle);
-
-  // Expect the two remaining textures to clean up.
-  ExpectTextureDeletion(9);
-  ExpectUnlockedTextureDeletion(7);
-}
-
-TEST_F(ServiceDiscardableManagerTest, TextureSizeChanged) {
-  const GLuint kClientId = 1;
-  const GLuint kServiceId = 2;
-
-  texture_manager_->CreateTexture(kClientId, kServiceId);
-  TextureRef* texture_ref = texture_manager_->GetTexture(kClientId);
-  auto handle = CreateLockedServiceHandleForTesting();
-  discardable_manager_.InsertLockedTexture(kClientId, 0, texture_manager_,
-                                           handle);
-  EXPECT_EQ(0u, discardable_manager_.TotalSizeForTesting());
-  texture_manager_->SetTarget(texture_ref, GL_TEXTURE_2D);
-  texture_manager_->SetLevelInfo(texture_ref, GL_TEXTURE_2D, 0, GL_RGBA,
-                                 kSmallTextureDim, kSmallTextureDim, 1, 0,
-                                 GL_RGBA, GL_UNSIGNED_BYTE,
-                                 gfx::Rect(kSmallTextureDim, kSmallTextureDim));
-  EXPECT_EQ(kSmallTextureSize, discardable_manager_.TotalSizeForTesting());
-
-  ExpectTextureDeletion(kClientId);
-}
-
-TEST_F(ServiceDiscardableManagerTest, OwnershipOnUnlock) {
-  const GLuint kClientId = 1;
-  const GLuint kServiceId = 2;
-
-  std::unique_ptr<ServiceDiscardableHandle> service_handle;
-  std::unique_ptr<ClientDiscardableHandle> client_handle;
-  CreateLockedHandlesForTesting(&service_handle, &client_handle);
-  texture_manager_->CreateTexture(kClientId, kServiceId);
-  discardable_manager_.InsertLockedTexture(kClientId, kSmallTextureSize,
-                                           texture_manager_, *service_handle);
-
-  // Ensure that the service ref count is used to determine ownership changes.
-  client_handle->Lock();
-  TextureRef* texture_to_unbind;
-  discardable_manager_.UnlockTexture(kClientId, texture_manager_,
-                                     &texture_to_unbind);
-  EXPECT_NE(nullptr, texture_to_unbind);
-  EXPECT_TRUE(discardable_manager_.IsEntryLockedForTesting(kClientId,
-                                                           texture_manager_));
-
-  // Get the counts back in sync.
-  discardable_manager_.LockTexture(kClientId, texture_manager_);
-  discardable_manager_.UnlockTexture(kClientId, texture_manager_,
-                                     &texture_to_unbind);
-  EXPECT_NE(nullptr, texture_to_unbind);
-  EXPECT_FALSE(discardable_manager_.IsEntryLockedForTesting(kClientId,
-                                                            texture_manager_));
-
-  // Re-lock the texture twice.
-  client_handle->Lock();
-  discardable_manager_.LockTexture(kClientId, texture_manager_);
-  client_handle->Lock();
-  discardable_manager_.LockTexture(kClientId, texture_manager_);
-
-  // Ensure that unlocking once doesn't cause us to unbind the texture.
-  discardable_manager_.UnlockTexture(kClientId, texture_manager_,
-                                     &texture_to_unbind);
-  EXPECT_EQ(nullptr, texture_to_unbind);
-  EXPECT_TRUE(discardable_manager_.IsEntryLockedForTesting(kClientId,
-                                                           texture_manager_));
-
-  // The second unlock should unbind/unlock the texture.
-  discardable_manager_.UnlockTexture(kClientId, texture_manager_,
-                                     &texture_to_unbind);
-  EXPECT_NE(nullptr, texture_to_unbind);
-  EXPECT_FALSE(discardable_manager_.IsEntryLockedForTesting(kClientId,
-                                                            texture_manager_));
-
-  ExpectUnlockedTextureDeletion(kClientId);
-}
-
-TEST_F(ServiceDiscardableManagerTest, BindGeneratedTextureLock) {
-  const GLuint kClientId = 1;
-  const GLuint kServiceId = 2;
-  const GLuint kGeneratedServiceId = 3;
-
-  // Create and insert a new texture.
-  texture_manager_->CreateTexture(kClientId, kServiceId);
-  auto handle = CreateLockedServiceHandleForTesting();
-  discardable_manager_.InsertLockedTexture(kClientId, kSmallTextureSize,
-                                           texture_manager_, handle);
-
-  // Unlock the texture, ServiceDiscardableManager should take ownership of the
-  // TextureRef.
-  gles2::TextureRef* texture_to_unbind;
-  EXPECT_TRUE(discardable_manager_.UnlockTexture(kClientId, texture_manager_,
-                                                 &texture_to_unbind));
-  EXPECT_NE(nullptr, texture_to_unbind);
-  EXPECT_EQ(nullptr, texture_manager_->GetTexture(kClientId));
-
-  // Generate a new texture for the given client id, similar to "bind generates
-  // resource" behavior.
-  texture_manager_->CreateTexture(kClientId, kGeneratedServiceId);
-  TextureRef* generated_texture_ref = texture_manager_->GetTexture(kClientId);
-
-  // Re-lock the texture, the TextureManager should delete the returned
-  // texture and keep the generated one.
-  ExpectUnlockedTextureDeletion(kClientId);
-  discardable_manager_.LockTexture(kClientId, texture_manager_);
-  EXPECT_EQ(generated_texture_ref, texture_manager_->GetTexture(kClientId));
-
-  // Delete the texture from the TextureManager, it should also be removed from
-  // the ServiceDiscardableManager.
-  ExpectTextureDeletion(kClientId);
-  texture_manager_->RemoveTexture(kClientId);
-  EXPECT_EQ(0u, discardable_manager_.NumCacheEntriesForTesting());
-}
-
-TEST_F(ServiceDiscardableManagerTest, BindGeneratedTextureInitialization) {
-  const GLuint kClientId = 1;
-  const GLuint kServiceId = 2;
-  const GLuint kGeneratedServiceId = 3;
-
-  // Create and insert a new texture.
-  texture_manager_->CreateTexture(kClientId, kServiceId);
-  auto handle = CreateLockedServiceHandleForTesting();
-  discardable_manager_.InsertLockedTexture(kClientId, kSmallTextureSize,
-                                           texture_manager_, handle);
-
-  // Unlock the texture, ServiceDiscardableManager should take ownership of the
-  // TextureRef.
-  gles2::TextureRef* texture_to_unbind;
-  EXPECT_TRUE(discardable_manager_.UnlockTexture(kClientId, texture_manager_,
-                                                 &texture_to_unbind));
-  EXPECT_NE(nullptr, texture_to_unbind);
-  EXPECT_EQ(nullptr, texture_manager_->GetTexture(kClientId));
-
-  // Generate a new texture for the given client id, similar to "bind generates
-  // resource" behavior.
-  texture_manager_->CreateTexture(kClientId, kGeneratedServiceId);
-  TextureRef* generated_texture_ref = texture_manager_->GetTexture(kClientId);
-
-  // Re-initialize the texture, the TextureManager should delete the old
-  // texture and keep the generated one.
-  ExpectUnlockedTextureDeletion(kClientId);
-  discardable_manager_.InsertLockedTexture(kClientId, kSmallTextureSize,
-                                           texture_manager_, handle);
-  EXPECT_EQ(generated_texture_ref, texture_manager_->GetTexture(kClientId));
-
-  ExpectTextureDeletion(kClientId);
-}
-
-TEST_F(ServiceDiscardableManagerTest, BindGeneratedTextureSizeChange) {
-  const GLuint kClientId = 1;
-  const GLuint kServiceId = 2;
-  const GLuint kGeneratedServiceId = 3;
-
-  // Create and insert a new texture.
-  texture_manager_->CreateTexture(kClientId, kServiceId);
-  auto handle = CreateLockedServiceHandleForTesting();
-  discardable_manager_.InsertLockedTexture(kClientId, 0, texture_manager_,
-                                           handle);
-
-  // Unlock the texture, ServiceDiscardableManager should take ownership of the
-  // TextureRef.
-  gles2::TextureRef* texture_to_unbind;
-  EXPECT_TRUE(discardable_manager_.UnlockTexture(kClientId, texture_manager_,
-                                                 &texture_to_unbind));
-  EXPECT_NE(nullptr, texture_to_unbind);
-  EXPECT_EQ(nullptr, texture_manager_->GetTexture(kClientId));
-
-  // Generate a new texture for the given client id, similar to "bind generates
-  // resource" behavior.
-  texture_manager_->CreateTexture(kClientId, kGeneratedServiceId);
-  TextureRef* generated_texture_ref = texture_manager_->GetTexture(kClientId);
-
-  // Re-size the generated texture. The tracked size should update.
-  EXPECT_EQ(0u, discardable_manager_.TotalSizeForTesting());
-  texture_manager_->SetTarget(generated_texture_ref, GL_TEXTURE_2D);
-  texture_manager_->SetLevelInfo(generated_texture_ref, GL_TEXTURE_2D, 0,
-                                 GL_RGBA, kSmallTextureDim, kSmallTextureDim, 1,
-                                 0, GL_RGBA, GL_UNSIGNED_BYTE,
-                                 gfx::Rect(kSmallTextureDim, kSmallTextureDim));
-  EXPECT_EQ(kSmallTextureSize, discardable_manager_.TotalSizeForTesting());
-
-  ExpectUnlockedTextureDeletion(kClientId);
-  ExpectTextureDeletion(kClientId);
-}
-
-TEST_F(ServiceDiscardableManagerTest, MemoryPressure) {
-  // Size textures so that four fit in the discardable manager.
-  const size_t cache_size_limit = 4 * 1024 * 1024;
-  const size_t texture_size = cache_size_limit / 4;
-
-  discardable_manager_.SetCacheSizeLimitForTesting(cache_size_limit);
-
-  // Create 4 textures, this should fill up the discardable cache.
-  for (int i = 1; i < 5; ++i) {
-    texture_manager_->CreateTexture(i, i);
-    auto handle = CreateLockedServiceHandleForTesting();
-    discardable_manager_.InsertLockedTexture(i, texture_size, texture_manager_,
-                                             handle);
-  }
-
-  // A memory pressure call should have no impact, as all textures are locked.
-  discardable_manager_.HandleMemoryPressure(
-      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
-
-  // Unlock one texture.
-  gles2::TextureRef* texture_to_unbind;
-  EXPECT_TRUE(discardable_manager_.UnlockTexture(3, texture_manager_,
-                                                 &texture_to_unbind));
-  EXPECT_NE(nullptr, texture_to_unbind);
-
-  // Send memory pressure critical again - this should delete the unlocked
-  // texture, but not the others.
-  ExpectUnlockedTextureDeletion(3);
-  discardable_manager_.HandleMemoryPressure(
-      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
-
-  // Unlock the remaining textures
-  EXPECT_TRUE(discardable_manager_.UnlockTexture(1, texture_manager_,
-                                                 &texture_to_unbind));
-  EXPECT_NE(nullptr, texture_to_unbind);
-  EXPECT_TRUE(discardable_manager_.UnlockTexture(2, texture_manager_,
-                                                 &texture_to_unbind));
-  EXPECT_NE(nullptr, texture_to_unbind);
-  EXPECT_TRUE(discardable_manager_.UnlockTexture(4, texture_manager_,
-                                                 &texture_to_unbind));
-  EXPECT_NE(nullptr, texture_to_unbind);
-
-  // Send memory pressure moderate - this should delete all but one texture
-  // (cache is capped at 1/4 size).
-  {
-    InSequence s;
-    ExpectUnlockedTextureDeletion(1);
-    ExpectUnlockedTextureDeletion(2);
-  }
-  discardable_manager_.HandleMemoryPressure(
-      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
-
-  // Send memory pressure critical again - this should delete the remaining
-  // textures.
-  ExpectUnlockedTextureDeletion(4);
-  discardable_manager_.HandleMemoryPressure(
-      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
-}
-
-}  // namespace gles2
-}  // namespace gpu
diff --git a/internal b/internal
index e49995f7..25713569 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit e49995f780d7d67f9fc46b290e83d3a6485cb6c8
+Subproject commit 2571356975131fd1444e99fc272b03ed4e92ea8e
diff --git a/ios/chrome/browser/browser_view/ui_bundled/browser_coordinator.mm b/ios/chrome/browser/browser_view/ui_bundled/browser_coordinator.mm
index e0fd2b6..b9a7501 100644
--- a/ios/chrome/browser/browser_view/ui_bundled/browser_coordinator.mm
+++ b/ios/chrome/browser/browser_view/ui_bundled/browser_coordinator.mm
@@ -2783,8 +2783,8 @@
     return;
   }
   ChooseFileTabHelper* tab_helper =
-      ChooseFileTabHelper::GetOrCreateForWebState(activeWebState);
-  if (!tab_helper->IsChoosingFiles()) {
+      ChooseFileTabHelper::FromWebState(activeWebState);
+  if (!tab_helper || !tab_helper->IsChoosingFiles()) {
     return;
   }
   // Start the 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 5530f946..20ca1e9d 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
@@ -243,9 +243,6 @@
   // view.
   BOOL _lensOverlayVisible;
 
-  // Whether the find bar is currently visible.
-  BOOL _findBarVisible;
-
   // TODO(crbug.com/429955447): Remove when diamond prototype is cleaned.
   ToolbarType _diamondToolbarType;
   NSArray<NSLayoutConstraint*>* _diamondToolbarTopConstraints;
@@ -465,7 +462,7 @@
              BrowserViewVisibilityState::kCoveredByOmniboxPopup ||
          _visibilityState ==
              BrowserViewVisibilityState::kCoveredByVoiceSearch ||
-         _lensOverlayVisible || _findBarVisible;
+         _lensOverlayVisible;
 }
 
 - (void)setVisibilityState:(BrowserViewVisibilityState)state {
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/shop_card/shop_card_mediator.mm b/ios/chrome/browser/content_suggestions/ui_bundled/shop_card/shop_card_mediator.mm
index 3a30596..3a921c2 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/shop_card/shop_card_mediator.mm
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/shop_card/shop_card_mediator.mm
@@ -50,16 +50,6 @@
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/l10n/l10n_util_mac.h"
 
-namespace {
-
-int GetImpressionLimit() {
-  return base::GetFieldTrialParamByFeatureAsInt(
-      commerce::kShopCard, commerce::kShopCardMaxImpressions,
-      kShopCardMaxImpressions);
-}
-
-}  // namespace
-
 @interface ShopCardMediator () <ImpressionLimitServiceObserverBridgeDelegate,
                                 MagicStackModuleDelegate,
                                 PrefObserverDelegate,
@@ -425,7 +415,7 @@
   }
   std::optional<int> count = _impressionLimitService->GetImpressionCount(
       url, shop_card_prefs::kShopCardPriceDropUrlImpressions);
-  return count.has_value() && count.value() >= GetImpressionLimit();
+  return count.has_value() && count.value() >= kShopCardMaxImpressions;
 }
 
 - (BOOL)hasBeenOpened:(const GURL&)url {
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/tab_resumption/tab_resumption_egtest.mm b/ios/chrome/browser/content_suggestions/ui_bundled/tab_resumption/tab_resumption_egtest.mm
index c945de9..5c75afe 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/tab_resumption/tab_resumption_egtest.mm
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/tab_resumption/tab_resumption_egtest.mm
@@ -129,7 +129,7 @@
   // Relaunching the app undoes the mock setup for shopping_service in setUp
   // For the relaunch cases, explicitly disabling ShopCard so the tests can
   // continue without waiting for the async callback.
-  config.features_disabled.push_back(commerce::kShopCard);
+  config.features_disabled.push_back(commerce::kTabResumptionShopCard);
   [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
 }
 
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/tab_resumption/tab_resumption_mediator.mm b/ios/chrome/browser/content_suggestions/ui_bundled/tab_resumption/tab_resumption_mediator.mm
index 8a8a975d..60b2e834 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/tab_resumption/tab_resumption_mediator.mm
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/tab_resumption/tab_resumption_mediator.mm
@@ -287,7 +287,7 @@
 
 int GetImpressionLimit() {
   return base::GetFieldTrialParamByFeatureAsInt(
-      commerce::kShopCard, commerce::kShopCardMaxImpressions,
+      commerce::kTabResumptionShopCard, commerce::kShopCardMaxImpressions,
       kShopCardMaxImpressions);
 }
 
diff --git a/ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator_unittest.mm b/ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator_unittest.mm
index 518a4d5..4dc60bf 100644
--- a/ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator_unittest.mm
+++ b/ios/chrome/browser/drive_file_picker/coordinator/browse_drive_file_picker_coordinator_unittest.mm
@@ -46,6 +46,7 @@
     [dispatcher startDispatchingToTarget:handler_
                              forProtocol:@protocol(DriveFilePickerCommands)];
     fake_web_state_ = std::make_unique<web::FakeWebState>();
+    ChooseFileTabHelper::CreateForWebState(fake_web_state_.get());
     metrics_helper_ = [[DriveFilePickerMetricsHelper alloc] init];
     image_fetcher_ =
         std::make_unique<DriveFilePickerImageFetcher>(shared_factory_);
@@ -67,7 +68,7 @@
   // Starts file selection in the WebState.
   void StartChoosingFiles() {
     ChooseFileTabHelper* tab_helper =
-        ChooseFileTabHelper::GetOrCreateForWebState(fake_web_state_.get());
+        ChooseFileTabHelper::FromWebState(fake_web_state_.get());
     auto controller = std::make_unique<FakeChooseFileController>(
         ChooseFileEvent(false /*allow_multiple_files*/,
                         false /*has_selected_file*/, std::vector<std::string>{},
diff --git a/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator.mm b/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator.mm
index 8dad426..8c03b6e 100644
--- a/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator.mm
+++ b/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator.mm
@@ -114,7 +114,7 @@
     _fetchedDriveItems = {};
     // Initialize the list of accepted types.
     ChooseFileTabHelper* tab_helper =
-        ChooseFileTabHelper::GetOrCreateForWebState(webState);
+        ChooseFileTabHelper::FromWebState(webState);
     CHECK(tab_helper->IsChoosingFiles());
     const ChooseFileEvent& event = tab_helper->GetChooseFileEvent();
     _acceptedTypes = UTTypesAcceptedForEvent(event);
@@ -134,7 +134,8 @@
     _metricsHelper.searchingState = DriveFilePickerSearchState::kNotSearching;
     if (_collection->IsRoot()) {
       ChooseFileTabHelper* tab_helper =
-          ChooseFileTabHelper::GetOrCreateForWebState(_webState.get());
+          ChooseFileTabHelper::FromWebState(_webState.get());
+      CHECK(tab_helper);
       [_metricsHelper
           reportActivationMetricsForEvent:tab_helper->GetChooseFileEvent()];
     }
@@ -158,7 +159,9 @@
 - (void)disconnect {
   if (_collection->IsRoot() && _webState && !_webState->IsBeingDestroyed()) {
     ChooseFileTabHelper* tab_helper =
-        ChooseFileTabHelper::GetOrCreateForWebState(_webState.get());
+        ChooseFileTabHelper::FromWebState(_webState.get());
+
+    CHECK(tab_helper);
     if (tab_helper->IsChoosingFiles()) {
       tab_helper->StopChoosingFiles();
     }
@@ -346,7 +349,8 @@
     return;
   }
   ChooseFileTabHelper* tab_helper =
-      ChooseFileTabHelper::GetOrCreateForWebState(_webState.get());
+      ChooseFileTabHelper::FromWebState(_webState.get());
+  CHECK(tab_helper);
   if (!tab_helper->IsChoosingFiles()) {
     [self.driveFilePickerHandler hideDriveFilePicker];
     return;
@@ -745,7 +749,8 @@
       },
       weakSelf, fileURL, fileToDownload.identifier));
   ChooseFileTabHelper* tabHelper =
-      ChooseFileTabHelper::GetOrCreateForWebState(_webState.get());
+      ChooseFileTabHelper::FromWebState(_webState.get());
+  CHECK(tabHelper);
   tabHelper->CheckFileUrlReadyForSelection(
       fileURL, fileToDownload.modified_time,
       _fileVersionReadyCallback.callback());
@@ -803,7 +808,8 @@
           weakSelf, fileURL));
   // Inform the WebState that the destination URL isn't ready for selection yet.
   ChooseFileTabHelper* tabHelper =
-      ChooseFileTabHelper::GetOrCreateForWebState(_webState.get());
+      ChooseFileTabHelper::FromWebState(_webState.get());
+  CHECK(tabHelper);
   tabHelper->RemoveFileUrlReadyForSelection(fileURL);
 }
 
@@ -853,7 +859,8 @@
   // selection, pop the file from the queue and continue processing the download
   // queue.
   ChooseFileTabHelper* tabHelper =
-      ChooseFileTabHelper::GetOrCreateForWebState(_webState.get());
+      ChooseFileTabHelper::FromWebState(_webState.get());
+  CHECK(tabHelper);
   tabHelper->AddFileUrlReadyForSelection(
       fileURL, _downloadingQueue.front().modified_time);
   _downloadingQueue.pop();
diff --git a/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator_unittest.mm b/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator_unittest.mm
index 8550795..33eaf871 100644
--- a/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator_unittest.mm
+++ b/ios/chrome/browser/drive_file_picker/coordinator/drive_file_picker_mediator_unittest.mm
@@ -232,10 +232,11 @@
     images_pending_ = [NSMutableSet set];
     image_cache_ = [[NSCache alloc] init];
     web_state_ = std::make_unique<web::FakeWebState>();
+    ChooseFileTabHelper::CreateForWebState(web_state_.get());
     StartChoosingFiles();
     // Start file selection in `web_state_`.
     choose_file_tab_helper_ =
-        ChooseFileTabHelper::GetOrCreateForWebState(web_state_.get());
+        ChooseFileTabHelper::FromWebState(web_state_.get());
     auto controller = std::make_unique<FakeChooseFileController>(
         ChooseFileEvent(false /*allow_multiple_files*/,
                         false /*has_selected_file*/, std::vector<std::string>{},
@@ -298,7 +299,7 @@
   // Starts file selection in the WebState.
   void StartChoosingFiles() {
     ChooseFileTabHelper* tab_helper =
-        ChooseFileTabHelper::GetOrCreateForWebState(web_state_.get());
+        ChooseFileTabHelper::FromWebState(web_state_.get());
     auto controller = std::make_unique<FakeChooseFileController>(
         ChooseFileEvent(false /*allow_multiple_files*/,
                         false /*has_selected_file*/, std::vector<std::string>{},
diff --git a/ios/chrome/browser/drive_file_picker/coordinator/root_drive_file_picker_coordinator_unittest.mm b/ios/chrome/browser/drive_file_picker/coordinator/root_drive_file_picker_coordinator_unittest.mm
index 60284ad..ec7d548 100644
--- a/ios/chrome/browser/drive_file_picker/coordinator/root_drive_file_picker_coordinator_unittest.mm
+++ b/ios/chrome/browser/drive_file_picker/coordinator/root_drive_file_picker_coordinator_unittest.mm
@@ -44,6 +44,7 @@
     [dispatcher startDispatchingToTarget:handler_
                              forProtocol:@protocol(DriveFilePickerCommands)];
     fake_web_state_ = std::make_unique<web::FakeWebState>();
+    ChooseFileTabHelper::CreateForWebState(fake_web_state_.get());
     coordinator_ = [[RootDriveFilePickerCoordinator alloc]
         initWithBaseViewController:base_view_controller_
                            browser:browser_.get()
@@ -54,7 +55,7 @@
   // Starts file selection in the WebState.
   void StartChoosingFiles() {
     ChooseFileTabHelper* tab_helper =
-        ChooseFileTabHelper::GetOrCreateForWebState(fake_web_state_.get());
+        ChooseFileTabHelper::FromWebState(fake_web_state_.get());
     auto controller = std::make_unique<FakeChooseFileController>(
         ChooseFileEvent(false /*allow_multiple_files*/,
                         false /*has_selected_file*/, std::vector<std::string>{},
diff --git a/ios/chrome/browser/drive_file_picker/test/drive_file_picker_app_interface.mm b/ios/chrome/browser/drive_file_picker/test/drive_file_picker_app_interface.mm
index 06d52be..46b3cc6 100644
--- a/ios/chrome/browser/drive_file_picker/test/drive_file_picker_app_interface.mm
+++ b/ios/chrome/browser/drive_file_picker/test/drive_file_picker_app_interface.mm
@@ -32,8 +32,8 @@
 + (void)startChoosingSingleFileInCurrentWebState {
   Browser* currentBrowser = chrome_test_util::GetCurrentBrowser();
   WebStateList* webStateList = currentBrowser->GetWebStateList();
-  ChooseFileTabHelper* tab_helper = ChooseFileTabHelper::GetOrCreateForWebState(
-      webStateList->GetActiveWebState());
+  ChooseFileTabHelper* tab_helper =
+      ChooseFileTabHelper::FromWebState(webStateList->GetActiveWebState());
   auto controller = std::make_unique<FakeChooseFileController>(ChooseFileEvent(
       false /*allow_multiple_files*/, false /*has_selected_file*/,
       std::vector<std::string>{}, std::vector<std::string>{},
@@ -44,8 +44,8 @@
 + (void)startChoosingMultipleFilesInCurrentWebState {
   Browser* currentBrowser = chrome_test_util::GetCurrentBrowser();
   WebStateList* webStateList = currentBrowser->GetWebStateList();
-  ChooseFileTabHelper* tab_helper = ChooseFileTabHelper::GetOrCreateForWebState(
-      webStateList->GetActiveWebState());
+  ChooseFileTabHelper* tab_helper =
+      ChooseFileTabHelper::FromWebState(webStateList->GetActiveWebState());
   auto controller = std::make_unique<FakeChooseFileController>(ChooseFileEvent(
       true /*allow_multiple_files*/, false /*has_selected_file*/,
       std::vector<std::string>{}, std::vector<std::string>{},
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index 9c6417b..89eaa5f 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -660,12 +660,6 @@
 };
 
 // ShopCard variants
-const FeatureEntry::FeatureParam kPriceDropForTrackedProductsArm[] = {
-    {"ShopCardVariant", "arm_1"},
-};
-const FeatureEntry::FeatureParam kReviewsArm[] = {
-    {"ShopCardVariant", "arm_2"},
-};
 const FeatureEntry::FeatureParam kPriceDropOnTabArm[] = {
     {"ShopCardVariant", "arm_3"},
 };
@@ -675,17 +669,6 @@
 const FeatureEntry::FeatureParam kTabResumptionWithImpressionLimitsArm[] = {
     {"ShopCardVariant", "arm_5"},
 };
-const FeatureEntry::FeatureParam kArm1Arm3[] = {
-    {"ShopCardVariant", "arm_1_arm_3"},
-};
-const FeatureEntry::FeatureParam kPriceDropForTrackedProductsFront[] = {
-    {"ShopCardVariant", "arm_1"},
-    {"ShopCardPosition", "shop_card_front"},
-};
-const FeatureEntry::FeatureParam kReviewsFrontt[] = {
-    {"ShopCardVariant", "arm_2"},
-    {"ShopCardPosition", "shop_card_front"},
-};
 const FeatureEntry::FeatureParam kPriceDropOnTabFront[] = {
     {"ShopCardVariant", "arm_3"},
     {"ShopCardPosition", "shop_card_front"},
@@ -801,9 +784,6 @@
 
 // ShopCard experiment arms
 const FeatureEntry::FeatureVariation kShopCardOverrideOptions[] = {
-    {"Card 1 Price Drop", kPriceDropForTrackedProductsArm,
-     std::size(kPriceDropForTrackedProductsArm), "3393098"},
-    {"Card 2 Reviews", kReviewsArm, std::size(kReviewsArm), nullptr},
     {"Card 3 Price Drop on Tab Resumption", kPriceDropOnTabArm,
      std::size(kPriceDropOnTabArm), nullptr},
     {"Card 4 Price Trackable on Tab Resumption", kPriceTrackableProductOnTabArm,
@@ -811,12 +791,6 @@
     {"Card 5 Tab Resumption with Impression Limits",
      kTabResumptionWithImpressionLimitsArm,
      std::size(kTabResumptionWithImpressionLimitsArm), nullptr},
-    {"Card 1 & 3 combined", kArm1Arm3, std::size(kArm1Arm3), "3393098"},
-    {"Card 1 Price Drop at front of magic stack",
-     kPriceDropForTrackedProductsFront,
-     std::size(kPriceDropForTrackedProductsFront), nullptr},
-    {"Card 2 Reviews at front of magic stack", kReviewsFrontt,
-     std::size(kReviewsFrontt), nullptr},
     {"Card 3 Price Drop on Tab Resumption at front of magic stack",
      kPriceDropOnTabFront, std::size(kPriceDropOnTabFront), nullptr},
     {"Card 4 Price Trackable on Tab Resumption at front of magic stack",
@@ -1862,10 +1836,6 @@
      flag_descriptions::kOnlyAccessClipboardAsyncName,
      flag_descriptions::kOnlyAccessClipboardAsyncDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kOnlyAccessClipboardAsync)},
-    {"enable-signed-out-view-demotion",
-     flag_descriptions::kEnableSignedOutViewDemotionName,
-     flag_descriptions::kEnableSignedOutViewDemotionDescription,
-     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kEnableSignedOutViewDemotion)},
     {"spotlight-never-retain-index",
      flag_descriptions::kSpotlightNeverRetainIndexName,
      flag_descriptions::kSpotlightNeverRetainIndexDescription, flags_ui::kOsIos,
@@ -2123,9 +2093,9 @@
      FEATURE_VALUE_TYPE(commerce::kPriceTrackingPromo)},
     {"ios-shop-card", flag_descriptions::kShopCardName,
      flag_descriptions::kShopCardDescription, flags_ui::kOsIos,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(commerce::kShopCard,
+     FEATURE_WITH_PARAMS_VALUE_TYPE(commerce::kTabResumptionShopCard,
                                     kShopCardOverrideOptions,
-                                    "ShopCard")},
+                                    "TabResumptionShopCard")},
     {"ios-shop-card-impression-limits",
      flag_descriptions::kShopCardImpressionLimitsName,
      flag_descriptions::kShopCardImpressionLimitsDescription, flags_ui::kOsIos,
@@ -2872,6 +2842,10 @@
      flag_descriptions::kTabSwitcherOverflowMenuName,
      flag_descriptions::kTabSwitcherOverflowMenuDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kTabSwitcherOverflowMenu)},
+    {"cache-identity-list-in-chrome",
+     flag_descriptions::kCacheIdentityListInChromeName,
+     flag_descriptions::kCacheIdentityListInChromeDescription, flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(switches::kCacheIdentityListInChrome)},
 };
 
 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 21f7b32..7a6e9c9 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -597,12 +597,6 @@
 const char kEnableReadingListSignInPromoDescription[] =
     "Enable the sign-in promo view in the reading list screen.";
 
-const char kEnableSignedOutViewDemotionName[] =
-    "Enable signed out user view demotion";
-const char kEnableSignedOutViewDemotionDescription[] =
-    "Enable signed out user view demotion to avoid repeated content for signed "
-    "out users.";
-
 const char kEnableIdentityInAuthErrorName[] = "Enable Identities in Auth Error";
 const char kEnableIdentityInAuthErrorDescription[] =
     "Enable identities in auth error state.";
@@ -720,6 +714,11 @@
 const char kIOSCustomFileUploadMenuDescription[] =
     "Enables the custom file upload menu implementation.";
 
+const char kCacheIdentityListInChromeName[] = "Cache identity list in chrome.";
+const char kCacheIdentityListInChromeDescription[] =
+    "Changes the implementation of the cache of the list of identities on "
+    "device.";
+
 const char kIOSDockingPromoName[] = "Docking Promo";
 const char kIOSDockingPromoDescription[] =
     "When enabled, the user will be presented an animated, instructional "
@@ -1521,9 +1520,9 @@
 const char kShareInWebContextMenuIOSDescription[] =
     "Enables the Share button in the web context menu in iOS 16.0 and above.";
 
-const char kShopCardName[] = "Enables ShopCard";
+const char kShopCardName[] = "Enables Tab Resumption ShopCard";
 const char kShopCardDescription[] =
-    "Enables being able to show ShopCard in the Magic Stack";
+    "Enables being able to show Tab Resumption ShopCard in the Magic Stack";
 
 const char kShopCardImpressionLimitsName[] =
     "Enables ShopCard Impression limits";
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index 992fedc3..0362e80f 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -342,9 +342,6 @@
 extern const char kEnableReadingListSignInPromoName[];
 extern const char kEnableReadingListSignInPromoDescription[];
 
-extern const char kEnableSignedOutViewDemotionName[];
-extern const char kEnableSignedOutViewDemotionDescription[];
-
 extern const char kEnableIdentityInAuthErrorName[];
 extern const char kEnableIdentityInAuthErrorDescription[];
 
@@ -417,6 +414,9 @@
 extern const char kIOSCustomFileUploadMenuName[];
 extern const char kIOSCustomFileUploadMenuDescription[];
 
+extern const char kCacheIdentityListInChromeName[];
+extern const char kCacheIdentityListInChromeDescription[];
+
 extern const char kIOSDockingPromoName[];
 extern const char kIOSDockingPromoDescription[];
 
diff --git a/ios/chrome/browser/lens_overlay/ui/lens_overlay_results_page_presenter.mm b/ios/chrome/browser/lens_overlay/ui/lens_overlay_results_page_presenter.mm
index af49a2c..661cf2dc 100644
--- a/ios/chrome/browser/lens_overlay/ui/lens_overlay_results_page_presenter.mm
+++ b/ios/chrome/browser/lens_overlay/ui/lens_overlay_results_page_presenter.mm
@@ -242,7 +242,8 @@
   // To prevent such a behavior, extract the recognizers added as a consequence
   // of presenting and allow touches to be delivered to views.
   __block NSSet<UIGestureRecognizer*>* panRecognizersBeforePresenting =
-      [self panGestureRecognizersOnWindow];
+      UseCustomLensOverlayBottomSheet() ? [[NSSet alloc] init]
+                                        : [self panGestureRecognizersOnWindow];
 
   [self setUpVisibleAreaLayoutGuideIfNeeded];
   [self monitorResultsBottomSheetPosition];
@@ -257,7 +258,10 @@
 
   ProceduralBlock afterPresentation = ^{
     [weakSelf resultsPagePresentationDidAppear];
-    [weakSelf handlePanRecognizersAddedAfter:panRecognizersBeforePresenting];
+    if (!UseCustomLensOverlayBottomSheet()) {
+      [weakSelf handlePanRecognizersAddedAfter:panRecognizersBeforePresenting];
+    }
+
     if (completion) {
       completion();
     }
diff --git a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_feature.h b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_feature.h
index 2420549..29fa0776 100644
--- a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_feature.h
+++ b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_feature.h
@@ -62,9 +62,6 @@
 // Feature flag to enable sending discover feedback to an updated target
 BASE_DECLARE_FEATURE(kWebFeedFeedbackReroute);
 
-// Feature flag to enable signed out user view demotion.
-BASE_DECLARE_FEATURE(kEnableSignedOutViewDemotion);
-
 // Feature flag to enable ghost cards on the iPad feeds.
 BASE_DECLARE_FEATURE(kEnableiPadFeedGhostCards);
 
diff --git a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_feature.mm b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_feature.mm
index 8cf9d39..3e44e5d 100644
--- a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_feature.mm
+++ b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_feature.mm
@@ -44,8 +44,6 @@
 
 BASE_FEATURE(kWebFeedFeedbackReroute, base::FEATURE_ENABLED_BY_DEFAULT);
 
-BASE_FEATURE(kEnableSignedOutViewDemotion, base::FEATURE_DISABLED_BY_DEFAULT);
-
 BASE_FEATURE(kEnableiPadFeedGhostCards, base::FEATURE_DISABLED_BY_DEFAULT);
 
 BASE_FEATURE(kFeedSwipeInProductHelp, base::FEATURE_DISABLED_BY_DEFAULT);
@@ -99,7 +97,7 @@
 }
 
 bool IsSignedOutViewDemotionEnabled() {
-  return base::FeatureList::IsEnabled(kEnableSignedOutViewDemotion);
+  return NO;
 }
 
 bool IsiPadFeedGhostCardsEnabled() {
diff --git a/ios/chrome/browser/shared/ui/table_view/cells/BUILD.gn b/ios/chrome/browser/shared/ui/table_view/cells/BUILD.gn
index 3d843483..7500de5 100644
--- a/ios/chrome/browser/shared/ui/table_view/cells/BUILD.gn
+++ b/ios/chrome/browser/shared/ui/table_view/cells/BUILD.gn
@@ -10,6 +10,7 @@
     "table_view_cell.mm",
   ]
   deps = [
+    "//ios/chrome/browser/shared/ui/table_view/content_configuration:generic_content",
     "//ios/chrome/browser/shared/ui/util",
     "//ios/chrome/common/ui/colors",
     "//ios/chrome/common/ui/table_view:cells_constants",
diff --git a/ios/chrome/browser/shared/ui/table_view/cells/legacy_table_view_cell.mm b/ios/chrome/browser/shared/ui/table_view/cells/legacy_table_view_cell.mm
index 3f9b383..020a1aa 100644
--- a/ios/chrome/browser/shared/ui/table_view/cells/legacy_table_view_cell.mm
+++ b/ios/chrome/browser/shared/ui/table_view/cells/legacy_table_view_cell.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/shared/ui/table_view/cells/legacy_table_view_cell.h"
 
+#import "ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_view.h"
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/table_view/table_view_cells_constants.h"
@@ -76,4 +77,15 @@
   return accessibilityTraits;
 }
 
+- (CGPoint)accessibilityActivationPoint {
+  if ([self.contentView conformsToProtocol:@protocol(ChromeContentView)]) {
+    UIView<ChromeContentView>* chromeContentView =
+        static_cast<UIView<ChromeContentView>*>(self.contentView);
+    if ([chromeContentView hasCustomAccessibilityActivationPoint]) {
+      return chromeContentView.accessibilityActivationPoint;
+    }
+  }
+  return [super accessibilityActivationPoint];
+}
+
 @end
diff --git a/ios/chrome/browser/shared/ui/table_view/cells/table_view_cell.mm b/ios/chrome/browser/shared/ui/table_view/cells/table_view_cell.mm
index 2ebdc61..eb0dc11 100644
--- a/ios/chrome/browser/shared/ui/table_view/cells/table_view_cell.mm
+++ b/ios/chrome/browser/shared/ui/table_view/cells/table_view_cell.mm
@@ -4,10 +4,9 @@
 
 #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_cell.h"
 
-@implementation TableViewCell {
-  NSString* _accessibilityLabel;
-  NSArray<NSString*>* _accessibilityUserInputLabels;
-}
+#import "ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_view.h"
+
+@implementation TableViewCell
 
 #pragma mark - UITableViewCell
 
@@ -15,26 +14,35 @@
   [super prepareForReuse];
   self.accessoryType = UITableViewCellAccessoryNone;
   self.accessibilityLabel = nil;
+  self.accessibilityHint = nil;
+  self.accessibilityValue = nil;
   self.accessibilityUserInputLabels = nil;
 }
 
 #pragma mark - Accessibility
 
-- (void)setAccessibilityLabel:(NSString*)accessibilityLabel {
-  _accessibilityLabel = accessibilityLabel;
-}
-
 - (NSString*)accessibilityLabel {
   NSObject* contentConfiguration = self.contentConfiguration;
   if (contentConfiguration.accessibilityLabel) {
     return contentConfiguration.accessibilityLabel;
   }
-  return _accessibilityLabel;
+  return [super accessibilityLabel];
 }
 
-- (void)setAccessibilityUserInputLabels:
-    (NSArray<NSString*>*)accessibilityUserInputLabels {
-  _accessibilityUserInputLabels = accessibilityUserInputLabels;
+- (NSString*)accessibilityValue {
+  NSObject* contentConfiguration = self.contentConfiguration;
+  if (contentConfiguration.accessibilityValue) {
+    return contentConfiguration.accessibilityValue;
+  }
+  return [super accessibilityValue];
+}
+
+- (NSString*)accessibilityHint {
+  NSObject* contentConfiguration = self.contentConfiguration;
+  if (contentConfiguration.accessibilityHint) {
+    return contentConfiguration.accessibilityHint;
+  }
+  return [super accessibilityHint];
 }
 
 - (NSArray<NSString*>*)accessibilityUserInputLabels {
@@ -42,7 +50,18 @@
   if (contentConfiguration.accessibilityUserInputLabels) {
     return contentConfiguration.accessibilityUserInputLabels;
   }
-  return _accessibilityUserInputLabels;
+  return [super accessibilityUserInputLabels];
+}
+
+- (CGPoint)accessibilityActivationPoint {
+  if ([self.contentView conformsToProtocol:@protocol(ChromeContentView)]) {
+    UIView<ChromeContentView>* chromeContentView =
+        static_cast<UIView<ChromeContentView>*>(self.contentView);
+    if ([chromeContentView hasCustomAccessibilityActivationPoint]) {
+      return chromeContentView.accessibilityActivationPoint;
+    }
+  }
+  return [super accessibilityActivationPoint];
 }
 
 @end
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/BUILD.gn b/ios/chrome/browser/shared/ui/table_view/content_configuration/BUILD.gn
index 6e885d7..11990f8 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/BUILD.gn
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/BUILD.gn
@@ -22,10 +22,20 @@
     "table_view_cell_content_view.mm",
   ]
   deps = [
+    ":generic_content",
     "//base",
+    "//ios/chrome/app/strings",
     "//ios/chrome/browser/shared/ui/table_view/cells:generic_cells",
     "//ios/chrome/common/ui/colors",
     "//ios/chrome/common/ui/table_view:cells_constants",
     "//ios/chrome/common/ui/util",
+    "//ui/base",
+  ]
+}
+
+source_set("generic_content") {
+  sources = [
+    "chrome_content_configuration.h",
+    "chrome_content_view.h",
   ]
 }
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_configuration.h b/ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_configuration.h
new file mode 100644
index 0000000..8e0b37f
--- /dev/null
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_configuration.h
@@ -0,0 +1,20 @@
+// 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_SHARED_UI_TABLE_VIEW_CONTENT_CONFIGURATION_CHROME_CONTENT_CONFIGURATION_H_
+#define IOS_CHROME_BROWSER_SHARED_UI_TABLE_VIEW_CONTENT_CONFIGURATION_CHROME_CONTENT_CONFIGURATION_H_
+
+#import <UIKit/UIKit.h>
+
+@protocol ChromeContentView;
+
+// Protocol to specialize UIContentConfiguration to Chrome needs.
+@protocol ChromeContentConfiguration <UIContentConfiguration>
+
+// This is the same method as `makeContentView`, but with a more specific type.
+- (UIView<ChromeContentView>*)makeChromeContentView;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_SHARED_UI_TABLE_VIEW_CONTENT_CONFIGURATION_CHROME_CONTENT_CONFIGURATION_H_
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_view.h b/ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_view.h
new file mode 100644
index 0000000..ffcb384
--- /dev/null
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_view.h
@@ -0,0 +1,19 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_SHARED_UI_TABLE_VIEW_CONTENT_CONFIGURATION_CHROME_CONTENT_VIEW_H_
+#define IOS_CHROME_BROWSER_SHARED_UI_TABLE_VIEW_CONTENT_CONFIGURATION_CHROME_CONTENT_VIEW_H_
+
+#import <UIKit/UIKit.h>
+
+// Protocol to speciliaze UIContentView to Chrome needs.
+@protocol ChromeContentView <UIContentView>
+
+// Returns whether this view has a custom accessibility activation point that
+// should be used instead of the default.
+- (BOOL)hasCustomAccessibilityActivationPoint;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_SHARED_UI_TABLE_VIEW_CONTENT_CONFIGURATION_CHROME_CONTENT_VIEW_H_
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/colorful_symbol_content_configuration.h b/ios/chrome/browser/shared/ui/table_view/content_configuration/colorful_symbol_content_configuration.h
index 8c46735a..60072bf1 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/colorful_symbol_content_configuration.h
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/colorful_symbol_content_configuration.h
@@ -7,9 +7,11 @@
 
 #import <UIKit/UIKit.h>
 
+#import "ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_configuration.h"
+
 // A content configuration for a symbol image view with a colorful background.
 @interface ColorfulSymbolContentConfiguration
-    : NSObject <UIContentConfiguration>
+    : NSObject <ChromeContentConfiguration>
 
 // The updates to properties must be reflected in the copy method.
 // LINT.IfChange(Copy)
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/colorful_symbol_content_configuration.mm b/ios/chrome/browser/shared/ui/table_view/content_configuration/colorful_symbol_content_configuration.mm
index f31acf23..732ba464 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/colorful_symbol_content_configuration.mm
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/colorful_symbol_content_configuration.mm
@@ -8,8 +8,25 @@
 
 @implementation ColorfulSymbolContentConfiguration
 
+#pragma mark - ChromeContentConfiguration
+
+- (UIView<ChromeContentView>*)makeChromeContentView {
+  return [[ColorfulSymbolContentView alloc] initWithConfiguration:self];
+}
+
 #pragma mark - UIContentConfiguration
 
+- (UIView*)makeContentView {
+  return [self makeChromeContentView];
+}
+
+- (id<UIContentConfiguration>)updatedConfigurationForState:
+    (id<UIConfigurationState>)state {
+  return self;
+}
+
+#pragma mark - NSCopying
+
 - (instancetype)copyWithZone:(NSZone*)zone {
   ColorfulSymbolContentConfiguration* copy =
       [[self.class allocWithZone:zone] init];
@@ -22,13 +39,4 @@
   return copy;
 }
 
-- (id<UIContentConfiguration>)updatedConfigurationForState:
-    (id<UIConfigurationState>)state {
-  return self;
-}
-
-- (UIView*)makeContentView {
-  return [[ColorfulSymbolContentView alloc] initWithConfiguration:self];
-}
-
 @end
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/colorful_symbol_content_view.h b/ios/chrome/browser/shared/ui/table_view/content_configuration/colorful_symbol_content_view.h
index ba63503..ab64a47 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/colorful_symbol_content_view.h
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/colorful_symbol_content_view.h
@@ -7,10 +7,12 @@
 
 #import <UIKit/UIKit.h>
 
+#import "ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_view.h"
+
 @class ColorfulSymbolContentConfiguration;
 
 // A content view for a symbol image view with a colorful background.
-@interface ColorfulSymbolContentView : UIView <UIContentView>
+@interface ColorfulSymbolContentView : UIView <ChromeContentView>
 
 - (instancetype)initWithConfiguration:
     (ColorfulSymbolContentConfiguration*)configuration
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/colorful_symbol_content_view.mm b/ios/chrome/browser/shared/ui/table_view/content_configuration/colorful_symbol_content_view.mm
index 55a1acc..a9660ff 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/colorful_symbol_content_view.mm
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/colorful_symbol_content_view.mm
@@ -55,6 +55,12 @@
   return self;
 }
 
+#pragma mark - ChromeContentView
+
+- (BOOL)hasCustomAccessibilityActivationPoint {
+  return NO;
+}
+
 #pragma mark - UIContentView
 
 - (id<UIContentConfiguration>)configuration {
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/image_content_configuration.h b/ios/chrome/browser/shared/ui/table_view/content_configuration/image_content_configuration.h
index 1f8585a..2b8943b 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/image_content_configuration.h
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/image_content_configuration.h
@@ -7,8 +7,10 @@
 
 #import <UIKit/UIKit.h>
 
+#import "ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_configuration.h"
+
 // A content configuration for an image view.
-@interface ImageContentConfiguration : NSObject <UIContentConfiguration>
+@interface ImageContentConfiguration : NSObject <ChromeContentConfiguration>
 
 // LINT.IfChange(Copy)
 
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/image_content_configuration.mm b/ios/chrome/browser/shared/ui/table_view/content_configuration/image_content_configuration.mm
index 84bb071d..3c91baa8 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/image_content_configuration.mm
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/image_content_configuration.mm
@@ -16,14 +16,19 @@
   return self;
 }
 
-#pragma mark - UIContentConfiguration
+#pragma mark - ChromeContentConfiguration
 
-- (UIView<UIContentView>*)makeContentView {
+- (UIView<ChromeContentView>*)makeChromeContentView {
   return [[ImageContentView alloc] initWithConfiguration:self];
 }
 
+#pragma mark - UIContentConfiguration
+
+- (id<UIContentView>)makeContentView {
+  return [self makeChromeContentView];
+}
+
 - (instancetype)updatedConfigurationForState:(id<UIConfigurationState>)state {
-  // No state changes supported for now.
   return self;
 }
 
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/image_content_view.h b/ios/chrome/browser/shared/ui/table_view/content_configuration/image_content_view.h
index 09c6723..7189849 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/image_content_view.h
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/image_content_view.h
@@ -7,10 +7,12 @@
 
 #import <UIKit/UIKit.h>
 
+#import "ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_view.h"
+
 @class ImageContentConfiguration;
 
 // A content view for an image view.
-@interface ImageContentView : UIImageView <UIContentView>
+@interface ImageContentView : UIImageView <ChromeContentView>
 
 - (instancetype)initWithConfiguration:(ImageContentConfiguration*)configuration
     NS_DESIGNATED_INITIALIZER;
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/image_content_view.mm b/ios/chrome/browser/shared/ui/table_view/content_configuration/image_content_view.mm
index 8c9c7fb..57765e67 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/image_content_view.mm
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/image_content_view.mm
@@ -37,6 +37,12 @@
   return self;
 }
 
+#pragma mark - ChromeContentView
+
+- (BOOL)hasCustomAccessibilityActivationPoint {
+  return NO;
+}
+
 #pragma mark - UIContentView
 
 - (id<UIContentConfiguration>)configuration {
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_configuration.h b/ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_configuration.h
index 503665e..48953f9 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_configuration.h
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_configuration.h
@@ -7,10 +7,12 @@
 
 #import <UIKit/UIKit.h>
 
+#import "ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_configuration.h"
+
 @class SwitchContentView;
 
 // Content configuration for a view with a single switch.
-@interface SwitchContentConfiguration : NSObject <UIContentConfiguration>
+@interface SwitchContentConfiguration : NSObject <ChromeContentConfiguration>
 
 // The updates to properties must be reflected in the copy method.
 // LINT.IfChange(Copy)
@@ -22,6 +24,9 @@
 // Whether the switch is on by default. Default it NO.
 @property(nonatomic, assign) BOOL on;
 
+// Whether the switch is enabled. Default is YES.
+@property(nonatomic, assign) BOOL enabled;
+
 // The tag for the switch.
 @property(nonatomic, assign) NSInteger tag;
 
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_configuration.mm b/ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_configuration.mm
index 561d0373..26f5adc 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_configuration.mm
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_configuration.mm
@@ -5,13 +5,29 @@
 #import "ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_configuration.h"
 
 #import "ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_view.h"
+#import "ios/chrome/grit/ios_strings.h"
+#import "ui/base/l10n/l10n_util_mac.h"
 
 @implementation SwitchContentConfiguration
 
+- (instancetype)init {
+  self = [super init];
+  if (self) {
+    _enabled = YES;
+  }
+  return self;
+}
+
+#pragma mark - ChromeContentConfiguration
+
+- (UIView<ChromeContentView>*)makeChromeContentView {
+  return [[SwitchContentView alloc] initWithConfiguration:self];
+}
+
 #pragma mark - UIContentConfiguration
 
 - (id<UIContentView>)makeContentView {
-  return [[SwitchContentView alloc] initWithConfiguration:self];
+  return [self makeChromeContentView];
 }
 
 - (instancetype)updatedConfigurationForState:(id<UIConfigurationState>)state {
@@ -26,9 +42,27 @@
   configuration.target = self.target;
   configuration.selector = self.selector;
   configuration.on = self.on;
+  configuration.enabled = self.enabled;
   configuration.tag = self.tag;
   // LINT.ThenChange(switch_content_configuration.h:Copy)
   return configuration;
 }
 
+#pragma mark - Accessibility
+
+- (NSString*)accessibilityHint {
+  if (self.enabled) {
+    return l10n_util::GetNSString(IDS_IOS_TOGGLE_SWITCH_ACCESSIBILITY_HINT);
+  }
+  return nil;
+}
+
+- (NSString*)accessibilityValue {
+  if (self.on) {
+    return l10n_util::GetNSString(IDS_IOS_SETTING_ON);
+  } else {
+    return l10n_util::GetNSString(IDS_IOS_SETTING_OFF);
+  }
+}
+
 @end
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_view.h b/ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_view.h
index dd7423d..05bb504 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_view.h
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_view.h
@@ -7,10 +7,12 @@
 
 #import <UIKit/UIKit.h>
 
+#import "ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_view.h"
+
 @class SwitchContentConfiguration;
 
 // A view that displays a single switch, leading-aligned.
-@interface SwitchContentView : UIView <UIContentView>
+@interface SwitchContentView : UIView <ChromeContentView>
 
 // Returns the view, configured with `configuration`.
 - (instancetype)initWithConfiguration:
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_view.mm b/ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_view.mm
index 356af52..6753c91 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_view.mm
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/switch_content_view.mm
@@ -33,6 +33,12 @@
   return self;
 }
 
+#pragma mark - ChromeContentView
+
+- (BOOL)hasCustomAccessibilityActivationPoint {
+  return YES;
+}
+
 #pragma mark - UIContentView
 
 - (id<UIContentConfiguration>)configuration {
@@ -50,6 +56,16 @@
   return [configuration isMemberOfClass:SwitchContentConfiguration.class];
 }
 
+#pragma mark - UIAccessibility
+
+- (CGPoint)accessibilityActivationPoint {
+  CGRect frameInScreenCoordinates =
+      UIAccessibilityConvertFrameToScreenCoordinates(_switchView.bounds,
+                                                     _switchView);
+  return CGPointMake(CGRectGetMidX(frameInScreenCoordinates),
+                     CGRectGetMidY(frameInScreenCoordinates));
+}
+
 #pragma mark - Private
 
 // Updates the content view with the current configuration.
@@ -62,6 +78,7 @@
         forControlEvents:UIControlEventValueChanged];
   _switchView.tag = _configuration.tag;
   _switchView.on = _configuration.on;
+  _switchView.enabled = _configuration.enabled;
 }
 
 @end
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_configuration.h b/ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_configuration.h
index b5b164a..62a78049 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_configuration.h
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_configuration.h
@@ -7,27 +7,33 @@
 
 #import <UIKit/UIKit.h>
 
+@protocol ChromeContentConfiguration;
 @class TableViewCell;
 @class LegacyTableViewCell;
 
 // Configuration object for a TableView cell.
 // It is using a TableViewCellContentView as content view.
-// +---------------------------------------------+
-// |           TableViewCellContentView          |
-// |                                             |
-// |  title                       trailing label |
-// |  subtitle                                   |
-// |                                             |
-// +---------------------------------------------+
+// +------------------------------------------------------------------+
+// |                     TableViewCellContentView                     |
+// |                                                                  |
+// | +-----------+                                   +-----------+    |
+// | | Leading   |  Title                            | Trailing  |    |
+// | | View      |                    Trailing Label | View      |    |
+// | |(Optional) |  Subtitle                         |(Optional) |    |
+// | +-----------+                                   +-----------+    |
+// |                                                                  |
+// +------------------------------------------------------------------+
 @interface TableViewCellContentConfiguration : NSObject <UIContentConfiguration>
 
 // The updates to properties must be reflected in the copy method.
 // LINT.IfChange(Copy)
 
 // The leading content configuration for the cell.
-@property(nonatomic, copy) id<UIContentConfiguration> leadingConfiguration;
+@property(nonatomic, copy)
+    NSObject<ChromeContentConfiguration>* leadingConfiguration;
 // The trailing content configuration for the cell.
-@property(nonatomic, copy) id<UIContentConfiguration> trailingConfiguration;
+@property(nonatomic, copy)
+    NSObject<ChromeContentConfiguration>* trailingConfiguration;
 
 // Whether the labels should be disabled (change text color). Default NO.
 @property(nonatomic, assign, getter=isTextDisabled) BOOL textDisabled;
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_configuration.mm b/ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_configuration.mm
index 449aceb..9696aa36 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_configuration.mm
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_configuration.mm
@@ -6,6 +6,7 @@
 
 #import "ios/chrome/browser/shared/ui/table_view/cells/legacy_table_view_cell.h"
 #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_cell.h"
+#import "ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_configuration.h"
 #import "ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_view.h"
 
 @implementation TableViewCellContentConfiguration
@@ -101,4 +102,24 @@
   return @[ self.title ];
 }
 
+- (NSString*)accessibilityHint {
+  if (self.trailingConfiguration.accessibilityHint) {
+    return self.trailingConfiguration.accessibilityHint;
+  }
+  if (self.leadingConfiguration.accessibilityHint) {
+    return self.leadingConfiguration.accessibilityHint;
+  }
+  return [super accessibilityHint];
+}
+
+- (NSString*)accessibilityValue {
+  if (self.trailingConfiguration.accessibilityValue) {
+    return self.trailingConfiguration.accessibilityValue;
+  }
+  if (self.leadingConfiguration.accessibilityValue) {
+    return self.leadingConfiguration.accessibilityValue;
+  }
+  return [super accessibilityValue];
+}
+
 @end
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_view.h b/ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_view.h
index 42cd4cd..90d917e 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_view.h
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_view.h
@@ -7,9 +7,11 @@
 
 #import <UIKit/UIKit.h>
 
+#import "ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_view.h"
+
 @class TableViewCellContentConfiguration;
 
-@interface TableViewCellContentView : UIView <UIContentView>
+@interface TableViewCellContentView : UIView <ChromeContentView>
 
 /// Initializes with `configuration`.
 - (instancetype)initWithConfiguration:
diff --git a/ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_view.mm b/ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_view.mm
index fbe7a09..17f142b1 100644
--- a/ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_view.mm
+++ b/ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_view.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_view.h"
 
 #import "base/apple/foundation_util.h"
+#import "ios/chrome/browser/shared/ui/table_view/content_configuration/chrome_content_configuration.h"
 #import "ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_configuration.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/table_view/table_view_cells_constants.h"
@@ -71,9 +72,9 @@
   TableViewCellContentConfiguration* _configuration;
 
   // The leading content view.
-  UIView<UIContentView>* _leadingContentView;
+  UIView<ChromeContentView>* _leadingContentView;
   // The trailing content view.
-  UIView<UIContentView>* _trailingContentView;
+  UIView<ChromeContentView>* _trailingContentView;
   // The container for the leading content view.
   UIView* _leadingContentViewContainer;
   // The container for the trailing content view.
@@ -110,6 +111,13 @@
   return self;
 }
 
+#pragma mark - ChromeContentView
+
+- (BOOL)hasCustomAccessibilityActivationPoint {
+  return [_leadingContentView hasCustomAccessibilityActivationPoint] ||
+         [_trailingContentView hasCustomAccessibilityActivationPoint];
+}
+
 #pragma mark - UIContentView
 
 - (id<UIContentConfiguration>)configuration {
@@ -133,7 +141,7 @@
 
 // Updates the elements based on a new configuration.
 - (void)applyConfiguration {
-  id<UIContentConfiguration> leadingConfiguration =
+  id<ChromeContentConfiguration> leadingConfiguration =
       _configuration.leadingConfiguration;
   BOOL isLeadingImageContentViewCompatible =
       [_leadingContentView
@@ -150,14 +158,14 @@
     if (_leadingContentView) {
       _leadingContentView.configuration = leadingConfiguration;
     } else {
-      _leadingContentView = [leadingConfiguration makeContentView];
+      _leadingContentView = [leadingConfiguration makeChromeContentView];
       _leadingContentView.translatesAutoresizingMaskIntoConstraints = NO;
       [_leadingContentViewContainer addSubview:_leadingContentView];
       AddSameConstraints(_leadingContentView, _leadingContentViewContainer);
     }
   }
 
-  id<UIContentConfiguration> trailingConfiguration =
+  id<ChromeContentConfiguration> trailingConfiguration =
       _configuration.trailingConfiguration;
   BOOL isTrailingImageContentViewCompatible =
       [_trailingContentView
@@ -174,7 +182,7 @@
     if (_trailingContentView) {
       _trailingContentView.configuration = trailingConfiguration;
     } else {
-      _trailingContentView = [trailingConfiguration makeContentView];
+      _trailingContentView = [trailingConfiguration makeChromeContentView];
       _trailingContentView.translatesAutoresizingMaskIntoConstraints = NO;
       [_trailingContentViewContainer addSubview:_trailingContentView];
       AddSameConstraints(_trailingContentView, _trailingContentViewContainer);
@@ -382,4 +390,16 @@
   return stack;
 }
 
+#pragma mark - UIAccessibility
+
+- (CGPoint)accessibilityActivationPoint {
+  if ([_trailingContentView hasCustomAccessibilityActivationPoint]) {
+    return _trailingContentView.accessibilityActivationPoint;
+  }
+  if ([_leadingContentView hasCustomAccessibilityActivationPoint]) {
+    return _leadingContentView.accessibilityActivationPoint;
+  }
+  return [super accessibilityActivationPoint];
+}
+
 @end
diff --git a/ios/chrome/browser/tabs/model/BUILD.gn b/ios/chrome/browser/tabs/model/BUILD.gn
index 36a06d3..74fe6ae 100644
--- a/ios/chrome/browser/tabs/model/BUILD.gn
+++ b/ios/chrome/browser/tabs/model/BUILD.gn
@@ -131,6 +131,7 @@
     "//ios/chrome/browser/web/model",
     "//ios/chrome/browser/web/model:page_placeholder",
     "//ios/chrome/browser/web/model/annotations",
+    "//ios/chrome/browser/web/model/choose_file",
     "//ios/chrome/browser/web/model/font_size",
     "//ios/chrome/browser/web/model/image_fetch",
     "//ios/chrome/browser/web/model/print",
diff --git a/ios/chrome/browser/tabs/model/tab_helper_util.mm b/ios/chrome/browser/tabs/model/tab_helper_util.mm
index 05da7e4..9ad10d7 100644
--- a/ios/chrome/browser/tabs/model/tab_helper_util.mm
+++ b/ios/chrome/browser/tabs/model/tab_helper_util.mm
@@ -107,6 +107,7 @@
 #import "ios/chrome/browser/voice/model/voice_search_navigations_tab_helper.h"
 #import "ios/chrome/browser/web/model/annotations/annotations_tab_helper.h"
 #import "ios/chrome/browser/web/model/blocked_popup_tab_helper.h"
+#import "ios/chrome/browser/web/model/choose_file/choose_file_tab_helper.h"
 #import "ios/chrome/browser/web/model/font_size/font_size_tab_helper.h"
 #import "ios/chrome/browser/web/model/image_fetch/image_fetch_tab_helper.h"
 #import "ios/chrome/browser/web/model/invalid_url_tab_helper.h"
@@ -384,4 +385,10 @@
   }
 
   WebViewProxyTabHelper::CreateForWebState(web_state);
+
+  if (!for_prerender && !for_reader_mode && !for_lens_overlay &&
+      (base::FeatureList::IsEnabled(kIOSChooseFromDrive) ||
+       base::FeatureList::IsEnabled(kIOSCustomFileUploadMenu))) {
+    ChooseFileTabHelper::CreateForWebState(web_state);
+  }
 }
diff --git a/ios/chrome/browser/web/model/choose_file/choose_file_tab_helper.h b/ios/chrome/browser/web/model/choose_file/choose_file_tab_helper.h
index 784258de..f116d532 100644
--- a/ios/chrome/browser/web/model/choose_file/choose_file_tab_helper.h
+++ b/ios/chrome/browser/web/model/choose_file/choose_file_tab_helper.h
@@ -7,14 +7,15 @@
 
 #import "base/scoped_observation.h"
 #import "ios/chrome/browser/web/model/choose_file/choose_file_controller.h"
-#import "ios/web/public/lazy_web_state_user_data.h"
 #import "ios/web/public/web_state_observer.h"
+#import "ios/web/public/web_state_user_data.h"
 
 class ChooseFileController;
+@class WKOpenPanelParameters;
+@class WKFrameInfo;
 
-class ChooseFileTabHelper
-    : public web::LazyWebStateUserData<ChooseFileTabHelper>,
-      public web::WebStateObserver {
+class ChooseFileTabHelper : public web::WebStateUserData<ChooseFileTabHelper>,
+                            public web::WebStateObserver {
  public:
   ~ChooseFileTabHelper() override;
 
@@ -36,6 +37,14 @@
                          NSString* display_string = nil,
                          UIImage* icon_image = nil);
 
+  // Displays a file upload panel and calls `completion` with file URLs selected
+  // by the user. `parameters` describe the file upload control which initiated
+  // the call from `frame`.
+  void RunOpenPanel(WKOpenPanelParameters* parameters,
+                    WKFrameInfo* frame,
+                    base::OnceCallback<void(NSArray<NSURL*>*)> completion)
+      API_AVAILABLE(ios(18.4));
+
   // Adds `file_url` to the set of file URLs ready to be passed to
   // `StopChoosingFiles`. `version_identifier` is used to represent the version
   // of the file which is stored at `file_url`.
@@ -62,7 +71,24 @@
 
  private:
   explicit ChooseFileTabHelper(web::WebState* web_state);
-  friend class web::LazyWebStateUserData<ChooseFileTabHelper>;
+  friend class web::WebStateUserData<ChooseFileTabHelper>;
+
+  // TODO(crbug.com/441659098): Remove once it is not used anywhere.
+  template <typename... Args>
+  static ChooseFileTabHelper* GetOrCreateForWebState(web::WebState* web_state,
+                                                     Args&&... args) {
+    CHECK(web_state);
+    if (!FromWebState(web_state)) {
+      CHECK(!web_state->IsBeingDestroyed());
+      web_state->SetUserData(
+          UserDataKey(),
+          ChooseFileTabHelper::Create(web_state, std::forward<Args>(args)...));
+    }
+
+    return FromWebState(web_state);
+  }
+  friend class FileUploadMenuUpdater;
+  friend class DriveFileUploadMenuElement;
 
   // Abort the current selection flow.
   void AbortSelection();
diff --git a/ios/chrome/browser/web/model/choose_file/choose_file_tab_helper.mm b/ios/chrome/browser/web/model/choose_file/choose_file_tab_helper.mm
index eb43232b..399f4057 100644
--- a/ios/chrome/browser/web/model/choose_file/choose_file_tab_helper.mm
+++ b/ios/chrome/browser/web/model/choose_file/choose_file_tab_helper.mm
@@ -54,6 +54,16 @@
   controller_.reset();
 }
 
+void ChooseFileTabHelper::RunOpenPanel(
+    WKOpenPanelParameters* parameters,
+    WKFrameInfo* frame,
+    base::OnceCallback<void(NSArray<NSURL*>*)> completion)
+    API_AVAILABLE(ios(18.4)) {
+  // TODO(crbug.com/441659098): Show the open panel and let the user select
+  // files.
+  std::move(completion).Run(nil);
+}
+
 void ChooseFileTabHelper::AbortSelection() {
   if (IsChoosingFiles()) {
     controller_->Abort();
diff --git a/ios/chrome/browser/web/model/choose_file/choose_file_tab_helper_unittest.mm b/ios/chrome/browser/web/model/choose_file/choose_file_tab_helper_unittest.mm
index b59c4cd..c28e167 100644
--- a/ios/chrome/browser/web/model/choose_file/choose_file_tab_helper_unittest.mm
+++ b/ios/chrome/browser/web/model/choose_file/choose_file_tab_helper_unittest.mm
@@ -20,7 +20,8 @@
   void SetUp() override {
     PlatformTest::SetUp();
     web_state_ = std::make_unique<web::FakeWebState>();
-    tab_helper_ = ChooseFileTabHelper::GetOrCreateForWebState(web_state_.get());
+    ChooseFileTabHelper::CreateForWebState(web_state_.get());
+    tab_helper_ = ChooseFileTabHelper::FromWebState(web_state_.get());
   }
 
  protected:
diff --git a/ios/chrome/browser/web/model/chrome_web_client.mm b/ios/chrome/browser/web/model/chrome_web_client.mm
index ede58300..4bf4080 100644
--- a/ios/chrome/browser/web/model/chrome_web_client.mm
+++ b/ios/chrome/browser/web/model/chrome_web_client.mm
@@ -79,6 +79,7 @@
 #import "ios/chrome/browser/supervised_user/model/supervised_user_url_filter_tab_helper.h"
 #import "ios/chrome/browser/web/model/browser_about_rewriter.h"
 #import "ios/chrome/browser/web/model/choose_file/choose_file_java_script_feature.h"
+#import "ios/chrome/browser/web/model/choose_file/choose_file_tab_helper.h"
 #import "ios/chrome/browser/web/model/chrome_main_parts.h"
 #import "ios/chrome/browser/web/model/error_page_util.h"
 #import "ios/chrome/browser/web/model/features.h"
@@ -654,7 +655,8 @@
     WKFrameInfo* frame,
     base::OnceCallback<void(NSArray<NSURL*>*)> completion) const
     API_AVAILABLE(ios(18.4)) {
-  // TODO(crbug.com/441659098): Forward the request to show the upload panel to
-  // the appropriate tab helper.
-  std::move(completion).Run(nil);
+  CHECK(base::FeatureList::IsEnabled(kIOSCustomFileUploadMenu));
+  ChooseFileTabHelper* tab_helper = ChooseFileTabHelper::FromWebState(source);
+  CHECK(tab_helper);
+  tab_helper->RunOpenPanel(parameters, frame, std::move(completion));
 }
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 702dd75e..51a872e1 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 @@
-550a474583f6c2f78405847292e440dd8fc7f52b
\ No newline at end of file
+104b734909293d64f905566ff4cafa357da05cf5
\ 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 74f251f..e35e348 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 @@
-53a18eb21638a6f00e4277f91dc2ecc34766259b
\ No newline at end of file
+6596f488bba389d9ba33366ef19b1418f79af4d7
\ 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 30387fce..671d094 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 @@
-ae25d074c6dfdaa4ab9889fe36fdfb161191b6cb
\ No newline at end of file
+f3e8f221fe3f04b90491118b3715fe12b32b8750
\ 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 a902335..85c6ebb 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 @@
-6c7a93f1bb4ae2e4da810009d87186f9e859aa5e
\ No newline at end of file
+0ed29e52f3dcc387756ee5dff2060223c7a3bafe
\ 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 a8011a28..2db5b19 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 @@
-54b483eb8f89dd07db65132fe783951ce4824f38
\ No newline at end of file
+fc391a6d44e32f3b4804e1c45aa2bbb4bb73c3f2
\ 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 8fad1c636..f798005 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 @@
-3a2c890507b32025e3aa947f85af581769557660
\ No newline at end of file
+215e7323f6d2e4e0e93e5e8347c3cf1d69781dc0
\ 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 c71a9f5..0fd7085 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 @@
-59bb59ecce35e9bc6b5af798f5d40be2add5a2f1
\ No newline at end of file
+c6d87ad516d009ed5ec8be17902ed5e567c8102d
\ 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 f090085..f3ff1fc 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 @@
-8f423755cf700a93e6b1fd34acc29c05771364af
\ No newline at end of file
+02788af65e3a5a864938b0c711bfcb5b1f7cacf4
\ 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 3bae33b6..906812b 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 @@
-06018c42f42086ce364c83895edf38c33fde1623
\ No newline at end of file
+60fe6a139c24d7552d763413dfe660c86cb4061b
\ 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 6bbf2f4..3cd3db1 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 @@
-a3c764b71bd2e77d7d10a52e0172a928315d6d2e
\ No newline at end of file
+2ad7ae444ee990710b41482fba3de88112a0d63b
\ 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 1e48a3fa..dbc1cc1 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 @@
-9150b3266b5993a14a1c33ec9021c3b4bb792780
\ No newline at end of file
+3adc1cdc6e980fcf050b051435965c486e13811d
\ 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 5eb813b..fc9e6f68 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 @@
-87bd99b42dc2862b9a041f00e2e724bbdca5ad8d
\ No newline at end of file
+9584e32c731de57bbfa74793c7c87fba1a67678d
\ 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 1b4f672d..a3f03299 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 @@
-69617d69a39b73b0ecf04dc505adfc110d8806cf
\ No newline at end of file
+056d390a3efc34aa7206d27aacd44f089b732b6f
\ 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 056d1c8..33f6e15 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 @@
-3d027fb6cf61e58a4d0da7f8b4a43a9ef5263eb1
\ No newline at end of file
+1146bfea3d1a1ec9b7f0bc029bd0faa842b71149
\ 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 5706520..424d547 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 @@
-56bff8fac1645a73b8fd9f8750396f66d4769b4d
\ No newline at end of file
+b296cd147b843629180315a28302f6a23bb9108a
\ 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 08dd40a..89e771fb 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 @@
-ae16621144955c02650976efb7cdf676633e3911
\ No newline at end of file
+448c4a1870fad55de49e88a87e8d359dc168d025
\ 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 0a873ec..0996f66 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 @@
-a15de2fa45bc569c670d3994619401a52b90ae08
\ No newline at end of file
+d227536348779e3bd4b8b7b414f84d592a8dce20
\ 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 2125db5..03e90eb 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 @@
-5060d5b98f8978eb862dfde5139a40489c9be288
\ No newline at end of file
+e568995b6358b60de05b7810bd1e741ac31da8c6
\ 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 4a05070..e4703bf 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 @@
-e9834ef7a7ca6ab0476895580c33add52d394cc9
\ No newline at end of file
+2fc79e67a8b72d5dbbdbc565ab6bb4385b1aff7b
\ 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 3c43c713..92cf384 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 @@
-c3a29ee65a8b01bc43ec9ccb7acbe074fda52230
\ No newline at end of file
+99790aa816651916d4939149c2ac02e66e656402
\ 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 1a75d114..c51aa3b 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 @@
-01c0f19757173b1a9ed40473df731cb3adc53896
\ No newline at end of file
+f03c7e22b14fbacb3f25db210ad06303bfbac28d
\ 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 a3932257..5de8ed0d 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 @@
-eb7649daa4d05285fb5f3b01d24c5cff8920f245
\ No newline at end of file
+ace1b699f30e41c8ca6f2a2d2088553bc4c9aea0
\ 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 014958f..8163ded 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 @@
-51e7d4f6f206c51683f53c6c4e758d921cb4345b
\ No newline at end of file
+b7ea53b80fff87e3a392d8e97cee3440f518a0f2
\ 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 9bcf87d3..e8793f06 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 @@
-718581d4849a42573d69473e190839b2e1a8541a
\ No newline at end of file
+3af7949c16f301b86a39d2a9ac8cf6f707845438
\ 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 d02ede3..5341b76 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 @@
-7bdea5925c06b12fc789a13d50078086985ace3e
\ No newline at end of file
+e97651eb4187188ee2826c7d6893fc2842184055
\ 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 5b06efb..1ea3ab8 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 @@
-ab4e98eef8d797256e9a5898647ec22e02bcc1cf
\ No newline at end of file
+c582680039ca8b1019397babb4eb339202193923
\ 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 58ba11f..edfec629 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 @@
-dfdf6be56101d20d9e3e674cd61f2f988febdf53
\ No newline at end of file
+d8168f24bfcf3a71044e3f29b69a2a5af380b188
\ 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 53a4d21..8426c676 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 @@
-4dc40ca6d28aa779a15d714fff58d95c62c411fc
\ No newline at end of file
+51a828f97529489699a063d445130a3f56a952f1
\ No newline at end of file
diff --git a/ios_internal b/ios_internal
index 77b7d99..484637b 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit 77b7d99bb2c3d0809ca87fd517282901bc017060
+Subproject commit 484637bf993d755b82ff1501b415a4abb8eb6fe7
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 21bc44c2..4601a05 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -3133,6 +3133,7 @@
 
   fuzztests = [
     "HpackHeaderTableFuzzTest.CanCallMethodSequence",
+    "HttpNoVarySearchTest.AreEquivalentImplementationsMatch",
     "PickleTest.FuzzRoundTrip",
     "QuicVersionsFuzzTest.ParseSerializeParseIdentityProperty",
     "TransportParametersFuzzTest.ParseTransportParametersDoesNotCrash",
diff --git a/net/base/features.cc b/net/base/features.cc
index 1c781dc..5e0383a 100644
--- a/net/base/features.cc
+++ b/net/base/features.cc
@@ -655,6 +655,11 @@
                    &kDiskCacheBackendExperiment,
                    "SqlDiskCacheIdleCheckpointThreshold",
                    1000);
+BASE_FEATURE_PARAM(int,
+                   kSqlDiskCacheOptimisticWriteBufferSize,
+                   &kDiskCacheBackendExperiment,
+                   "SqlDiskCacheOptimisticWriteBufferSize",
+                   32 * 1024 * 1024);
 #endif  // ENABLE_DISK_CACHE_SQL_BACKEND
 
 BASE_FEATURE(kIgnoreHSTSForLocalhost, base::FEATURE_ENABLED_BY_DEFAULT);
@@ -705,6 +710,15 @@
                    "keep_not_suitable",
                    false);
 
+BASE_FEATURE(kHttpNoVarySearchDataUseNewAreEquivalent,
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+BASE_FEATURE_PARAM(bool,
+                   kHttpNoVarySearchDataAreEquivalentCheckResult,
+                   &kHttpNoVarySearchDataUseNewAreEquivalent,
+                   "check_result",
+                   false);
+
 BASE_FEATURE(kReportingApiCorsOriginHeader, base::FEATURE_ENABLED_BY_DEFAULT);
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/net/base/features.h b/net/base/features.h
index c61b895..4d9b6766 100644
--- a/net/base/features.h
+++ b/net/base/features.h
@@ -779,6 +779,10 @@
 // exceeds this value and the browser is idle, a checkpoint is executed.
 NET_EXPORT BASE_DECLARE_FEATURE_PARAM(int,
                                       kSqlDiskCacheIdleCheckpointThreshold);
+// While the memory usage for the buffer doesn't exceed the number of bytes
+// specified by this param, the SQL backend executes optimistic writes.
+NET_EXPORT BASE_DECLARE_FEATURE_PARAM(int,
+                                      kSqlDiskCacheOptimisticWriteBufferSize);
 #endif  // ENABLE_DISK_CACHE_SQL_BACKEND
 
 // If enabled, ignore Strict-Transport-Security for [*.]localhost hosts.
@@ -820,6 +824,16 @@
 NET_EXPORT BASE_DECLARE_FEATURE_PARAM(bool,
                                       kHttpCacheNoVarySearchKeepNotSuitable);
 
+// Whether to use the new implementation of
+// HttpNoVarySearchData::AreEquivalent().
+NET_EXPORT BASE_DECLARE_FEATURE(kHttpNoVarySearchDataUseNewAreEquivalent);
+
+// Whether to check the result against the old implementation and
+// DumpWithoutCrashing() if they differ.
+NET_EXPORT BASE_DECLARE_FEATURE_PARAM(
+    bool,
+    kHttpNoVarySearchDataAreEquivalentCheckResult);
+
 // Enables sending the CORS Origin header on the POST request for Reporting API
 // report uploads.
 NET_EXPORT BASE_DECLARE_FEATURE(kReportingApiCorsOriginHeader);
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc
index a005e9c2..924d749 100644
--- a/net/disk_cache/entry_unittest.cc
+++ b/net/disk_cache/entry_unittest.cc
@@ -3903,15 +3903,11 @@
   EXPECT_EQ(kWriteSize,
             WriteData(entry, 1, 0, buffer.get(), kWriteSize, false));
   entry->Close();
-  AddDelay();
 
   std::string key2("the key prefix");
   for (int i = 0; i < kNumExtraEntries; i++) {
-    if (i == kNumExtraEntries - 2) {
-      // Create a distinct timestamp for the last two entries. These entries
-      // will be checked for outliving the eviction.
-      AddDelay();
-    }
+    // Create a distinct timestamp for the each entries.
+    AddDelay();
     ASSERT_THAT(CreateEntry(key2 + base::NumberToString(i), &entry), IsOk());
     ScopedEntryPtr entry_closer(entry);
     EXPECT_EQ(kWriteSize,
diff --git a/net/disk_cache/sql/sql_backend_impl.cc b/net/disk_cache/sql/sql_backend_impl.cc
index 0e797929..f3cf265 100644
--- a/net/disk_cache/sql/sql_backend_impl.cc
+++ b/net/disk_cache/sql/sql_backend_impl.cc
@@ -24,6 +24,7 @@
 #include "base/task/task_runner.h"
 #include "base/task/thread_pool.h"
 #include "base/types/expected.h"
+#include "net/base/features.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/disk_cache/sql/sql_entry_impl.h"
@@ -523,7 +524,8 @@
 
   const auto optional_res_id = GetResId(entry.res_id_or_error());
   if (!optional_res_id) {
-    // Speculative entry creation was failed.
+    // Fail the operation for entries that previously failed a speculative
+    // creation or optimistic write.
     CHECK(GetError(entry.res_id_or_error()).has_value());
     std::move(callback).Run(net::ERR_FAILED);
     return;
@@ -902,7 +904,8 @@
     std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle) {
   const auto optional_res_id = GetResId(res_id_or_error);
   if (!optional_res_id) {
-    // Speculative entry creation was failed.
+    // Fail the operation for entries that previously failed a speculative
+    // creation or optimistic write.
     return;
   }
   store_->DeleteDoomedEntry(
@@ -935,8 +938,8 @@
     std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle) {
   const auto optional_res_id = GetResId(res_id_or_error);
   if (!optional_res_id) {
-    // Fail the operation for entries that were speculatively created but
-    // failed, or for entries that previously failed optimistic writes.
+    // Fail the operation for entries that previously failed a speculative
+    // creation or optimistic write.
     return;
   }
   store_->UpdateEntryLastUsedByResId(
@@ -973,7 +976,8 @@
     std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle) {
   const auto optional_res_id = GetResId(res_id_or_error);
   if (!optional_res_id) {
-    // Speculative entry creation was failed.
+    // Fail the operation for entries that previously failed a speculative
+    // creation or optimistic write.
     const auto optional_error = GetError(res_id_or_error);
     CHECK(optional_error.has_value());
     return;
@@ -986,7 +990,7 @@
           .Then(OnceClosureWithBoundArgs(std::move(handle))));
 }
 
-void SqlBackendImpl::WriteEntryData(
+int SqlBackendImpl::WriteEntryData(
     const CacheEntryKey& key,
     const scoped_refptr<ResIdOrErrorHolder>& res_id_or_error,
     int64_t old_body_end,
@@ -996,6 +1000,54 @@
     int buf_len,
     bool truncate,
     CompletionOnceCallback callback) {
+  if (res_id_or_error->data.has_value() &&
+      std::holds_alternative<SqlPersistentStore::Error>(
+          res_id_or_error->data.value())) {
+    // Fail the operation for entries that previously failed a speculative
+    // creation or optimistic write.
+    return net::ERR_FAILED;
+  }
+
+  // Perform optimistic writes as long as `optimistic_write_buffer_total_size_`
+  // does not exceed `kSqlDiskCacheOptimisticWriteBufferSize`.
+  const bool can_execute_optimistic_write =
+      optimistic_write_buffer_total_size_ + buf_len <=
+      net::features::kSqlDiskCacheOptimisticWriteBufferSize.Get();
+  base::UmaHistogramBoolean("Net.SqlDiskCache.Write.IsOptimistic",
+                            can_execute_optimistic_write);
+  if (can_execute_optimistic_write) {
+    optimistic_write_buffer_total_size_ += buf_len;
+    if (buffer) {
+      // Note: `buffer` can be nullptr.
+      buffer = base::MakeRefCounted<net::VectorIOBuffer>(
+          buffer->span().first(static_cast<size_t>(buf_len)));
+    }
+    // Callback to set an error on `res_id_or_error` when an error occurs or
+    // the backend is deleted.
+    auto maybe_update_res_id_or_error_callback =
+        WrapCallbackWithAbortError<SqlPersistentStore::Error>(
+            base::BindOnce(
+                [](const scoped_refptr<ResIdOrErrorHolder>& res_id_or_error,
+                   SqlPersistentStore::Error result) {
+                  base::UmaHistogramEnumeration(
+                      "Net.SqlDiskCache.OptimisticWrite.Result", result);
+                  if (result != SqlPersistentStore::Error::kOk) {
+                    res_id_or_error->data = result;
+                  }
+                },
+                res_id_or_error),
+            SqlPersistentStore::Error::kAborted);
+    exclusive_operation_coordinator_.PostOrRunNormalOperation(
+        key,
+        base::BindOnce(
+            &SqlBackendImpl::HandleOptimisticWriteEntryDataOperation,
+            weak_factory_.GetWeakPtr(), key, res_id_or_error, old_body_end,
+            offset, std::move(buffer), buf_len, truncate,
+            std::move(maybe_update_res_id_or_error_callback),
+            PushInFlightEntryModification(
+                key, InFlightEntryModification(res_id_or_error, body_end))));
+    return buf_len;
+  }
   exclusive_operation_coordinator_.PostOrRunNormalOperation(
       key,
       base::BindOnce(&SqlBackendImpl::HandleWriteEntryDataOperation,
@@ -1015,6 +1067,7 @@
                      PushInFlightEntryModification(
                          key, InFlightEntryModification(res_id_or_error,
                                                         body_end))));
+  return net::ERR_IO_PENDING;
 }
 
 void SqlBackendImpl::HandleWriteEntryDataOperation(
@@ -1030,7 +1083,8 @@
     std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle) {
   const auto optional_res_id = GetResId(res_id_or_error);
   if (!optional_res_id) {
-    // Speculative entry creation was failed.
+    // Fail the operation for entries that previously failed a speculative
+    // creation or optimistic write.
     const auto optional_error = GetError(res_id_or_error);
     CHECK(optional_error.has_value());
     std::move(callback).Run(*optional_error);
@@ -1045,6 +1099,66 @@
           .Then(OnceClosureWithBoundArgs(std::move(handle))));
 }
 
+void SqlBackendImpl::HandleOptimisticWriteEntryDataOperation(
+    const CacheEntryKey& key,
+    const scoped_refptr<ResIdOrErrorHolder>& res_id_or_error,
+    int64_t old_body_end,
+    int64_t offset,
+    scoped_refptr<net::IOBuffer> buffer,
+    int buf_len,
+    bool truncate,
+    SqlPersistentStore::ErrorCallback maybe_update_res_id_or_error_callback,
+    PopInFlightEntryModificationRunner pop_in_flight_entry_modification,
+    std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle) {
+  const auto optional_res_id = GetResId(res_id_or_error);
+  if (!optional_res_id) {
+    // Decrement the total size.
+    optimistic_write_buffer_total_size_ -= buf_len;
+    CHECK_GE(optimistic_write_buffer_total_size_, 0);
+    // Fail the operation for entries that previously failed a speculative
+    // creation or optimistic write.
+    const auto optional_error = GetError(res_id_or_error);
+    CHECK(optional_error.has_value());
+    // Need to call `maybe_update_res_id_or_error_callback` here, otherwise
+    // `res_id_or_error` will be set to SqlPersistentStore::Error::kAborted.
+    std::move(maybe_update_res_id_or_error_callback).Run(*optional_error);
+    return;
+  }
+  store_->WriteEntryData(
+      key, *optional_res_id, old_body_end, offset, std::move(buffer), buf_len,
+      truncate,
+      base::BindOnce(&SqlBackendImpl::OnOptimisticWriteFinished,
+                     weak_factory_.GetWeakPtr(), key, *optional_res_id, buf_len,
+                     std::move(maybe_update_res_id_or_error_callback),
+                     std::move(pop_in_flight_entry_modification),
+                     std::move(handle)));
+}
+
+void SqlBackendImpl::OnOptimisticWriteFinished(
+    const CacheEntryKey& key,
+    SqlPersistentStore::ResId res_id,
+    int buf_len,
+    SqlPersistentStore::ErrorCallback maybe_update_res_id_or_error_callback,
+    PopInFlightEntryModificationRunner pop_in_flight_entry_modification,
+    std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle,
+    SqlPersistentStore::Error result) {
+  optimistic_write_buffer_total_size_ -= buf_len;
+  CHECK_GE(optimistic_write_buffer_total_size_, 0);
+  std::move(maybe_update_res_id_or_error_callback).Run(result);
+
+  if (result == SqlPersistentStore::Error::kOk) {
+    return;
+  }
+  // If an optimistic write fails, `maybe_update_res_id_or_error_callback` has
+  // set an error value in the entry's `res_id_or_error`. This ensures that all
+  // subsequent operations on this entry will also fail.
+  // Since the user of the Sql backend can no longer delete the entry from
+  // storage, SqlBackendImpl takes responsibility for deleting it.
+  store_->DoomEntry(key, res_id, base::DoNothing());
+  store_->DeleteDoomedEntry(key, res_id,
+                            base::DoNothingWithBoundArgs(std::move(handle)));
+}
+
 void SqlBackendImpl::ReadEntryData(
     const CacheEntryKey& key,
     const scoped_refptr<ResIdOrErrorHolder>& res_id_or_error,
@@ -1079,7 +1193,8 @@
     std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle) {
   const auto optional_res_id = GetResId(res_id_or_error);
   if (!optional_res_id) {
-    // Speculative entry creation was failed.
+    // Fail the operation for entries that previously failed a speculative
+    // creation or optimistic write.
     const auto optional_error = GetError(res_id_or_error);
     CHECK(optional_error.has_value());
     std::move(callback).Run(net::ERR_FAILED);
@@ -1112,7 +1227,8 @@
     std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle) {
   const auto optional_res_id = GetResId(res_id_or_error);
   if (!optional_res_id) {
-    // Speculative entry creation was failed.
+    // Fail the operation for entries that previously failed a speculative
+    // creation or optimistic write.
     const auto optional_error = GetError(res_id_or_error);
     CHECK(optional_error.has_value());
     std::move(callback).Run(RangeResult(net::ERR_FAILED));
diff --git a/net/disk_cache/sql/sql_backend_impl.h b/net/disk_cache/sql/sql_backend_impl.h
index 3053e90..f3a0fa9 100644
--- a/net/disk_cache/sql/sql_backend_impl.h
+++ b/net/disk_cache/sql/sql_backend_impl.h
@@ -150,15 +150,15 @@
   // serialization.
   // If the backend is deleted during execution, the callback will be called
   // with net::ERR_ABORTED.
-  void WriteEntryData(const CacheEntryKey& key,
-                      const scoped_refptr<ResIdOrErrorHolder>& res_id_or_error,
-                      int64_t old_body_end,
-                      int64_t body_end,
-                      int64_t offset,
-                      scoped_refptr<net::IOBuffer> buffer,
-                      int buf_len,
-                      bool truncate,
-                      CompletionOnceCallback callback);
+  int WriteEntryData(const CacheEntryKey& key,
+                     const scoped_refptr<ResIdOrErrorHolder>& res_id_or_error,
+                     int64_t old_body_end,
+                     int64_t body_end,
+                     int64_t offset,
+                     scoped_refptr<net::IOBuffer> buffer,
+                     int buf_len,
+                     bool truncate,
+                     CompletionOnceCallback callback);
 
   // Reads data from an entry's body (stream 1). The operation is scheduled via
   // the `ExclusiveOperationCoordinator`. `sparse_reading` controls whether
@@ -209,6 +209,10 @@
     return in_flight_entry_modifications_.size();
   }
 
+  int64_t GetOptimisticWriteBufferTotalSizeForTesting() {
+    return optimistic_write_buffer_total_size_;
+  }
+
  private:
   class IteratorImpl;
 
@@ -371,9 +375,9 @@
       PopInFlightEntryModificationRunner pop_in_flight_entry_modification,
       std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);
 
-  // Handles the backend logic for `WriteEntryData()`. This method is scheduled
-  // as a normal operation via the `ExclusiveOperationCoordinator` and forwards
-  // the call to the persistent store.
+  // Handles the backend logic for a non-optimistic write operation. This method
+  // is scheduled as a normal operation via the `ExclusiveOperationCoordinator`
+  // and forwards the call to the persistent store.
   void HandleWriteEntryDataOperation(
       const CacheEntryKey& key,
       const scoped_refptr<ResIdOrErrorHolder>& res_id_or_error,
@@ -386,6 +390,32 @@
       PopInFlightEntryModificationRunner pop_in_flight_entry_modification,
       std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);
 
+  // Handles the backend logic for an optimistic write operation. This method is
+  // scheduled as a normal operation via the `ExclusiveOperationCoordinator` and
+  // forwards the write to the persistent store.
+  void HandleOptimisticWriteEntryDataOperation(
+      const CacheEntryKey& key,
+      const scoped_refptr<ResIdOrErrorHolder>& res_id_or_error,
+      int64_t old_body_end,
+      int64_t offset,
+      scoped_refptr<net::IOBuffer> buffer,
+      int buf_len,
+      bool truncate,
+      SqlPersistentStore::ErrorCallback maybe_update_res_id_or_error_callback,
+      PopInFlightEntryModificationRunner pop_in_flight_entry_modification,
+      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);
+
+  // Called when an optimistic write is finished. `buf_len` is the memory usage
+  // consumed for the optimistic write.
+  void OnOptimisticWriteFinished(
+      const CacheEntryKey& key,
+      SqlPersistentStore::ResId res_id,
+      int buf_len,
+      SqlPersistentStore::ErrorCallback maybe_update_res_id_or_error_callback,
+      PopInFlightEntryModificationRunner pop_in_flight_entry_modification,
+      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle,
+      SqlPersistentStore::Error result);
+
   // Handles the backend logic for `ReadEntryData()`. This method is scheduled
   // as a normal operation via the `ExclusiveOperationCoordinator` and forwards
   // the call to the persistent store.
@@ -489,6 +519,11 @@
   // task is pending, only one will be in the queue at any time.
   bool eviction_operation_queued_ = false;
 
+  // The memory usage consumed for optimistic writes. Optimistic writes are
+  // performed as long as this value does not exceed
+  // `kSqlDiskCacheOptimisticWriteBufferSize`.
+  int64_t optimistic_write_buffer_total_size_ = 0;
+
   // Weak pointer factory for this class.
   base::WeakPtrFactory<SqlBackendImpl> weak_factory_{this};
 };
diff --git a/net/disk_cache/sql/sql_backend_impl_unittest.cc b/net/disk_cache/sql/sql_backend_impl_unittest.cc
index 2723dd8..09d2e43 100644
--- a/net/disk_cache/sql/sql_backend_impl_unittest.cc
+++ b/net/disk_cache/sql/sql_backend_impl_unittest.cc
@@ -16,9 +16,11 @@
 #include "base/task/thread_pool.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/test/test_file_util.h"
 #include "base/test/test_future.h"
+#include "net/base/features.h"
 #include "net/base/io_buffer.h"
 #include "net/base/test_completion_callback.h"
 #include "net/disk_cache/disk_cache_test_util.h"
@@ -94,6 +96,18 @@
     CHECK_EQ(future.Get(), net::OK);
     return backend;
   }
+  void WaitUntilInitialized(
+      SqlBackendImpl& backend,
+      const scoped_refptr<SqlBackendImpl::ResIdOrErrorHolder>&
+          res_id_or_error) {
+    CHECK(res_id_or_error);
+    while (!res_id_or_error->data.has_value()) {
+      base::RunLoop run_loop;
+      backend.GetBackgroundTaskRunnerForTest()->PostTask(
+          FROM_HERE, run_loop.QuitClosure());
+      run_loop.Run();
+    }
+  }
 
   base::test::TaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
@@ -1093,18 +1107,34 @@
   ASSERT_THAT(create_result.net_error(), IsOk());
   auto* entry = create_result.ReleaseEntry();
 
+  net::TestCompletionCallback flush_cb;
+  backend->FlushQueueForTest(flush_cb.callback());
+  EXPECT_THAT(flush_cb.WaitForResult(), IsOk());
+
   // Initiate a WriteData operation, which will be pending.
   auto write_buffer = base::MakeRefCounted<net::StringIOBuffer>("data");
   base::test::TestFuture<int> write_future;
   int rv = entry->WriteData(1, 0, write_buffer.get(), write_buffer->size(),
                             write_future.GetCallback(), false);
-  ASSERT_THAT(rv, IsError(net::ERR_IO_PENDING));
+  ASSERT_THAT(rv, write_buffer->size());
+
+  auto task_runner = backend->GetBackgroundTaskRunnerForTest();
 
   // Destroy the backend while the write is in flight.
   backend.reset();
 
-  // The callback should be aborted.
-  EXPECT_EQ(write_future.Get(), net::ERR_ABORTED);
+  auto res_id_or_error = static_cast<SqlEntryImpl*>(entry)->res_id_or_error();
+  while (!(res_id_or_error->data.has_value() &&
+           std::holds_alternative<SqlPersistentStore::Error>(
+               *res_id_or_error->data))) {
+    base::RunLoop run_loop;
+    task_runner->PostTask(FROM_HERE, run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
+  // The res_id_or_error should have been set to aborted.
+  EXPECT_EQ(std::get<SqlPersistentStore::Error>(*res_id_or_error->data),
+            SqlPersistentStore::Error::kAborted);
 
   entry->Close();
 }
@@ -1150,8 +1180,8 @@
   auto* entry1 = CreateEntryAndWriteData(backend.get(), kKey1, kData);
   auto* entry2 = CreateEntryAndWriteData(backend.get(), kKey2, kData);
   auto* entry3 = CreateEntryAndWriteData(backend.get(), kKey3, kData);
-  CHECK(std::holds_alternative<SqlPersistentStore::ResId>(
-      static_cast<SqlEntryImpl*>(entry3)->res_id_or_error()->data.value()));
+  WaitUntilInitialized(*backend,
+                       static_cast<SqlEntryImpl*>(entry3)->res_id_or_error());
   auto res_id = std::get<SqlPersistentStore::ResId>(
       static_cast<SqlEntryImpl*>(entry3)->res_id_or_error()->data.value());
   entry1->Close();
@@ -1237,12 +1267,7 @@
   EXPECT_FALSE(sql_entry->res_id_or_error()->data.has_value());
 
   // 3. Wait for the database operation to complete.
-  while (!sql_entry->res_id_or_error()->data.has_value()) {
-    base::RunLoop run_loop;
-    backend->GetBackgroundTaskRunnerForTest()->PostTask(FROM_HERE,
-                                                        run_loop.QuitClosure());
-    run_loop.Run();
-  }
+  WaitUntilInitialized(*backend, sql_entry->res_id_or_error());
 
   // 4. Now the res_id should be available.
   ASSERT_TRUE(sql_entry->res_id_or_error()->data.has_value());
@@ -1362,12 +1387,7 @@
   EXPECT_FALSE(sql_entry->res_id_or_error()->data.has_value());
 
   // 3. Wait for the database operation to complete.
-  while (!sql_entry->res_id_or_error()->data.has_value()) {
-    base::RunLoop run_loop;
-    backend->GetBackgroundTaskRunnerForTest()->PostTask(FROM_HERE,
-                                                        run_loop.QuitClosure());
-    run_loop.Run();
-  }
+  WaitUntilInitialized(*backend, sql_entry->res_id_or_error());
 
   // 4. Now the res_id should be available and hold a kFailedForTesting.
   ASSERT_TRUE(sql_entry->res_id_or_error()->data.has_value());
@@ -1400,11 +1420,11 @@
   auto* entry = entry_result.ReleaseEntry();
   ASSERT_TRUE(entry);
 
-  net::TestCompletionCallback write_cb;
   auto write_buffer = base::MakeRefCounted<net::StringIOBuffer>("data");
-  EXPECT_EQ(entry->WriteData(1, 0, write_buffer.get(), write_buffer->size(),
-                             write_cb.callback(), false),
-            net::ERR_IO_PENDING);
+  EXPECT_EQ(
+      entry->WriteData(1, 0, write_buffer.get(), write_buffer->size(),
+                       base::BindOnce([](int rv) { NOTREACHED(); }), false),
+      write_buffer->size());
 
   net::TestCompletionCallback read_cb;
   auto read_buffer = base::MakeRefCounted<net::IOBufferWithSize>(10);
@@ -1417,7 +1437,6 @@
       entry->GetAvailableRange(0, 10, range_future.GetCallback()).net_error,
       net::ERR_IO_PENDING);
 
-  EXPECT_THAT(write_cb.WaitForResult(), IsError(net::ERR_FAILED));
   EXPECT_THAT(read_cb.WaitForResult(), IsError(net::ERR_FAILED));
   EXPECT_THAT(range_future.Get().net_error, IsError(net::ERR_FAILED));
   entry->Close();
@@ -1435,22 +1454,17 @@
   ASSERT_TRUE(entry);
 
   auto* sql_entry = static_cast<SqlEntryImpl*>(entry);
-  while (!sql_entry->res_id_or_error()->data.has_value()) {
-    base::RunLoop run_loop;
-    backend->GetBackgroundTaskRunnerForTest()->PostTask(FROM_HERE,
-                                                        run_loop.QuitClosure());
-    run_loop.Run();
-  }
+  WaitUntilInitialized(*backend, sql_entry->res_id_or_error());
   auto write_buffer = base::MakeRefCounted<net::StringIOBuffer>("data");
   EXPECT_EQ(entry->WriteData(0, 0, write_buffer.get(), write_buffer->size(),
                              base::DoNothing(), false),
             static_cast<int>(write_buffer->size()));
 
   net::TestCompletionCallback write_cb;
-  EXPECT_EQ(entry->WriteData(1, 0, write_buffer.get(), write_buffer->size(),
-                             write_cb.callback(), false),
-            net::ERR_IO_PENDING);
-  EXPECT_THAT(write_cb.WaitForResult(), IsError(net::ERR_FAILED));
+  EXPECT_EQ(
+      entry->WriteData(1, 0, write_buffer.get(), write_buffer->size(),
+                       base::BindOnce([](int rv) { NOTREACHED(); }), false),
+      net::ERR_FAILED);
 
   net::TestCompletionCallback read_cb;
   auto read_buffer = base::MakeRefCounted<net::IOBufferWithSize>(10);
@@ -1480,12 +1494,7 @@
   ASSERT_TRUE(entry);
 
   auto* sql_entry = static_cast<SqlEntryImpl*>(entry);
-  while (!sql_entry->res_id_or_error()->data.has_value()) {
-    base::RunLoop run_loop;
-    backend->GetBackgroundTaskRunnerForTest()->PostTask(FROM_HERE,
-                                                        run_loop.QuitClosure());
-    run_loop.Run();
-  }
+  WaitUntilInitialized(*backend, sql_entry->res_id_or_error());
 
   entry->Doom();
   EXPECT_TRUE(static_cast<SqlEntryImpl*>(entry)->doomed());
@@ -1498,5 +1507,232 @@
   EXPECT_THAT(open_result.net_error(), IsError(net::ERR_FAILED));
 }
 
+TEST_F(SqlBackendImplTest, OptimisticWriteBufferSize) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeatureWithParameters(
+      net::features::kDiskCacheBackendExperiment,
+      {{net::features::kSqlDiskCacheOptimisticWriteBufferSize.name, "100"}});
+
+  auto backend = CreateBackendAndInit();
+  TestEntryResultCompletionCallback cb;
+  disk_cache::EntryResult entry_result =
+      backend->CreateEntry("key", net::HIGHEST, cb.callback());
+  ASSERT_THAT(entry_result.net_error(), IsOk());
+  auto* entry = entry_result.ReleaseEntry();
+  ASSERT_TRUE(entry);
+
+  // First write is smaller than the buffer size, should be optimistic.
+  auto write_buffer1 = base::MakeRefCounted<net::StringIOBuffer>("data1");
+  EXPECT_EQ(entry->WriteData(1, 0, write_buffer1.get(), write_buffer1->size(),
+                             base::DoNothing(), false),
+            static_cast<int>(write_buffer1->size()));
+  EXPECT_EQ(backend->GetOptimisticWriteBufferTotalSizeForTesting(),
+            write_buffer1->size());
+
+  // Second write exceeds the buffer size, should be pending.
+  auto write_buffer2 =
+      base::MakeRefCounted<net::StringIOBuffer>(std::string(100, 'a'));
+  net::TestCompletionCallback write_cb;
+  EXPECT_EQ(entry->WriteData(1, write_buffer1->size(), write_buffer2.get(),
+                             write_buffer2->size(), write_cb.callback(), false),
+            net::ERR_IO_PENDING);
+  EXPECT_EQ(backend->GetOptimisticWriteBufferTotalSizeForTesting(),
+            write_buffer1->size());
+
+  EXPECT_EQ(write_cb.WaitForResult(), static_cast<int>(write_buffer2->size()));
+  EXPECT_EQ(backend->GetOptimisticWriteBufferTotalSizeForTesting(), 0);
+
+  entry->Close();
+}
+
+TEST_F(SqlBackendImplTest, OptimisticWriteBufferLifecycle) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeatureWithParameters(
+      net::features::kDiskCacheBackendExperiment,
+      {{net::features::kSqlDiskCacheOptimisticWriteBufferSize.name, "100"}});
+
+  auto backend = CreateBackendAndInit();
+  TestEntryResultCompletionCallback cb;
+  disk_cache::EntryResult entry_result =
+      backend->CreateEntry("key", net::HIGHEST, cb.callback());
+  ASSERT_THAT(entry_result.net_error(), IsOk());
+  auto* entry = entry_result.ReleaseEntry();
+  ASSERT_TRUE(entry);
+
+  // This write should be optimistic.
+  auto write_buffer1 =
+      base::MakeRefCounted<net::StringIOBuffer>(std::string(50, 'a'));
+  EXPECT_EQ(entry->WriteData(1, 0, write_buffer1.get(), write_buffer1->size(),
+                             base::DoNothing(), false),
+            static_cast<int>(write_buffer1->size()));
+  EXPECT_EQ(backend->GetOptimisticWriteBufferTotalSizeForTesting(),
+            write_buffer1->size());
+
+  // This write should also be optimistic, filling the buffer.
+  auto write_buffer2 =
+      base::MakeRefCounted<net::StringIOBuffer>(std::string(50, 'b'));
+  EXPECT_EQ(entry->WriteData(1, 50, write_buffer2.get(), write_buffer2->size(),
+                             base::DoNothing(), false),
+            static_cast<int>(write_buffer2->size()));
+  EXPECT_EQ(backend->GetOptimisticWriteBufferTotalSizeForTesting(),
+            write_buffer1->size() + write_buffer2->size());
+
+  // This write should be pending as the buffer is full.
+  auto write_buffer3 = base::MakeRefCounted<net::StringIOBuffer>("c");
+  net::TestCompletionCallback write_cb3;
+  EXPECT_EQ(entry->WriteData(1, 100, write_buffer3.get(), write_buffer3->size(),
+                             write_cb3.callback(), false),
+            net::ERR_IO_PENDING);
+  EXPECT_EQ(backend->GetOptimisticWriteBufferTotalSizeForTesting(),
+            write_buffer1->size() + write_buffer2->size());
+
+  // Flush the queue. This will ensure the first two optimistic writes complete
+  // on the background thread, which will free up the buffer and allow the
+  // pending write to proceed.
+  net::TestCompletionCallback flush_cb1;
+  backend->FlushQueueForTest(flush_cb1.callback());
+  EXPECT_THAT(flush_cb1.WaitForResult(), IsOk());
+
+  EXPECT_EQ(backend->GetOptimisticWriteBufferTotalSizeForTesting(), 0);
+
+  // Now that the queue is flushed, the pending write should have completed.
+  EXPECT_EQ(write_cb3.WaitForResult(), static_cast<int>(write_buffer3->size()));
+
+  EXPECT_EQ(backend->GetOptimisticWriteBufferTotalSizeForTesting(), 0);
+  // The buffer should be free again, so this write should be optimistic.
+  auto write_buffer4 =
+      base::MakeRefCounted<net::StringIOBuffer>(std::string(50, 'd'));
+  EXPECT_EQ(entry->WriteData(1, 101, write_buffer4.get(), write_buffer4->size(),
+                             base::DoNothing(), false),
+            static_cast<int>(write_buffer4->size()));
+  EXPECT_EQ(backend->GetOptimisticWriteBufferTotalSizeForTesting(),
+            write_buffer4->size());
+
+  entry->Close();
+
+  net::TestCompletionCallback flush_cb2;
+  backend->FlushQueueForTest(flush_cb2.callback());
+  EXPECT_THAT(flush_cb2.WaitForResult(), IsOk());
+
+  EXPECT_EQ(backend->GetOptimisticWriteBufferTotalSizeForTesting(), 0);
+}
+
+TEST_F(SqlBackendImplTest, OptimisticWriteFailure) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeatureWithParameters(
+      net::features::kDiskCacheBackendExperiment,
+      {{net::features::kSqlDiskCacheOptimisticWriteBufferSize.name, "100"}});
+
+  auto backend = CreateBackendAndInit();
+  const std::string kKey = "my-key";
+  const std::string kInitialData = "initial data";
+
+  // 1. Create an entry with some data.
+  auto* entry = CreateEntryAndWriteData(backend.get(), kKey, kInitialData);
+  entry->Close();
+
+  // 2. Re-open the entry.
+  TestEntryResultCompletionCallback open_cb;
+  disk_cache::EntryResult open_result = open_cb.GetResult(
+      backend->OpenEntry(kKey, net::HIGHEST, open_cb.callback()));
+  ASSERT_THAT(open_result.net_error(), IsOk());
+  entry = open_result.ReleaseEntry();
+  auto* sql_entry = static_cast<SqlEntryImpl*>(entry);
+
+  // 3. Simulate a database failure for subsequent operations.
+  backend->GetSqlStoreForTest()->SetSimulateDbFailureForTesting(true);
+
+  // 4. Perform an optimistic write, which should fail in the background.
+  auto write_buffer = base::MakeRefCounted<net::StringIOBuffer>("new data");
+  EXPECT_EQ(entry->WriteData(1, kInitialData.size(), write_buffer.get(),
+                             write_buffer->size(), base::DoNothing(), false),
+            static_cast<int>(write_buffer->size()));
+  EXPECT_EQ(backend->GetOptimisticWriteBufferTotalSizeForTesting(),
+            write_buffer->size());
+
+  // 5. Disable failure simulation.
+  backend->GetSqlStoreForTest()->SetSimulateDbFailureForTesting(false);
+
+  // 6. Wait for the background write to fail and update the entry's state.
+  net::TestCompletionCallback flush_cb1;
+  backend->FlushQueueForTest(flush_cb1.callback());
+  EXPECT_THAT(flush_cb1.WaitForResult(), IsOk());
+
+  // 7. Verify that the entry is now in an error state.
+  ASSERT_TRUE(sql_entry->res_id_or_error()->data.has_value());
+  ASSERT_TRUE(std::holds_alternative<SqlPersistentStore::Error>(
+      sql_entry->res_id_or_error()->data.value()));
+  EXPECT_EQ(std::get<SqlPersistentStore::Error>(
+                sql_entry->res_id_or_error()->data.value()),
+            SqlPersistentStore::Error::kFailedForTesting);
+  EXPECT_EQ(backend->GetOptimisticWriteBufferTotalSizeForTesting(), 0);
+
+  // 8. Subsequent writes should fail immediately.
+  EXPECT_EQ(entry->WriteData(1, 0, write_buffer.get(), write_buffer->size(),
+                             base::DoNothing(), false),
+            net::ERR_FAILED);
+  EXPECT_EQ(backend->GetOptimisticWriteBufferTotalSizeForTesting(), 0);
+
+  entry->Close();
+
+  // 9. Since the entry should have been deleted from storage, OpenEntry will
+  //    fail.
+  TestEntryResultCompletionCallback open_cb2;
+  open_result = open_cb2.GetResult(
+      backend->OpenEntry(kKey, net::HIGHEST, open_cb2.callback()));
+  ASSERT_THAT(open_result.net_error(), IsError(net::ERR_FAILED));
+}
+
+TEST_F(SqlBackendImplTest, OptimisticWriteAfterSpeculativeCreateEntry) {
+  auto backend = CreateBackendAndInit();
+
+  // 1. Enable failure simulation.
+  backend->GetSqlStoreForTest()->SetSimulateDbFailureForTesting(true);
+
+  const std::string kKey = "my-key";
+
+  // 2. Create an entry. This should return immediately with a speculatively
+  //    created entry.
+  TestEntryResultCompletionCallback cb_create;
+  disk_cache::EntryResult create_result =
+      backend->CreateEntry(kKey, net::HIGHEST, cb_create.callback());
+  ASSERT_THAT(create_result.net_error(), IsOk());
+  auto* entry = create_result.ReleaseEntry();
+  ASSERT_TRUE(entry);
+
+  // 2. Disable failure simulation.
+  backend->GetSqlStoreForTest()->SetSimulateDbFailureForTesting(false);
+
+  // 3. This write should be optimistic, filling the buffer.
+  auto write_buffer1 =
+      base::MakeRefCounted<net::StringIOBuffer>(std::string(50, 'a'));
+  EXPECT_EQ(entry->WriteData(1, 0, write_buffer1.get(), write_buffer1->size(),
+                             base::DoNothing(), false),
+            static_cast<int>(write_buffer1->size()));
+  EXPECT_EQ(backend->GetOptimisticWriteBufferTotalSizeForTesting(),
+            write_buffer1->size());
+
+  // 4. Wait for the background creation and write to fail and update the
+  //    entry's state.
+  net::TestCompletionCallback flush_cb;
+  backend->FlushQueueForTest(flush_cb.callback());
+  EXPECT_THAT(flush_cb.WaitForResult(), IsOk());
+
+  auto* sql_entry = static_cast<SqlEntryImpl*>(entry);
+
+  // 6. Verify that the entry is now in an error state.
+  ASSERT_TRUE(sql_entry->res_id_or_error()->data.has_value());
+  ASSERT_TRUE(std::holds_alternative<SqlPersistentStore::Error>(
+      sql_entry->res_id_or_error()->data.value()));
+  EXPECT_EQ(std::get<SqlPersistentStore::Error>(
+                sql_entry->res_id_or_error()->data.value()),
+            SqlPersistentStore::Error::kFailedForTesting);
+
+  // 7. The buffer size should be set to 0.
+  EXPECT_EQ(backend->GetOptimisticWriteBufferTotalSizeForTesting(), 0);
+
+  entry->Close();
+}
+
 }  // namespace
 }  // namespace disk_cache
diff --git a/net/disk_cache/sql/sql_entry_impl.cc b/net/disk_cache/sql/sql_entry_impl.cc
index ac4c63db..8ab8eb5 100644
--- a/net/disk_cache/sql/sql_entry_impl.cc
+++ b/net/disk_cache/sql/sql_entry_impl.cc
@@ -226,12 +226,9 @@
   const auto old_body_end = body_end_;
   body_end_ = new_body_end;
 
-  // TODO(crbug.com/422065015): Consider implementing optimistic writes, similar
-  // to Simple Cache (see https://chromiumcodereview.appspot.com/13907009). This
-  // would allow returning synchronously if no other operations are pending.
-  backend_->WriteEntryData(key_, res_id_or_error_, old_body_end, body_end_,
-                           offset, buf, buf_len, truncate, std::move(callback));
-  return net::ERR_IO_PENDING;
+  return backend_->WriteEntryData(key_, res_id_or_error_, old_body_end,
+                                  body_end_, offset, buf, buf_len, truncate,
+                                  std::move(callback));
 }
 
 int SqlEntryImpl::ReadSparseData(int64_t offset,
diff --git a/net/disk_cache/sql/sql_persistent_store.cc b/net/disk_cache/sql/sql_persistent_store.cc
index 173c0f8e..2bdc308 100644
--- a/net/disk_cache/sql/sql_persistent_store.cc
+++ b/net/disk_cache/sql/sql_persistent_store.cc
@@ -227,13 +227,24 @@
   PopulateTraceDetails(store_status, dict);
 }
 
+// A helper function to record the time delay from posting a task to its
+// execution.
+void RecordPostingDelay(std::string_view method_name,
+                        base::TimeDelta posting_delay) {
+  base::UmaHistogramMicrosecondsTimes(
+      base::StrCat({kHistogramPrefix, method_name, ".PostingDelay"}),
+      posting_delay);
+}
+
 // Records timing and result histograms for a backend method. This logs the
 // method's duration to ".SuccessTime" or ".FailureTime" histograms and the
 // `Error` code to a ".Result" histogram.
 void RecordTimeAndErrorResultHistogram(std::string_view method_name,
+                                       base::TimeDelta posting_delay,
                                        base::TimeDelta time_delta,
                                        Error error,
                                        bool corruption_detected) {
+  RecordPostingDelay(method_name, posting_delay);
   base::UmaHistogramMicrosecondsTimes(
       base::StrCat({kHistogramPrefix, method_name,
                     error == Error::kOk ? ".SuccessTime" : ".FailureTime",
@@ -318,7 +329,7 @@
 
   // Initializes the database, including setting up the schema and reading
   // metadata. Returns the cache status and max size on success.
-  InitResultOrError Initialize();
+  InitResultOrError Initialize(base::TimeTicks start_time);
 
   int32_t GetEntryCount() const { return store_status_.entry_count; }
   int64_t GetSizeOfAllEntries() const {
@@ -330,52 +341,74 @@
   }
 
   EntryInfoOrErrorAndEvictionRequested OpenOrCreateEntry(
-      const CacheEntryKey& key);
-  OptionalEntryInfoOrError OpenEntry(const CacheEntryKey& key);
+      const CacheEntryKey& key,
+      base::TimeTicks start_time);
+  OptionalEntryInfoOrError OpenEntry(const CacheEntryKey& key,
+                                     base::TimeTicks start_time);
   EntryInfoOrErrorAndEvictionRequested CreateEntry(const CacheEntryKey& key,
                                                    base::Time creation_time,
-                                                   bool run_existance_check);
+                                                   bool run_existance_check,
+                                                   base::TimeTicks start_time);
 
-  ErrorAndEvictionRequested DoomEntry(const CacheEntryKey& key, ResId res_id);
+  ErrorAndEvictionRequested DoomEntry(const CacheEntryKey& key,
+                                      ResId res_id,
+                                      base::TimeTicks start_time);
   ErrorAndEvictionRequested DeleteDoomedEntry(const CacheEntryKey& key,
-                                              ResId res_id);
-  Error DeleteDoomedEntries(base::flat_set<ResId> excluded_res_ids);
+                                              ResId res_id,
+                                              base::TimeTicks start_time);
+  Error DeleteDoomedEntries(base::flat_set<ResId> excluded_res_ids,
+                            base::TimeTicks start_time);
   ResIdAndHashKeyListOrErrorAndEvictionRequested DeleteLiveEntry(
-      const CacheEntryKey& key);
+      const CacheEntryKey& key,
+      base::TimeTicks start_time);
 
-  ErrorAndEvictionRequested DeleteAllEntries();
+  ErrorAndEvictionRequested DeleteAllEntries(base::TimeTicks start_time);
   ResIdAndHashKeyListOrErrorAndEvictionRequested DeleteLiveEntriesBetween(
       base::Time initial_time,
       base::Time end_time,
-      base::flat_set<CacheEntryKey> excluded_keys);
+      base::flat_set<CacheEntryKey> excluded_keys,
+      base::TimeTicks start_time);
   Error UpdateEntryLastUsedByKey(const CacheEntryKey& key,
-                                 base::Time last_used);
-  Error UpdateEntryLastUsedByResId(ResId res_id, base::Time last_used);
+                                 base::Time last_used,
+                                 base::TimeTicks start_time);
+  Error UpdateEntryLastUsedByResId(ResId res_id,
+                                   base::Time last_used,
+                                   base::TimeTicks start_time);
   ErrorAndEvictionRequested UpdateEntryHeaderAndLastUsed(
       const CacheEntryKey& key,
       ResId res_id,
       base::Time last_used,
       scoped_refptr<net::IOBuffer> buffer,
-      int64_t header_size_delta);
+      int64_t header_size_delta,
+      base::TimeTicks start_time);
   ErrorAndEvictionRequested WriteEntryData(const CacheEntryKey& key,
                                            ResId res_id,
                                            int64_t old_body_end,
                                            int64_t offset,
                                            scoped_refptr<net::IOBuffer> buffer,
                                            int buf_len,
-                                           bool truncate);
+                                           bool truncate,
+                                           base::TimeTicks start_time);
   IntOrError ReadEntryData(ResId res_id,
                            int64_t offset,
                            scoped_refptr<net::IOBuffer> buffer,
                            int buf_len,
                            int64_t body_end,
-                           bool sparse_reading);
-  RangeResult GetEntryAvailableRange(ResId res_id, int64_t offset, int len);
+                           bool sparse_reading,
+                           base::TimeTicks start_time);
+  RangeResult GetEntryAvailableRange(ResId res_id,
+                                     int64_t offset,
+                                     int len,
+                                     base::TimeTicks start_time);
   int64_t CalculateSizeOfEntriesBetween(base::Time initial_time,
-                                        base::Time end_time);
-  OptionalEntryInfoWithIdAndKey OpenLatestEntryBeforeResId(ResId res_id_cursor);
+                                        base::Time end_time,
+                                        base::TimeTicks start_time);
+  OptionalEntryInfoWithIdAndKey OpenLatestEntryBeforeResId(
+      ResId res_id_cursor,
+      base::TimeTicks start_time);
   ResIdAndHashKeyListOrErrorAndEvictionRequested RunEviction(
-      base::flat_set<CacheEntryKey> excluded_keys);
+      base::flat_set<CacheEntryKey> excluded_keys,
+      base::TimeTicks start_time);
   bool MaybeRunCheckpoint();
 
   void EnableStrictCorruptionCheckForTesting() {
@@ -543,15 +576,17 @@
   int wal_pages_ = 0;
 };
 
-InitResultOrError Backend::Initialize() {
+InitResultOrError Backend::Initialize(base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN0("disk_cache", "SqlBackend.Initialize");
   base::ElapsedTimer timer;
   CHECK(!db_init_status_.has_value());
   bool corruption_detected = false;
   HashResIdSet index;
   db_init_status_ = InitializeInternal(corruption_detected, index);
-  RecordTimeAndErrorResultHistogram("Initialize", timer.Elapsed(),
-                                    *db_init_status_, corruption_detected);
+  RecordTimeAndErrorResultHistogram("Initialize", posting_delay,
+                                    timer.Elapsed(), *db_init_status_,
+                                    corruption_detected);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.Initialize", "result",
                    [&](perfetto::TracedValue trace_context) {
                      auto dict = std::move(trace_context).WriteDictionary();
@@ -695,7 +730,9 @@
 }
 
 EntryInfoOrErrorAndEvictionRequested Backend::OpenOrCreateEntry(
-    const CacheEntryKey& key) {
+    const CacheEntryKey& key,
+    base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.OpenOrCreateEntry", "data",
                      [&](perfetto::TracedValue trace_context) {
                        auto dict = std::move(trace_context).WriteDictionary();
@@ -705,9 +742,9 @@
   base::ElapsedTimer timer;
   bool corruption_detected = false;
   auto result = OpenOrCreateEntryInternal(key, corruption_detected);
-  RecordTimeAndErrorResultHistogram("OpenOrCreateEntry", timer.Elapsed(),
-                                    result.error_or(Error::kOk),
-                                    corruption_detected);
+  RecordTimeAndErrorResultHistogram(
+      "OpenOrCreateEntry", posting_delay, timer.Elapsed(),
+      result.error_or(Error::kOk), corruption_detected);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.OpenOrCreateEntry", "result",
                    [&](perfetto::TracedValue trace_context) {
                      auto dict = std::move(trace_context).WriteDictionary();
@@ -738,7 +775,9 @@
                              corruption_detected);
 }
 
-OptionalEntryInfoOrError Backend::OpenEntry(const CacheEntryKey& key) {
+OptionalEntryInfoOrError Backend::OpenEntry(const CacheEntryKey& key,
+                                            base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.OpenEntry", "data",
                      [&](perfetto::TracedValue trace_context) {
                        auto dict = std::move(trace_context).WriteDictionary();
@@ -747,7 +786,7 @@
                      });
   base::ElapsedTimer timer;
   auto result = OpenEntryInternal(key);
-  RecordTimeAndErrorResultHistogram("OpenEntry", timer.Elapsed(),
+  RecordTimeAndErrorResultHistogram("OpenEntry", posting_delay, timer.Elapsed(),
                                     result.error_or(Error::kOk),
                                     /*corruption_detected=*/false);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.OpenEntry", "result",
@@ -794,7 +833,9 @@
 EntryInfoOrErrorAndEvictionRequested Backend::CreateEntry(
     const CacheEntryKey& key,
     base::Time creation_time,
-    bool run_existance_check) {
+    bool run_existance_check,
+    base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.CreateEntry", "data",
                      [&](perfetto::TracedValue trace_context) {
                        auto dict = std::move(trace_context).WriteDictionary();
@@ -805,9 +846,9 @@
   bool corruption_detected = false;
   auto result = CreateEntryInternal(key, creation_time, run_existance_check,
                                     corruption_detected);
-  RecordTimeAndErrorResultHistogram("CreateEntry", timer.Elapsed(),
-                                    result.error_or(Error::kOk),
-                                    corruption_detected);
+  RecordTimeAndErrorResultHistogram(
+      "CreateEntry", posting_delay, timer.Elapsed(),
+      result.error_or(Error::kOk), corruption_detected);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.CreateEntry", "result",
                    [&](perfetto::TracedValue trace_context) {
                      auto dict = std::move(trace_context).WriteDictionary();
@@ -881,7 +922,9 @@
 }
 
 ErrorAndEvictionRequested Backend::DoomEntry(const CacheEntryKey& key,
-                                             ResId res_id) {
+                                             ResId res_id,
+                                             base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.DoomEntry", "data",
                      [&](perfetto::TracedValue trace_context) {
                        auto dict = std::move(trace_context).WriteDictionary();
@@ -892,8 +935,8 @@
   base::ElapsedTimer timer;
   bool corruption_detected = false;
   auto result = DoomEntryInternal(res_id, corruption_detected);
-  RecordTimeAndErrorResultHistogram("DoomEntry", timer.Elapsed(), result,
-                                    corruption_detected);
+  RecordTimeAndErrorResultHistogram("DoomEntry", posting_delay, timer.Elapsed(),
+                                    result, corruption_detected);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.DoomEntry", "result",
                    [&](perfetto::TracedValue trace_context) {
                      auto dict = std::move(trace_context).WriteDictionary();
@@ -955,8 +998,11 @@
       /*total_size_delta=*/total_size_delta.ValueOrDie(), corruption_detected);
 }
 
-ErrorAndEvictionRequested Backend::DeleteDoomedEntry(const CacheEntryKey& key,
-                                                     ResId res_id) {
+ErrorAndEvictionRequested Backend::DeleteDoomedEntry(
+    const CacheEntryKey& key,
+    ResId res_id,
+    base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.DeleteDoomedEntry", "data",
                      [&](perfetto::TracedValue trace_context) {
                        auto dict = std::move(trace_context).WriteDictionary();
@@ -966,8 +1012,9 @@
                      });
   base::ElapsedTimer timer;
   auto result = DeleteDoomedEntryInternal(res_id);
-  RecordTimeAndErrorResultHistogram("DeleteDoomedEntry", timer.Elapsed(),
-                                    result, /*corruption_detected=*/false);
+  RecordTimeAndErrorResultHistogram("DeleteDoomedEntry", posting_delay,
+                                    timer.Elapsed(), result,
+                                    /*corruption_detected=*/false);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.DeleteDoomedEntry", "result",
                    [&](perfetto::TracedValue trace_context) {
                      auto dict = std::move(trace_context).WriteDictionary();
@@ -1014,15 +1061,18 @@
   return transaction.Commit() ? Error::kOk : Error::kFailedToCommitTransaction;
 }
 
-Error Backend::DeleteDoomedEntries(base::flat_set<ResId> excluded_res_ids) {
+Error Backend::DeleteDoomedEntries(base::flat_set<ResId> excluded_res_ids,
+                                   base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN0("disk_cache", "SqlBackend.DeleteDoomedEntries");
   base::ElapsedTimer timer;
   bool corruption_detected = false;
   size_t deleted_count = 0;
   auto result = DeleteDoomedEntriesInternal(excluded_res_ids, deleted_count,
                                             corruption_detected);
-  RecordTimeAndErrorResultHistogram("DeleteDoomedEntries", timer.Elapsed(),
-                                    result, corruption_detected);
+  RecordTimeAndErrorResultHistogram("DeleteDoomedEntries", posting_delay,
+                                    timer.Elapsed(), result,
+                                    corruption_detected);
   base::UmaHistogramCounts100("Net.SqlDiskCache.DeleteDoomedEntriesCount",
                               deleted_count);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.DeleteDoomedEntries", "result",
@@ -1088,7 +1138,9 @@
 }
 
 ResIdAndHashKeyListOrErrorAndEvictionRequested Backend::DeleteLiveEntry(
-    const CacheEntryKey& key) {
+    const CacheEntryKey& key,
+    base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.DeleteLiveEntry", "data",
                      [&](perfetto::TracedValue trace_context) {
                        auto dict = std::move(trace_context).WriteDictionary();
@@ -1098,9 +1150,9 @@
   base::ElapsedTimer timer;
   bool corruption_detected = false;
   auto result = DeleteLiveEntryInternal(key, corruption_detected);
-  RecordTimeAndErrorResultHistogram("DeleteLiveEntry", timer.Elapsed(),
-                                    result.error_or(Error::kOk),
-                                    corruption_detected);
+  RecordTimeAndErrorResultHistogram(
+      "DeleteLiveEntry", posting_delay, timer.Elapsed(),
+      result.error_or(Error::kOk), corruption_detected);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.DeleteLiveEntry", "result",
                    [&](perfetto::TracedValue trace_context) {
                      auto dict = std::move(trace_context).WriteDictionary();
@@ -1180,7 +1232,9 @@
              : base::unexpected(error);
 }
 
-ErrorAndEvictionRequested Backend::DeleteAllEntries() {
+ErrorAndEvictionRequested Backend::DeleteAllEntries(
+    base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.DeleteAllEntries", "data",
                      [&](perfetto::TracedValue trace_context) {
                        auto dict = std::move(trace_context).WriteDictionary();
@@ -1189,7 +1243,8 @@
   base::ElapsedTimer timer;
   bool corruption_detected = false;
   Error result = DeleteAllEntriesInternal(corruption_detected);
-  RecordTimeAndErrorResultHistogram("DeleteAllEntries", timer.Elapsed(), result,
+  RecordTimeAndErrorResultHistogram("DeleteAllEntries", posting_delay,
+                                    timer.Elapsed(), result,
                                     corruption_detected);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.DeleteAllEntries", "result",
                    [&](perfetto::TracedValue trace_context) {
@@ -1240,7 +1295,9 @@
 ResIdAndHashKeyListOrErrorAndEvictionRequested
 Backend::DeleteLiveEntriesBetween(base::Time initial_time,
                                   base::Time end_time,
-                                  base::flat_set<CacheEntryKey> excluded_keys) {
+                                  base::flat_set<CacheEntryKey> excluded_keys,
+                                  base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.DeleteLiveEntriesBetween",
                      "data", [&](perfetto::TracedValue trace_context) {
                        auto dict = std::move(trace_context).WriteDictionary();
@@ -1255,9 +1312,9 @@
   bool corruption_detected = false;
   auto result = DeleteLiveEntriesBetweenInternal(
       initial_time, end_time, excluded_keys, corruption_detected);
-  RecordTimeAndErrorResultHistogram("DeleteLiveEntriesBetween", timer.Elapsed(),
-                                    result.error_or(Error::kOk),
-                                    corruption_detected);
+  RecordTimeAndErrorResultHistogram(
+      "DeleteLiveEntriesBetween", posting_delay, timer.Elapsed(),
+      result.error_or(Error::kOk), corruption_detected);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.DeleteLiveEntriesBetween",
                    "result", [&](perfetto::TracedValue trace_context) {
                      auto dict = std::move(trace_context).WriteDictionary();
@@ -1337,7 +1394,9 @@
 }
 
 Error Backend::UpdateEntryLastUsedByKey(const CacheEntryKey& key,
-                                        base::Time last_used) {
+                                        base::Time last_used,
+                                        base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.UpdateEntryLastUsedByKey",
                      "data", [&](perfetto::TracedValue trace_context) {
                        auto dict = std::move(trace_context).WriteDictionary();
@@ -1346,8 +1405,9 @@
                      });
   base::ElapsedTimer timer;
   auto result = UpdateEntryLastUsedByKeyInternal(key, last_used);
-  RecordTimeAndErrorResultHistogram("UpdateEntryLastUsedByKey", timer.Elapsed(),
-                                    result, /*corruption_detected=*/false);
+  RecordTimeAndErrorResultHistogram("UpdateEntryLastUsedByKey", posting_delay,
+                                    timer.Elapsed(), result,
+                                    /*corruption_detected=*/false);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.UpdateEntryLastUsedByKey",
                    "result", [&](perfetto::TracedValue trace_context) {
                      auto dict = std::move(trace_context).WriteDictionary();
@@ -1385,7 +1445,10 @@
   return change_count == 0 ? Error::kNotFound : Error::kOk;
 }
 
-Error Backend::UpdateEntryLastUsedByResId(ResId res_id, base::Time last_used) {
+Error Backend::UpdateEntryLastUsedByResId(ResId res_id,
+                                          base::Time last_used,
+                                          base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.UpdateEntryLastUsedByResId",
                      "data", [&](perfetto::TracedValue trace_context) {
                        auto dict = std::move(trace_context).WriteDictionary();
@@ -1394,7 +1457,7 @@
                      });
   base::ElapsedTimer timer;
   auto result = UpdateEntryLastUsedByResIdInternal(res_id, last_used);
-  RecordTimeAndErrorResultHistogram("UpdateEntryLastUsedByResId",
+  RecordTimeAndErrorResultHistogram("UpdateEntryLastUsedByResId", posting_delay,
                                     timer.Elapsed(), result,
                                     /*corruption_detected=*/false);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.UpdateEntryLastUsedByResId",
@@ -1438,7 +1501,9 @@
     ResId res_id,
     base::Time last_used,
     scoped_refptr<net::IOBuffer> buffer,
-    int64_t header_size_delta) {
+    int64_t header_size_delta,
+    base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.UpdateEntryHeaderAndLastUsed",
                      "data", [&](perfetto::TracedValue trace_context) {
                        auto dict = std::move(trace_context).WriteDictionary();
@@ -1454,7 +1519,7 @@
       key, res_id, last_used, std::move(buffer), header_size_delta,
       corruption_detected);
   RecordTimeAndErrorResultHistogram("UpdateEntryHeaderAndLastUsed",
-                                    timer.Elapsed(), result,
+                                    posting_delay, timer.Elapsed(), result,
                                     corruption_detected);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.UpdateEntryHeaderAndLastUsed",
                    "result", [&](perfetto::TracedValue trace_context) {
@@ -1517,7 +1582,9 @@
     int64_t offset,
     scoped_refptr<net::IOBuffer> buffer,
     int buf_len,
-    bool truncate) {
+    bool truncate,
+    base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.WriteEntryData", "data",
                      [&](perfetto::TracedValue trace_context) {
                        auto dict = std::move(trace_context).WriteDictionary();
@@ -1534,7 +1601,8 @@
   auto result =
       WriteEntryDataInternal(res_id, old_body_end, offset, std::move(buffer),
                              buf_len, truncate, corruption_detected);
-  RecordTimeAndErrorResultHistogram("WriteEntryData", timer.Elapsed(), result,
+  RecordTimeAndErrorResultHistogram("WriteEntryData", posting_delay,
+                                    timer.Elapsed(), result,
                                     corruption_detected);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.WriteEntryData", "result",
                    [&](perfetto::TracedValue trace_context) {
@@ -1928,7 +1996,9 @@
                                   scoped_refptr<net::IOBuffer> buffer,
                                   int buf_len,
                                   int64_t body_end,
-                                  bool sparse_reading) {
+                                  bool sparse_reading,
+                                  base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.ReadEntryData", "data",
                      [&](perfetto::TracedValue trace_context) {
                        auto dict = std::move(trace_context).WriteDictionary();
@@ -1944,9 +2014,9 @@
   auto result =
       ReadEntryDataInternal(res_id, offset, std::move(buffer), buf_len,
                             body_end, sparse_reading, corruption_detected);
-  RecordTimeAndErrorResultHistogram("ReadEntryData", timer.Elapsed(),
-                                    result.error_or(Error::kOk),
-                                    corruption_detected);
+  RecordTimeAndErrorResultHistogram(
+      "ReadEntryData", posting_delay, timer.Elapsed(),
+      result.error_or(Error::kOk), corruption_detected);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.ReadEntryData", "result",
                    [&](perfetto::TracedValue trace_context) {
                      auto dict = std::move(trace_context).WriteDictionary();
@@ -2042,7 +2112,9 @@
 
 RangeResult Backend::GetEntryAvailableRange(ResId res_id,
                                             int64_t offset,
-                                            int len) {
+                                            int len,
+                                            base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.GetEntryAvailableRange", "data",
                      [&](perfetto::TracedValue trace_context) {
                        auto dict = std::move(trace_context).WriteDictionary();
@@ -2052,8 +2124,9 @@
                      });
   base::ElapsedTimer timer;
   auto result = GetEntryAvailableRangeInternal(res_id, offset, len);
-  RecordTimeAndErrorResultHistogram("GetEntryAvailableRange", timer.Elapsed(),
-                                    Error::kOk, /*corruption_detected=*/false);
+  RecordTimeAndErrorResultHistogram("GetEntryAvailableRange", posting_delay,
+                                    timer.Elapsed(), Error::kOk,
+                                    /*corruption_detected=*/false);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.GetEntryAvailableRange", "result",
                    [&](perfetto::TracedValue trace_context) {
                      auto dict = std::move(trace_context).WriteDictionary();
@@ -2114,10 +2187,12 @@
 }
 
 int64_t Backend::CalculateSizeOfEntriesBetween(base::Time initial_time,
-                                               base::Time end_time) {
+                                               base::Time end_time,
+                                               base::TimeTicks start_time) {
   if (initial_time == base::Time::Min() && end_time == base::Time::Max()) {
     return GetSizeOfAllEntries();
   }
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.CalculateSizeOfEntriesBetween",
                      "data", [&](perfetto::TracedValue trace_context) {
                        auto dict = std::move(trace_context).WriteDictionary();
@@ -2127,7 +2202,7 @@
   base::ElapsedTimer timer;
   auto result = CalculateSizeOfEntriesBetweenInternal(initial_time, end_time);
   RecordTimeAndErrorResultHistogram("CalculateSizeOfEntriesBetween",
-                                    timer.Elapsed(), Error::kOk,
+                                    posting_delay, timer.Elapsed(), Error::kOk,
                                     /*corruption_detected=*/false);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.CalculateSizeOfEntriesBetween",
                    "result", result);
@@ -2155,7 +2230,9 @@
 }
 
 OptionalEntryInfoWithIdAndKey Backend::OpenLatestEntryBeforeResId(
-    ResId res_id_cursor) {
+    ResId res_id_cursor,
+    base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT_BEGIN1("disk_cache", "SqlBackend.OpenLatestEntryBeforeResId",
                      "data", [&](perfetto::TracedValue trace_context) {
                        auto dict = std::move(trace_context).WriteDictionary();
@@ -2165,7 +2242,7 @@
   bool corruption_detected = false;
   auto result =
       OpenLatestEntryBeforeResIdInternal(res_id_cursor, corruption_detected);
-  RecordTimeAndErrorResultHistogram("OpenLatestEntryBeforeResId",
+  RecordTimeAndErrorResultHistogram("OpenLatestEntryBeforeResId", posting_delay,
                                     timer.Elapsed(), Error::kOk,
                                     corruption_detected);
   TRACE_EVENT_END1("disk_cache", "SqlBackend.OpenLatestEntryBeforeResId",
@@ -2212,15 +2289,17 @@
 }
 
 ResIdAndHashKeyListOrErrorAndEvictionRequested Backend::RunEviction(
-    base::flat_set<CacheEntryKey> excluded_keys) {
+    base::flat_set<CacheEntryKey> excluded_keys,
+    base::TimeTicks start_time) {
+  const base::TimeDelta posting_delay = base::TimeTicks::Now() - start_time;
   TRACE_EVENT0("disk_cache", "SqlBackend.RunEviction");
   base::ElapsedTimer timer;
   bool corruption_detected = false;
   auto result =
       RunEvictionInternal(std::move(excluded_keys), corruption_detected);
-  RecordTimeAndErrorResultHistogram("RunEviction", timer.Elapsed(),
-                                    result.error_or(Error::kOk),
-                                    corruption_detected);
+  RecordTimeAndErrorResultHistogram(
+      "RunEviction", posting_delay, timer.Elapsed(),
+      result.error_or(Error::kOk), corruption_detected);
   MaybeCrashIfCorrupted(corruption_detected);
   return ResIdAndHashKeyListOrErrorAndEvictionRequested(std::move(result),
                                                         ShouldStartEviction());
@@ -2447,6 +2526,7 @@
   // Kicks off the asynchronous initialization of the backend.
   void Initialize(ErrorCallback callback) override {
     backend_.AsyncCall(&Backend::Initialize)
+        .WithArgs(base::TimeTicks::Now())
         .Then(base::BindOnce(
             [](base::WeakPtr<SqlPersistentStoreImpl> weak_ptr,
                ErrorCallback callback, InitResultOrError result) {
@@ -2464,7 +2544,7 @@
   void OpenOrCreateEntry(const CacheEntryKey& key,
                          EntryInfoOrErrorCallback callback) override {
     backend_.AsyncCall(&Backend::OpenOrCreateEntry)
-        .WithArgs(key)
+        .WithArgs(key, base::TimeTicks::Now())
         .Then(WrapEntryInfoOrErrorCallback(
             std::move(callback), key,
             IndexMismatchLocation::kOpenOrCreateEntry));
@@ -2472,7 +2552,7 @@
   void OpenEntry(const CacheEntryKey& key,
                  OptionalEntryInfoOrErrorCallback callback) override {
     backend_.AsyncCall(&Backend::OpenEntry)
-        .WithArgs(key)
+        .WithArgs(key, base::TimeTicks::Now())
         .Then(WrapCallback(std::move(callback)));
   }
   void CreateEntry(const CacheEntryKey& key,
@@ -2480,7 +2560,8 @@
                    EntryInfoOrErrorCallback callback) override {
     bool run_existance_check = !index_ || index_->Contains(key.hash());
     backend_.AsyncCall(&Backend::CreateEntry)
-        .WithArgs(key, creation_time, run_existance_check)
+        .WithArgs(key, creation_time, run_existance_check,
+                  base::TimeTicks::Now())
         .Then(WrapEntryInfoOrErrorCallback(
             std::move(callback), key, IndexMismatchLocation::kCreateEntry));
   }
@@ -2488,7 +2569,7 @@
                  ResId res_id,
                  ErrorCallback callback) override {
     backend_.AsyncCall(&Backend::DoomEntry)
-        .WithArgs(key, res_id)
+        .WithArgs(key, res_id, base::TimeTicks::Now())
         .Then(base::BindOnce(
             [](base::WeakPtr<SqlPersistentStoreImpl> weak_ptr,
                CacheEntryKey::Hash key_hash, ResId res_id,
@@ -2513,24 +2594,25 @@
                          ResId res_id,
                          ErrorCallback callback) override {
     backend_.AsyncCall(&Backend::DeleteDoomedEntry)
-        .WithArgs(key, res_id)
+        .WithArgs(key, res_id, base::TimeTicks::Now())
         .Then(WrapCallbackWithEvictionRequested(std::move(callback)));
   }
   void DeleteDoomedEntries(base::flat_set<ResId> excluded_res_ids,
                            ErrorCallback callback) override {
     backend_.AsyncCall(&Backend::DeleteDoomedEntries)
-        .WithArgs(std::move(excluded_res_ids))
+        .WithArgs(std::move(excluded_res_ids), base::TimeTicks::Now())
         .Then(WrapCallback(std::move(callback)));
   }
   void DeleteLiveEntry(const CacheEntryKey& key,
                        ErrorCallback callback) override {
     backend_.AsyncCall(&Backend::DeleteLiveEntry)
-        .WithArgs(key)
+        .WithArgs(key, base::TimeTicks::Now())
         .Then(WrapErrorCallbackToRemoveFromIndex(
             std::move(callback), IndexMismatchLocation::kDeleteLiveEntry));
   }
   void DeleteAllEntries(ErrorCallback callback) override {
     backend_.AsyncCall(&Backend::DeleteAllEntries)
+        .WithArgs(base::TimeTicks::Now())
         .Then(base::BindOnce(
             [](base::WeakPtr<SqlPersistentStoreImpl> weak_ptr,
                ErrorCallback callback, ErrorAndEvictionRequested result) {
@@ -2550,7 +2632,8 @@
                                 base::flat_set<CacheEntryKey> excluded_keys,
                                 ErrorCallback callback) override {
     backend_.AsyncCall(&Backend::DeleteLiveEntriesBetween)
-        .WithArgs(initial_time, end_time, std::move(excluded_keys))
+        .WithArgs(initial_time, end_time, std::move(excluded_keys),
+                  base::TimeTicks::Now())
         .Then(WrapErrorCallbackToRemoveFromIndex(
             std::move(callback),
             IndexMismatchLocation::kDeleteLiveEntriesBetween));
@@ -2559,14 +2642,14 @@
                                 base::Time last_used,
                                 ErrorCallback callback) override {
     backend_.AsyncCall(&Backend::UpdateEntryLastUsedByKey)
-        .WithArgs(key, last_used)
+        .WithArgs(key, last_used, base::TimeTicks::Now())
         .Then(WrapCallback(std::move(callback)));
   }
   void UpdateEntryLastUsedByResId(ResId res_id,
                                   base::Time last_used,
                                   ErrorCallback callback) override {
     backend_.AsyncCall(&Backend::UpdateEntryLastUsedByResId)
-        .WithArgs(res_id, last_used)
+        .WithArgs(res_id, last_used, base::TimeTicks::Now())
         .Then(WrapCallback(std::move(callback)));
   }
   void UpdateEntryHeaderAndLastUsed(const CacheEntryKey& key,
@@ -2576,7 +2659,8 @@
                                     int64_t header_size_delta,
                                     ErrorCallback callback) override {
     backend_.AsyncCall(&Backend::UpdateEntryHeaderAndLastUsed)
-        .WithArgs(key, res_id, last_used, std::move(buffer), header_size_delta)
+        .WithArgs(key, res_id, last_used, std::move(buffer), header_size_delta,
+                  base::TimeTicks::Now())
         .Then(WrapCallbackWithEvictionRequested(std::move(callback)));
   }
 
@@ -2590,7 +2674,7 @@
                       ErrorCallback callback) override {
     backend_.AsyncCall(&Backend::WriteEntryData)
         .WithArgs(key, res_id, old_body_end, offset, std::move(buffer), buf_len,
-                  truncate)
+                  truncate, base::TimeTicks::Now())
         .Then(WrapCallbackWithEvictionRequested(std::move(callback)));
   }
   void ReadEntryData(ResId res_id,
@@ -2602,7 +2686,7 @@
                      IntOrErrorCallback callback) override {
     backend_.AsyncCall(&Backend::ReadEntryData)
         .WithArgs(res_id, offset, std::move(buffer), buf_len, body_end,
-                  sparse_reading)
+                  sparse_reading, base::TimeTicks::Now())
         .Then(WrapCallback(std::move(callback)));
   }
   void GetEntryAvailableRange(ResId res_id,
@@ -2610,21 +2694,21 @@
                               int len,
                               RangeResultCallback callback) override {
     backend_.AsyncCall(&Backend::GetEntryAvailableRange)
-        .WithArgs(res_id, offset, len)
+        .WithArgs(res_id, offset, len, base::TimeTicks::Now())
         .Then(WrapCallback(std::move(callback)));
   }
   void CalculateSizeOfEntriesBetween(base::Time initial_time,
                                      base::Time end_time,
                                      Int64OrErrorCallback callback) override {
     backend_.AsyncCall(&Backend::CalculateSizeOfEntriesBetween)
-        .WithArgs(initial_time, end_time)
+        .WithArgs(initial_time, end_time, base::TimeTicks::Now())
         .Then(WrapCallback(std::move(callback)));
   }
   void OpenLatestEntryBeforeResId(
       ResId res_id_cursor,
       OptionalEntryInfoWithIdAndKeyCallback callback) override {
     backend_.AsyncCall(&Backend::OpenLatestEntryBeforeResId)
-        .WithArgs(res_id_cursor)
+        .WithArgs(res_id_cursor, base::TimeTicks::Now())
         .Then(WrapCallback(std::move(callback)));
   }
   bool ShouldStartEviction() override {
@@ -2635,7 +2719,7 @@
     CHECK(!eviction_in_progress_);
     eviction_in_progress_ = true;
     backend_.AsyncCall(&Backend::RunEviction)
-        .WithArgs(std::move(excluded_keys))
+        .WithArgs(std::move(excluded_keys), base::TimeTicks::Now())
         .Then(base::BindOnce(
             [](base::WeakPtr<SqlPersistentStoreImpl> weak_ptr,
                ErrorCallback callback,
diff --git a/net/disk_cache/sql/sql_persistent_store.h b/net/disk_cache/sql/sql_persistent_store.h
index 5c2de2f..f1a7632 100644
--- a/net/disk_cache/sql/sql_persistent_store.h
+++ b/net/disk_cache/sql/sql_persistent_store.h
@@ -68,7 +68,8 @@
     kInvalidArgument = 14,
     kBodyEndMismatch = 15,
     kFailedForTesting = 16,
-    kMaxValue = kFailedForTesting
+    kAborted = 17,
+    kMaxValue = kAborted
   };
   // LINT.ThenChange(//tools/metrics/histograms/metadata/net/enums.xml:SqlDiskCacheStoreError)
 
diff --git a/net/http/http_no_vary_search_data.cc b/net/http/http_no_vary_search_data.cc
index 67dd159c..cd212d8f 100644
--- a/net/http/http_no_vary_search_data.cc
+++ b/net/http/http_no_vary_search_data.cc
@@ -9,12 +9,15 @@
 
 #include "base/containers/contains.h"
 #include "base/containers/flat_set.h"
+#include "base/debug/crash_logging.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/feature_list.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/types/expected.h"
 #include "net/base/features.h"
 #include "net/base/pickle.h"
 #include "net/base/url_search_params.h"
+#include "net/base/url_search_params_view.h"
 #include "net/base/url_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/structured_headers.h"
@@ -38,6 +41,42 @@
   return keys;
 }
 
+template <typename ParamsType>
+void ApplyNoVarySearchRulesToParams(const HttpNoVarySearchData& rules,
+                                    ParamsType& params) {
+  // Ignore all the query search params that the URL is not varying on.
+  if (rules.vary_by_default()) {
+    params.DeleteAllWithNames(rules.no_vary_params());
+  } else {
+    params.DeleteAllExceptWithNames(rules.vary_params());
+  }
+  // Sort the params if the order of the search params in the query
+  // is ignored.
+  if (!rules.vary_on_key_order()) {
+    params.Sort();
+  }
+}
+
+template <typename ParamsType>
+void ApplyNoVarySearchRulesToBothParams(const HttpNoVarySearchData& rules,
+                                        ParamsType& params_a,
+                                        ParamsType& params_b) {
+  ApplyNoVarySearchRulesToParams(rules, params_a);
+  ApplyNoVarySearchRulesToParams(rules, params_b);
+}
+
+// Extracts the "base URL" (everything before the query or fragment) from `url`.
+// It relies on the fact that GURL canonicalizes http(s) URLs to not contain '?'
+// or '#' before the start of the query. It's a lot faster than using
+// GURL::Replacements to do the same thing, as no allocations or copies are
+// needed.
+std::string_view ExtractBaseUrl(const GURL& url) {
+  const std::string_view view(url.possibly_invalid_spec());
+  size_t end_of_base = view.find_first_of("?#");
+  // This returns the whole of `view` if `end_of_base` is std::string::npos.
+  return view.substr(0, end_of_base);
+}
+
 }  // namespace
 
 HttpNoVarySearchData::HttpNoVarySearchData() = default;
@@ -51,36 +90,36 @@
     default;
 
 bool HttpNoVarySearchData::AreEquivalent(const GURL& a, const GURL& b) const {
-  // Check urls without query and reference (fragment) for equality first.
-  GURL::Replacements replacements;
-  replacements.ClearRef();
-  replacements.ClearQuery();
-  if (a.ReplaceComponents(replacements) != b.ReplaceComponents(replacements)) {
-    return false;
+  CHECK(a.is_valid());
+  CHECK(b.is_valid());
+  if (base::FeatureList::IsEnabled(
+          features::kHttpNoVarySearchDataUseNewAreEquivalent)) {
+    const bool result = AreEquivalentNewImpl(a, b);
+    if (features::kHttpNoVarySearchDataAreEquivalentCheckResult.Get()) {
+      const bool old_result = AreEquivalentOldImpl(a, b);
+      if (old_result != result) {
+        SCOPED_CRASH_KEY_BOOL("NoVarySearch", "old_result", old_result);
+        SCOPED_CRASH_KEY_BOOL("NoVarySearch", "new_result", result);
+        // The full URLs are necessary to debug issues if they occur. This
+        // debugging code will be removed as quickly as possible once the old
+        // and new implementations are proved to have identical behavior.
+        SCOPED_CRASH_KEY_STRING1024("NoVarySearch", "url_a",
+                                    a.possibly_invalid_spec());
+        SCOPED_CRASH_KEY_STRING1024("NoVarySearch", "url_b",
+                                    b.possibly_invalid_spec());
+        SCOPED_CRASH_KEY_STRING256("NoVarySearch", "nv_params",
+                                   base::JoinString(no_vary_params_, ","));
+        SCOPED_CRASH_KEY_STRING256("NoVarySearch", "v_params",
+                                   base::JoinString(vary_params_, ","));
+        SCOPED_CRASH_KEY_BOOL("NoVarySearch", "key_order", vary_on_key_order_);
+        SCOPED_CRASH_KEY_BOOL("NoVarySearch", "by_default", vary_by_default_);
+        base::debug::DumpWithoutCrashing();
+      }
+    }
+    return result;
   }
 
-  // If equal, look at how HttpNoVarySearchData argument affects
-  // search params variance.
-  UrlSearchParams a_search_params(a);
-  UrlSearchParams b_search_params(b);
-  // Ignore all the query search params that the URL is not varying on.
-  if (vary_by_default()) {
-    a_search_params.DeleteAllWithNames(no_vary_params());
-    b_search_params.DeleteAllWithNames(no_vary_params());
-  } else {
-    a_search_params.DeleteAllExceptWithNames(vary_params());
-    b_search_params.DeleteAllExceptWithNames(vary_params());
-  }
-  // Sort the params if the order of the search params in the query
-  // is ignored.
-  if (!vary_on_key_order()) {
-    a_search_params.Sort();
-    b_search_params.Sort();
-  }
-  // Check Search Params for equality
-  // All search params, in order, need to have the same keys and the same
-  // values.
-  return a_search_params.params() == b_search_params.params();
+  return AreEquivalentOldImpl(a, b);
 }
 
 // static
@@ -147,6 +186,16 @@
   return vary_by_default_;
 }
 
+bool HttpNoVarySearchData::AreEquivalentOldImplForTesting(const GURL& a,
+                                                          const GURL& b) const {
+  return AreEquivalentOldImpl(a, b);
+}
+
+bool HttpNoVarySearchData::AreEquivalentNewImplForTesting(const GURL& a,
+                                                          const GURL& b) const {
+  return AreEquivalentNewImpl(a, b);
+}
+
 // static
 base::expected<HttpNoVarySearchData, HttpNoVarySearchData::ParseErrorEnum>
 HttpNoVarySearchData::ParseNoVarySearchDictionary(
@@ -239,6 +288,43 @@
   return base::ok(no_vary_search);
 }
 
+bool HttpNoVarySearchData::AreEquivalentOldImpl(const GURL& a,
+                                                const GURL& b) const {
+  // Check urls without query and reference (fragment) for equality first.
+  GURL::Replacements replacements;
+  replacements.ClearRef();
+  replacements.ClearQuery();
+  if (a.ReplaceComponents(replacements) != b.ReplaceComponents(replacements)) {
+    return false;
+  }
+
+  // If equal, look at how HttpNoVarySearchData argument affects
+  // search params variance.
+  UrlSearchParams a_search_params(a);
+  UrlSearchParams b_search_params(b);
+  ApplyNoVarySearchRulesToBothParams(*this, a_search_params, b_search_params);
+
+  // Check Search Params for equality
+  // All search params, in order, need to have the same keys and the same
+  // values.
+  return a_search_params.params() == b_search_params.params();
+}
+
+bool HttpNoVarySearchData::AreEquivalentNewImpl(const GURL& a,
+                                                const GURL& b) const {
+  if (ExtractBaseUrl(a) != ExtractBaseUrl(b)) {
+    return false;
+  }
+
+  // If equal, look at how HttpNoVarySearchData argument affects
+  // search params variance.
+  UrlSearchParamsView a_search_params(a);
+  UrlSearchParamsView b_search_params(b);
+  ApplyNoVarySearchRulesToBothParams(*this, a_search_params, b_search_params);
+
+  return a_search_params == b_search_params;
+}
+
 // LINT.IfChange(Serialization)
 void PickleTraits<HttpNoVarySearchData>::Serialize(
     base::Pickle& pickle,
diff --git a/net/http/http_no_vary_search_data.h b/net/http/http_no_vary_search_data.h
index 9046ba44..bfc53aa 100644
--- a/net/http/http_no_vary_search_data.h
+++ b/net/http/http_no_vary_search_data.h
@@ -72,6 +72,11 @@
   bool vary_on_key_order() const;
   bool vary_by_default() const;
 
+  // Direct access to the two AreEquivalent() implementations for tests and
+  // benchmarking.
+  bool AreEquivalentOldImplForTesting(const GURL& a, const GURL& b) const;
+  bool AreEquivalentNewImplForTesting(const GURL& a, const GURL& b) const;
+
  private:
   friend struct PickleTraits<HttpNoVarySearchData>;
 
@@ -81,6 +86,13 @@
                         HttpNoVarySearchData::ParseErrorEnum>
   ParseNoVarySearchDictionary(const structured_headers::Dictionary& dict);
 
+  // The old implementation of AreEquivalent() using UrlSearchParams.
+  // TODO(https://crbug.com/444335347): Remove this.
+  bool AreEquivalentOldImpl(const GURL& a, const GURL& b) const;
+
+  // The new implementation of AreEquivalent() using UrlSearchParamsView.
+  bool AreEquivalentNewImpl(const GURL& a, const GURL& b) const;
+
   // LINT.IfChange(MagicNumber)
 
   // Magic number for serialization. This should be updated whenever the number
diff --git a/net/http/http_no_vary_search_data_perftest.cc b/net/http/http_no_vary_search_data_perftest.cc
index 461f5f0..c8697e1 100644
--- a/net/http/http_no_vary_search_data_perftest.cc
+++ b/net/http/http_no_vary_search_data_perftest.cc
@@ -23,35 +23,67 @@
     "g7oxJqEddKz6ZFr0MyRDVYUA1drHTCLlBSRqPZH&wuk="
     "0vpRTHfdR2ppOvvrTLwJkjKNJDGd6Nx6T6RROflZBXPVA&bpm=5746&oqq=0460&mzx=0";
 
+bool RunNewImplementation(const HttpNoVarySearchData& nvs_data,
+                          const GURL& url1,
+                          const GURL& url2) {
+  return nvs_data.AreEquivalentNewImplForTesting(url1, url2);
+}
+
+bool RunOldImplementation(const HttpNoVarySearchData& nvs_data,
+                          const GURL& url1,
+                          const GURL& url2) {
+  return nvs_data.AreEquivalentOldImplForTesting(url1, url2);
+}
+
 void Benchmark(benchmark::State& state,
                const GURL& url1,
                const GURL& url2,
-               bool expected) {
+               bool expected,
+               bool use_new_implementation) {
   // Equivalent to "No-Vary-Search: key-order, params, except=("w" "spinptou")"
   const auto nvs_data =
       HttpNoVarySearchData::CreateFromVaryParams({"w", "spinptou"}, false);
 
+  const auto are_equivalent =
+      use_new_implementation ? RunNewImplementation : RunOldImplementation;
+
   for (auto _ : state) {
-    bool equivalent = nvs_data.AreEquivalent(url1, url2);
+    bool equivalent = are_equivalent(nvs_data, url1, url2);
     benchmark::DoNotOptimize(equivalent);
     DCHECK_EQ(equivalent, expected);
   }
 }
 
-void BM_HttpNoVarySearchDataAreEquivalentMatch(benchmark::State& state) {
+void BM_HttpNoVarySearchDataAreEquivalentMatch(benchmark::State& state,
+                                               bool use_new_implementation) {
   const GURL url1(kQueryUrl);
   const GURL url2(std::string(kQueryUrl) + "&pf=cs");
-  Benchmark(state, url1, url2, true);
+  Benchmark(state, url1, url2, true, use_new_implementation);
 }
 
-void BM_HttpNoVarySearchDataAreEquivalentNoMatch(benchmark::State& state) {
+void BM_HttpNoVarySearchDataAreEquivalentNoMatch(benchmark::State& state,
+                                                 bool use_new_implementation) {
   const GURL url1(kQueryUrl);
   const GURL url2(std::string(kQueryUrl) + "&spinptou=7");
-  Benchmark(state, url1, url2, false);
+  Benchmark(state, url1, url2, false, use_new_implementation);
 }
 
-BENCHMARK(BM_HttpNoVarySearchDataAreEquivalentMatch)->MinWarmUpTime(1.0);
-BENCHMARK(BM_HttpNoVarySearchDataAreEquivalentNoMatch)->MinWarmUpTime(1.0);
+BENCHMARK_CAPTURE(BM_HttpNoVarySearchDataAreEquivalentMatch,
+                  old_implementation,
+                  false)
+    ->MinWarmUpTime(1.0);
+BENCHMARK_CAPTURE(BM_HttpNoVarySearchDataAreEquivalentMatch,
+                  new_implementation,
+                  true)
+    ->MinWarmUpTime(1.0);
+BENCHMARK_CAPTURE(BM_HttpNoVarySearchDataAreEquivalentNoMatch,
+                  old_implementation,
+                  false)
+    ->MinWarmUpTime(1.0);
+BENCHMARK_CAPTURE(BM_HttpNoVarySearchDataAreEquivalentNoMatch,
+                  new_implementation,
+                  true)
+    ->MinWarmUpTime(1.0);
 
 }  // namespace
 
diff --git a/net/http/http_no_vary_search_data_unittest.cc b/net/http/http_no_vary_search_data_unittest.cc
index 0d163e0..d0f8d61 100644
--- a/net/http/http_no_vary_search_data_unittest.cc
+++ b/net/http/http_no_vary_search_data_unittest.cc
@@ -2,37 +2,44 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-
 #include "net/http/http_no_vary_search_data.h"
 
 #include <algorithm>
 #include <array>
 #include <string>
 #include <string_view>
+#include <tuple>
 #include <vector>
 
 #include "base/containers/flat_map.h"
 #include "base/containers/flat_set.h"
 #include "base/containers/to_vector.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "base/test/gmock_expected_support.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/types/expected.h"
+#include "net/base/features.h"
 #include "net/base/pickle.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/fuzztest/src/fuzztest/fuzztest.h"
 #include "url/gurl.h"
 
 namespace net {
 
 namespace {
 
-using testing::IsEmpty;
-using testing::Optional;
-using testing::UnorderedElementsAreArray;
+using ::testing::Combine;
+using ::testing::IsEmpty;
+using ::testing::Optional;
+using ::testing::UnorderedElementsAreArray;
+using ::testing::Values;
+using ::testing::ValuesIn;
 
 TEST(HttpNoVarySearchCreateTest, CreateFromNoVaryParamsNonEmptyVaryOnKeyOrder) {
   const auto no_vary_search =
@@ -779,11 +786,11 @@
 
 INSTANTIATE_TEST_SUITE_P(HttpNoVarySearchResponseHeadersTest,
                          HttpNoVarySearchResponseHeadersTest,
-                         testing::ValuesIn(response_headers_tests));
+                         ValuesIn(response_headers_tests));
 
 INSTANTIATE_TEST_SUITE_P(HttpNoVarySearchResponseHeadersParseFailureTest,
                          HttpNoVarySearchResponseHeadersParseFailureTest,
-                         testing::ValuesIn(response_header_failed));
+                         ValuesIn(response_header_failed));
 
 struct NoVarySearchCompareTestData {
   const GURL request_url;
@@ -792,7 +799,7 @@
   const bool expected_match;
 };
 
-TEST(HttpNoVarySearchCompare, CheckUrlEqualityWithSpecialCharacters) {
+TEST(HttpNoVarySearchAreEquivalentTest, CheckUrlEqualityWithSpecialCharacters) {
   // Use special characters in both `keys` and `values`.
   const base::flat_map<std::string, std::string> percent_encoding = {
       {"!", "%21"},    {"#", "%23"},    {"$", "%24"},    {"%", "%25"},
@@ -856,8 +863,57 @@
         {"𐨀", R"(%F0%90%A8%80)"},
 };
 
-TEST(HttpNoVarySearchCompare,
-     CheckUrlEqualityWithPercentEncodedNonASCIICharactersExcept) {
+enum class AreEquivalentImplementation {
+  kOld,
+  kNew,
+  kNewWithCheck,
+};
+
+// Configures `feature_list` to enable/disable feature
+// "HttpNoVarySearchDataUseNewAreEquivalent" and parameter "check_result"
+// according to `implementation`.
+void ConfigureAreEquivalentImplementation(
+    base::test::ScopedFeatureList& feature_list,
+    AreEquivalentImplementation implementation) {
+  switch (implementation) {
+    case AreEquivalentImplementation::kOld:
+      feature_list.InitAndDisableFeature(
+          features::kHttpNoVarySearchDataUseNewAreEquivalent);
+      break;
+
+    case AreEquivalentImplementation::kNew:
+      feature_list.InitAndEnableFeature(
+          features::kHttpNoVarySearchDataUseNewAreEquivalent);
+      break;
+
+    case AreEquivalentImplementation::kNewWithCheck:
+      feature_list.InitAndEnableFeatureWithParameters(
+          features::kHttpNoVarySearchDataUseNewAreEquivalent,
+          {{"check_result", "true"}});
+      break;
+  }
+}
+
+class HttpNoVarySearchAreEquivalentTest
+    : public ::testing::Test,
+      public ::testing::WithParamInterface<AreEquivalentImplementation> {
+ public:
+  HttpNoVarySearchAreEquivalentTest() {
+    ConfigureAreEquivalentImplementation(feature_list_, GetParam());
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+INSTANTIATE_TEST_SUITE_P(HttpNoVarySearchAreEquivalentTest,
+                         HttpNoVarySearchAreEquivalentTest,
+                         Values(AreEquivalentImplementation::kOld,
+                                AreEquivalentImplementation::kNew,
+                                AreEquivalentImplementation::kNewWithCheck));
+
+TEST_P(HttpNoVarySearchAreEquivalentTest,
+       CheckUrlEqualityWithPercentEncodedNonASCIICharactersExcept) {
   for (const auto& [key, value] : kPercentEncodedNonAsciiKeys) {
     std::string request_url_template = R"(https://a.test/index.html?$key=c)";
     std::string cached_url_template = R"(https://a.test/index.html?c=3&$key=c)";
@@ -882,8 +938,8 @@
   }
 }
 
-TEST(HttpNoVarySearchCompare,
-     CheckUrlEqualityWithPercentEncodedNonASCIICharacters) {
+TEST_P(HttpNoVarySearchAreEquivalentTest,
+       CheckUrlEqualityWithPercentEncodedNonASCIICharacters) {
   for (const auto& [key, value] : kPercentEncodedNonAsciiKeys) {
     std::string request_url_template =
         R"(https://a.test/index.html?a=2&$key=c)";
@@ -909,12 +965,26 @@
   }
 }
 
-class HttpNoVarySearchCompare
-    : public ::testing::Test,
-      public ::testing::WithParamInterface<NoVarySearchCompareTestData> {};
+class HttpNoVarySearchAreEquivalentParameterizedTest
+    : public ::testing::TestWithParam<std::tuple<NoVarySearchCompareTestData,
+                                                 AreEquivalentImplementation>> {
+ protected:
+  HttpNoVarySearchAreEquivalentParameterizedTest() {
+    ConfigureAreEquivalentImplementation(feature_list_,
+                                         std::get<1>(GetParam()));
+  }
 
-TEST_P(HttpNoVarySearchCompare, CheckUrlEqualityByNoVarySearch) {
-  const auto& test_data = GetParam();
+  const NoVarySearchCompareTestData& GetTestData() const {
+    return std::get<0>(GetParam());
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_P(HttpNoVarySearchAreEquivalentParameterizedTest,
+       CheckUrlEqualityByNoVarySearch) {
+  const auto& test_data = GetTestData();
 
   const std::string headers =
       HttpUtil::AssembleRawHeaders(test_data.raw_headers);
@@ -1152,9 +1222,55 @@
      false},
 };
 
-INSTANTIATE_TEST_SUITE_P(HttpNoVarySearchCompare,
-                         HttpNoVarySearchCompare,
-                         testing::ValuesIn(no_vary_search_compare_tests));
+INSTANTIATE_TEST_SUITE_P(
+    HttpNoVarySearchAreEquivalentParameterizedTest,
+    HttpNoVarySearchAreEquivalentParameterizedTest,
+    Combine(ValuesIn(no_vary_search_compare_tests),
+            Values(AreEquivalentImplementation::kOld,
+                   AreEquivalentImplementation::kNew,
+                   AreEquivalentImplementation::kNewWithCheck)));
+
+// AreEquivalent() needs to operate on a URL that has a scheme that has a query
+// and fragment. Rather than forcing the fuzzer to work that it needs to start
+// the string with an http(s) scheme by itself, this function always creates an
+// https URL.
+GURL CreateUrlFromSuffix(const std::string& suffix) {
+  return GURL(base::StrCat({"https://", suffix}));
+}
+
+// Verifies that the old and new implementations of AreEquivalent() give the
+// same output for the same input. `url_suffix_a` and `url_suffix_b` are the
+// URLs to test without the initial "https://". `params`, `vary_on_params` and
+// `vary_on_key_order` are used to configure the HttpNoVarySearchData object.
+void AreEquivalentImplementationsMatch(const std::string& url_suffix_a,
+                                       const std::string& url_suffix_b,
+                                       const std::vector<std::string>& params,
+                                       bool vary_on_params,
+                                       bool vary_on_key_order) {
+  // Discard invalid configurations early so we don't waste time on them.
+  if (!vary_on_params && params.empty()) {
+    // This configuration is equivalent to the default configuration, so is
+    // invalid.
+    return;
+  }
+  const GURL url_a = CreateUrlFromSuffix(url_suffix_a);
+  if (!url_a.is_valid()) {
+    return;
+  }
+  const GURL url_b = CreateUrlFromSuffix(url_suffix_b);
+  if (!url_b.is_valid()) {
+    return;
+  }
+  const HttpNoVarySearchData data =
+      vary_on_params ? HttpNoVarySearchData::CreateFromVaryParams(
+                           params, vary_on_key_order)
+                     : HttpNoVarySearchData::CreateFromNoVaryParams(
+                           params, vary_on_key_order);
+  EXPECT_EQ(data.AreEquivalentOldImplForTesting(url_a, url_b),
+            data.AreEquivalentNewImplForTesting(url_a, url_b));
+}
+
+FUZZ_TEST(HttpNoVarySearchTest, AreEquivalentImplementationsMatch);
 
 TEST(HttpNoVarySearchResponseHeadersParseHistogramTest, NoUnrecognizedKeys) {
   base::HistogramTester histogram_tester;
@@ -1218,7 +1334,8 @@
 
 // Use the `no_vary_search_compare_tests` as a convenient data set for testing
 // serialization and deserialization.
-using HttpNoVarySearchSerializationParameterizedTest = HttpNoVarySearchCompare;
+class HttpNoVarySearchSerializationParameterizedTest
+    : public ::testing::TestWithParam<NoVarySearchCompareTestData> {};
 
 TEST_P(HttpNoVarySearchSerializationParameterizedTest, RoundTrip) {
   const auto test_data = GetParam();
@@ -1241,7 +1358,7 @@
 
 INSTANTIATE_TEST_SUITE_P(HttpNoVarySearchSerializationParameterizedTest,
                          HttpNoVarySearchSerializationParameterizedTest,
-                         testing::ValuesIn(no_vary_search_compare_tests));
+                         ValuesIn(no_vary_search_compare_tests));
 
 base::Pickle MakeBadPickle(uint32_t magic_number,
                            const base::flat_set<std::string>& no_vary_params,
@@ -1291,7 +1408,7 @@
 INSTANTIATE_TEST_SUITE_P(
     HttpNoVarySearchBadPickleTest,
     HttpNoVarySearchBadPickleTest,
-    testing::ValuesIn(bad_pickle_params),
+    ValuesIn(bad_pickle_params),
     [](const testing::TestParamInfo<BadPickleParams>& info) {
       return std::string(info.param.why_bad);
     });
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 528a6b0a..d901fae6 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -20211,27 +20211,6 @@
             ]
         }
     ],
-    "RTCAlignReceivedEncodedVideoTransforms": [
-        {
-            "platforms": [
-                "android",
-                "android_webview",
-                "chromeos",
-                "ios",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "RTCAlignReceivedEncodedVideoTransforms"
-                    ]
-                }
-            ]
-        }
-    ],
     "RawDrawAndDrDc": [
         {
             "platforms": [
diff --git a/third_party/android_deps/autorolled/VERSION.txt b/third_party/android_deps/autorolled/VERSION.txt
index 13b07ae..19e877f 100644
--- a/third_party/android_deps/autorolled/VERSION.txt
+++ b/third_party/android_deps/autorolled/VERSION.txt
@@ -1 +1 @@
-67d7f6f5a84ce77.b5c90cefdfa8231
\ No newline at end of file
+cb86445f7390869.8a3917f748a20a7
\ No newline at end of file
diff --git a/third_party/android_deps/autorolled/bill_of_materials.json b/third_party/android_deps/autorolled/bill_of_materials.json
index d1ffef5c..066d01f1 100644
--- a/third_party/android_deps/autorolled/bill_of_materials.json
+++ b/third_party/android_deps/autorolled/bill_of_materials.json
@@ -1127,17 +1127,17 @@
     {
         "name": "window",
         "group": "androidx.window",
-        "version": "1.5.0"
+        "version": "1.6.0-SNAPSHOT"
     },
     {
         "name": "window-core",
         "group": "androidx.window",
-        "version": "1.5.0"
+        "version": "1.6.0-SNAPSHOT"
     },
     {
         "name": "window-core-android",
         "group": "androidx.window",
-        "version": "1.5.0"
+        "version": "1.6.0-SNAPSHOT"
     },
     {
         "name": "window-extensions",
@@ -1172,7 +1172,7 @@
     {
         "name": "lottie",
         "group": "com.airbnb.android",
-        "version": "6.6.9"
+        "version": "6.6.10"
     },
     {
         "name": "sqlite4java",
diff --git a/third_party/android_deps/autorolled/build.gradle b/third_party/android_deps/autorolled/build.gradle
index 774cbfd..cd32a1a 100644
--- a/third_party/android_deps/autorolled/build.gradle
+++ b/third_party/android_deps/autorolled/build.gradle
@@ -239,16 +239,16 @@
 versionCache['androidx.viewpager:viewpager'] = '1.1.0'
 versionCache['androidx.webkit:webkit'] = '1.15.0-SNAPSHOT'
 versionCache['androidx.window.sidecar:sidecar'] = '1.0.0-SNAPSHOT'
-versionCache['androidx.window:window'] = '1.5.0'
-versionCache['androidx.window:window-core'] = '1.5.0'
-versionCache['androidx.window:window-core-android'] = '1.5.0'
+versionCache['androidx.window:window'] = '1.6.0-SNAPSHOT'
+versionCache['androidx.window:window-core'] = '1.6.0-SNAPSHOT'
+versionCache['androidx.window:window-core-android'] = '1.6.0-SNAPSHOT'
 versionCache['androidx.window:window-extensions'] = '1.0.0-alpha01'
 versionCache['androidx.xr.arcore:arcore'] = '1.0.0-alpha05'
 versionCache['androidx.xr.runtime:runtime'] = '1.0.0-alpha05'
 versionCache['androidx.xr.runtime:runtime-manifest'] = '1.0.0-alpha05'
 versionCache['androidx.xr.runtime:runtime-openxr'] = '1.0.0-alpha05'
 versionCache['androidx.xr.scenecore:scenecore'] = '1.0.0-alpha05'
-versionCache['com.airbnb.android:lottie'] = '6.6.9'
+versionCache['com.airbnb.android:lottie'] = '6.6.10'
 versionCache['com.almworks.sqlite4java:sqlite4java'] = '1.0.392'
 versionCache['com.android.extensions.xr:extensions-xr'] = '1.1.0'
 versionCache['com.android.support:support-annotations'] = '28.0.0'
diff --git a/third_party/android_deps/autorolled/committed/libs/com_airbnb_android_lottie/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_airbnb_android_lottie/README.chromium
index e4ff9f2..d97ac389 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_airbnb_android_lottie/README.chromium
+++ b/third_party/android_deps/autorolled/committed/libs/com_airbnb_android_lottie/README.chromium
@@ -1,7 +1,7 @@
 Name: Lottie
 Short Name: lottie
-URL: https://repo.maven.apache.org/maven2/com/airbnb/android/lottie/6.6.9/lottie-6.6.9.aar
-Version: 6.6.9
+URL: https://repo.maven.apache.org/maven2/com/airbnb/android/lottie/6.6.10/lottie-6.6.10.aar
+Version: 6.6.10
 Update Mechanism: Autoroll
 License: Apache-2.0
 License File: LICENSE
diff --git a/third_party/androidx/bill_of_materials.json b/third_party/androidx/bill_of_materials.json
index 599fe81..1ff7a63 100644
--- a/third_party/androidx/bill_of_materials.json
+++ b/third_party/androidx/bill_of_materials.json
@@ -1137,17 +1137,17 @@
     {
         "name": "window",
         "group": "androidx.window",
-        "version": "1.5.0"
+        "version": "1.6.0-SNAPSHOT"
     },
     {
         "name": "window-core",
         "group": "androidx.window",
-        "version": "1.5.0"
+        "version": "1.6.0-SNAPSHOT"
     },
     {
         "name": "window-core-android",
         "group": "androidx.window",
-        "version": "1.5.0"
+        "version": "1.6.0-SNAPSHOT"
     },
     {
         "name": "window-extensions",
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle
index 87134b4..a74a39d 100644
--- a/third_party/androidx/build.gradle
+++ b/third_party/androidx/build.gradle
@@ -242,9 +242,9 @@
 versionCache['androidx.viewpager:viewpager'] = '1.1.0'
 versionCache['androidx.webkit:webkit'] = '1.15.0-SNAPSHOT'
 versionCache['androidx.window.sidecar:sidecar'] = '1.0.0-SNAPSHOT'
-versionCache['androidx.window:window'] = '1.5.0'
-versionCache['androidx.window:window-core'] = '1.5.0'
-versionCache['androidx.window:window-core-android'] = '1.5.0'
+versionCache['androidx.window:window'] = '1.6.0-SNAPSHOT'
+versionCache['androidx.window:window-core'] = '1.6.0-SNAPSHOT'
+versionCache['androidx.window:window-core-android'] = '1.6.0-SNAPSHOT'
 versionCache['androidx.window:window-extensions'] = '1.0.0-alpha01'
 versionCache['androidx.xr.arcore:arcore'] = '1.0.0-alpha05'
 versionCache['androidx.xr.runtime:runtime'] = '1.0.0-alpha05'
@@ -314,7 +314,7 @@
     google()
     maven {
         // This URL is generated by the fetch_all_androidx.py script.
-        url 'https://androidx.dev/snapshots/builds/14203925/artifacts/repository'
+        url 'https://androidx.dev/snapshots/builds/14209644/artifacts/repository'
     }
     mavenCentral()
 }
diff --git a/third_party/androidx/committed/libs/androidx_activity_activity/README.chromium b/third_party/androidx/committed/libs/androidx_activity_activity/README.chromium
index 5a67eac..cc8daf7 100644
--- a/third_party/androidx/committed/libs/androidx_activity_activity/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_activity_activity/README.chromium
@@ -1,6 +1,6 @@
 Name: Activity
 Short Name: activity
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/activity/activity/1.12.0-SNAPSHOT/activity-1.12.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/activity/activity/1.12.0-SNAPSHOT/activity-1.12.0-20251003.062603-1.aar
 Version: 1.12.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_activity_activity_compose/README.chromium b/third_party/androidx/committed/libs/androidx_activity_activity_compose/README.chromium
index 93ce69c..3a8682e 100644
--- a/third_party/androidx/committed/libs/androidx_activity_activity_compose/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_activity_activity_compose/README.chromium
@@ -1,6 +1,6 @@
 Name: Activity Compose
 Short Name: activity-compose
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/activity/activity-compose/1.12.0-SNAPSHOT/activity-compose-1.12.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/activity/activity-compose/1.12.0-SNAPSHOT/activity-compose-1.12.0-20251003.062603-1.aar
 Version: 1.12.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_activity_activity_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_activity_activity_ktx/README.chromium
index 4d453d5..d646495 100644
--- a/third_party/androidx/committed/libs/androidx_activity_activity_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_activity_activity_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: Activity Kotlin Extensions
 Short Name: activity-ktx
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/activity/activity-ktx/1.12.0-SNAPSHOT/activity-ktx-1.12.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/activity/activity-ktx/1.12.0-SNAPSHOT/activity-ktx-1.12.0-20251003.062603-1.aar
 Version: 1.12.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium b/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium
index 7bd51c1b..118eb5a3 100644
--- a/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium
@@ -1,6 +1,6 @@
 Name: Experimental annotation
 Short Name: annotation-experimental
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/annotation/annotation-experimental/1.6.0-SNAPSHOT/annotation-experimental-1.6.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/annotation/annotation-experimental/1.6.0-SNAPSHOT/annotation-experimental-1.6.0-20251003.062603-1.aar
 Version: 1.6.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/README.chromium b/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/README.chromium
index 8fc9a8f..da0e695 100644
--- a/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/README.chromium
@@ -1,6 +1,6 @@
 Name: Annotation
 Short Name: annotation-jvm
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/annotation/annotation-jvm/1.10.0-SNAPSHOT/annotation-jvm-1.10.0-20251002.111255-1.jar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/annotation/annotation-jvm/1.10.0-SNAPSHOT/annotation-jvm-1.10.0-20251003.062603-1.jar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appcompat_appcompat/README.chromium b/third_party/androidx/committed/libs/androidx_appcompat_appcompat/README.chromium
index 7ccd181..e141a892 100644
--- a/third_party/androidx/committed/libs/androidx_appcompat_appcompat/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_appcompat_appcompat/README.chromium
@@ -1,6 +1,6 @@
 Name: AppCompat
 Short Name: appcompat
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/appcompat/appcompat/1.8.0-SNAPSHOT/appcompat-1.8.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/appcompat/appcompat/1.8.0-SNAPSHOT/appcompat-1.8.0-20251003.062603-1.aar
 Version: 1.8.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/README.chromium b/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/README.chromium
index 6789deb5..e14bceae 100644
--- a/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/README.chromium
@@ -1,6 +1,6 @@
 Name: AppCompat Resources
 Short Name: appcompat-resources
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/appcompat/appcompat-resources/1.8.0-SNAPSHOT/appcompat-resources-1.8.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/appcompat/appcompat-resources/1.8.0-SNAPSHOT/appcompat-resources-1.8.0-20251003.062603-1.aar
 Version: 1.8.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appsearch_appsearch/README.chromium b/third_party/androidx/committed/libs/androidx_appsearch_appsearch/README.chromium
index d833c37e..d09418b 100644
--- a/third_party/androidx/committed/libs/androidx_appsearch_appsearch/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_appsearch_appsearch/README.chromium
@@ -1,6 +1,6 @@
 Name: AppSearch
 Short Name: appsearch
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/appsearch/appsearch/1.2.0-SNAPSHOT/appsearch-1.2.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/appsearch/appsearch/1.2.0-SNAPSHOT/appsearch-1.2.0-20251003.062603-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/README.chromium b/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/README.chromium
index dc2beaae..7dbbfb9 100644
--- a/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/README.chromium
@@ -1,6 +1,6 @@
 Name: AppSearch Builtin Types
 Short Name: appsearch-builtin-types
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/appsearch/appsearch-builtin-types/1.2.0-SNAPSHOT/appsearch-builtin-types-1.2.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/appsearch/appsearch-builtin-types/1.2.0-SNAPSHOT/appsearch-builtin-types-1.2.0-20251003.062603-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/README.chromium b/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/README.chromium
index 315f7064..7cb8f89 100644
--- a/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/README.chromium
@@ -1,6 +1,6 @@
 Name: AppSearch Platform Storage
 Short Name: appsearch-platform-storage
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/appsearch/appsearch-platform-storage/1.2.0-SNAPSHOT/appsearch-platform-storage-1.2.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/appsearch/appsearch-platform-storage/1.2.0-SNAPSHOT/appsearch-platform-storage-1.2.0-20251003.062603-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_arch_core_core_common/README.chromium b/third_party/androidx/committed/libs/androidx_arch_core_core_common/README.chromium
index 67554160..692f3ae 100644
--- a/third_party/androidx/committed/libs/androidx_arch_core_core_common/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_arch_core_core_common/README.chromium
@@ -1,6 +1,6 @@
 Name: Arch-Common
 Short Name: core-common
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/arch/core/core-common/2.3.0-SNAPSHOT/core-common-2.3.0-20251002.111255-1.jar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/arch/core/core-common/2.3.0-SNAPSHOT/core-common-2.3.0-20251003.062603-1.jar
 Version: 2.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/README.chromium b/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/README.chromium
index 2b03dbc..fc6cc69 100644
--- a/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/README.chromium
@@ -1,6 +1,6 @@
 Name: Arch-Runtime
 Short Name: core-runtime
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/arch/core/core-runtime/2.3.0-SNAPSHOT/core-runtime-2.3.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/arch/core/core-runtime/2.3.0-SNAPSHOT/core-runtime-2.3.0-20251003.062603-1.aar
 Version: 2.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_autofill_autofill/README.chromium b/third_party/androidx/committed/libs/androidx_autofill_autofill/README.chromium
index 420cca05..0ebc37e3 100644
--- a/third_party/androidx/committed/libs/androidx_autofill_autofill/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_autofill_autofill/README.chromium
@@ -1,6 +1,6 @@
 Name: Autofill
 Short Name: autofill
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/autofill/autofill/1.4.0-SNAPSHOT/autofill-1.4.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/autofill/autofill/1.4.0-SNAPSHOT/autofill-1.4.0-20251003.062603-1.aar
 Version: 1.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_common/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_common/README.chromium
index 9c17204..3c186cb1 100644
--- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_common/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_common/README.chromium
@@ -1,6 +1,6 @@
 Name: Benchmark - Common
 Short Name: benchmark-common
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/benchmark/benchmark-common/1.5.0-SNAPSHOT/benchmark-common-1.5.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/benchmark/benchmark-common/1.5.0-SNAPSHOT/benchmark-common-1.5.0-20251003.062603-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_junit4/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_junit4/README.chromium
index 2c6f8ca..c0620b3 100644
--- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_junit4/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_junit4/README.chromium
@@ -1,6 +1,6 @@
 Name: Benchmark - JUnit4
 Short Name: benchmark-junit4
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/benchmark/benchmark-junit4/1.5.0-SNAPSHOT/benchmark-junit4-1.5.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/benchmark/benchmark-junit4/1.5.0-SNAPSHOT/benchmark-junit4-1.5.0-20251003.062603-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro/README.chromium
index 5a61f0ad..0c0622a 100644
--- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro/README.chromium
@@ -1,6 +1,6 @@
 Name: Benchmark - Macrobenchmark
 Short Name: benchmark-macro
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/benchmark/benchmark-macro/1.5.0-SNAPSHOT/benchmark-macro-1.5.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/benchmark/benchmark-macro/1.5.0-SNAPSHOT/benchmark-macro-1.5.0-20251003.062603-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro_junit4/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro_junit4/README.chromium
index df63cb0..747071b0 100644
--- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro_junit4/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro_junit4/README.chromium
@@ -1,6 +1,6 @@
 Name: Benchmark - Macrobenchmark JUnit4
 Short Name: benchmark-macro-junit4
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/benchmark/benchmark-macro-junit4/1.5.0-SNAPSHOT/benchmark-macro-junit4-1.5.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/benchmark/benchmark-macro-junit4/1.5.0-SNAPSHOT/benchmark-macro-junit4-1.5.0-20251003.062603-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_traceprocessor_android/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_traceprocessor_android/README.chromium
index 470e8cfd..6667673a 100644
--- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_traceprocessor_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_traceprocessor_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Benchmark TraceProcessor
 Short Name: benchmark-traceprocessor-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/benchmark/benchmark-traceprocessor-android/1.5.0-SNAPSHOT/benchmark-traceprocessor-android-1.5.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/benchmark/benchmark-traceprocessor-android/1.5.0-SNAPSHOT/benchmark-traceprocessor-android-1.5.0-20251003.062603-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_biometric_biometric/README.chromium b/third_party/androidx/committed/libs/androidx_biometric_biometric/README.chromium
index 81bb83d75..781b4228 100644
--- a/third_party/androidx/committed/libs/androidx_biometric_biometric/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_biometric_biometric/README.chromium
@@ -1,6 +1,6 @@
 Name: Biometric
 Short Name: biometric
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/biometric/biometric/1.4.0-SNAPSHOT/biometric-1.4.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/biometric/biometric/1.4.0-SNAPSHOT/biometric-1.4.0-20251003.062603-1.aar
 Version: 1.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_browser_browser/README.chromium b/third_party/androidx/committed/libs/androidx_browser_browser/README.chromium
index 1739a13..eb19e1d2 100644
--- a/third_party/androidx/committed/libs/androidx_browser_browser/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_browser_browser/README.chromium
@@ -1,6 +1,6 @@
 Name: Browser
 Short Name: browser
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/browser/browser/1.10.0-SNAPSHOT/browser-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/browser/browser/1.10.0-SNAPSHOT/browser-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_cardview_cardview/README.chromium b/third_party/androidx/committed/libs/androidx_cardview_cardview/README.chromium
index c46da41e..e54027c 100644
--- a/third_party/androidx/committed/libs/androidx_cardview_cardview/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_cardview_cardview/README.chromium
@@ -1,6 +1,6 @@
 Name: CardView
 Short Name: cardview
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/cardview/cardview/1.1.0-SNAPSHOT/cardview-1.1.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/cardview/cardview/1.1.0-SNAPSHOT/cardview-1.1.0-20251003.062603-1.aar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_collection_collection_jvm/README.chromium b/third_party/androidx/committed/libs/androidx_collection_collection_jvm/README.chromium
index 677014a..b799d14 100644
--- a/third_party/androidx/committed/libs/androidx_collection_collection_jvm/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_collection_collection_jvm/README.chromium
@@ -1,6 +1,6 @@
 Name: collections
 Short Name: collection-jvm
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/collection/collection-jvm/1.6.0-SNAPSHOT/collection-jvm-1.6.0-20251002.111255-1.jar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/collection/collection-jvm/1.6.0-SNAPSHOT/collection-jvm-1.6.0-20251003.062603-1.jar
 Version: 1.6.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_collection_collection_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_collection_collection_ktx/README.chromium
index 60319459..546aa67 100644
--- a/third_party/androidx/committed/libs/androidx_collection_collection_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_collection_collection_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: Collections Kotlin Extensions
 Short Name: collection-ktx
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/collection/collection-ktx/1.6.0-SNAPSHOT/collection-ktx-1.6.0-20251002.111255-1.jar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/collection/collection-ktx/1.6.0-SNAPSHOT/collection-ktx-1.6.0-20251003.062603-1.jar
 Version: 1.6.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/README.chromium
index b091b0cf..d8b94bb 100644
--- a/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Animation
 Short Name: animation-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/animation/animation-android/1.10.0-SNAPSHOT/animation-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/animation/animation-android/1.10.0-SNAPSHOT/animation-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/README.chromium
index e9d411c..ddf8556a 100644
--- a/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Animation Core
 Short Name: animation-core-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/animation/animation-core-android/1.10.0-SNAPSHOT/animation-core-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/animation/animation-core-android/1.10.0-SNAPSHOT/animation-core-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/README.chromium
index f2a044c..61d8944f 100644
--- a/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Foundation
 Short Name: foundation-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/foundation/foundation-android/1.10.0-SNAPSHOT/foundation-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/foundation/foundation-android/1.10.0-SNAPSHOT/foundation-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/README.chromium
index 188d821..c345529 100644
--- a/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Layouts
 Short Name: foundation-layout-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/foundation/foundation-layout-android/1.10.0-SNAPSHOT/foundation-layout-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/foundation/foundation-layout-android/1.10.0-SNAPSHOT/foundation-layout-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/README.chromium
index 3dd334a..f3f3d1f 100644
--- a/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Material3 Components
 Short Name: material3-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/material3/material3-android/1.5.0-SNAPSHOT/material3-android-1.5.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/material3/material3-android/1.5.0-SNAPSHOT/material3-android-1.5.0-20251003.062603-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/README.chromium
index e327b411..e44f1d0 100644
--- a/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Material Ripple
 Short Name: material-ripple-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/material/material-ripple-android/1.10.0-SNAPSHOT/material-ripple-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/material/material-ripple-android/1.10.0-SNAPSHOT/material-ripple-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/README.chromium
index 094c1fe4..fed6177 100644
--- a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Runtime
 Short Name: runtime-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/runtime/runtime-android/1.10.0-SNAPSHOT/runtime-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/runtime/runtime-android/1.10.0-SNAPSHOT/runtime-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/README.chromium
index 130d135..07092624 100644
--- a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Runtime Annotation
 Short Name: runtime-annotation-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/runtime/runtime-annotation-android/1.10.0-SNAPSHOT/runtime-annotation-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/runtime/runtime-annotation-android/1.10.0-SNAPSHOT/runtime-annotation-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_retain_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_retain_android/README.chromium
index 6aa8d868..6ac57ad30 100644
--- a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_retain_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_retain_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Runtime Retain
 Short Name: runtime-retain-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/runtime/runtime-retain-android/1.10.0-SNAPSHOT/runtime-retain-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/runtime/runtime-retain-android/1.10.0-SNAPSHOT/runtime-retain-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/README.chromium
index eda503c..b304e2d 100644
--- a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Saveable
 Short Name: runtime-saveable-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/runtime/runtime-saveable-android/1.10.0-SNAPSHOT/runtime-saveable-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/runtime/runtime-saveable-android/1.10.0-SNAPSHOT/runtime-saveable-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/README.chromium
index d318d57..5ddbe9a 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose UI
 Short Name: ui-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/ui/ui-android/1.10.0-SNAPSHOT/ui-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/ui/ui-android/1.10.0-SNAPSHOT/ui-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/README.chromium
index 020a33b..dfe2499 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Geometry
 Short Name: ui-geometry-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/ui/ui-geometry-android/1.10.0-SNAPSHOT/ui-geometry-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/ui/ui-geometry-android/1.10.0-SNAPSHOT/ui-geometry-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/README.chromium
index 1f68b46..a19fd3f0 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Graphics
 Short Name: ui-graphics-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/ui/ui-graphics-android/1.10.0-SNAPSHOT/ui-graphics-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/ui/ui-graphics-android/1.10.0-SNAPSHOT/ui-graphics-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_android/README.chromium
index 1a177df5..412c463 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Testing
 Short Name: ui-test-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/ui/ui-test-android/1.10.0-SNAPSHOT/ui-test-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/ui/ui-test-android/1.10.0-SNAPSHOT/ui-test-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_junit4_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_junit4_android/README.chromium
index c0e52c9..e0dd3e4 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_junit4_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_junit4_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Testing for JUnit4
 Short Name: ui-test-junit4-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/ui/ui-test-junit4-android/1.10.0-SNAPSHOT/ui-test-junit4-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/ui/ui-test-junit4-android/1.10.0-SNAPSHOT/ui-test-junit4-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_manifest/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_manifest/README.chromium
index 182d35d..6c5633e 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_manifest/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_manifest/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Testing manifest dependency
 Short Name: ui-test-manifest
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/ui/ui-test-manifest/1.10.0-SNAPSHOT/ui-test-manifest-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/ui/ui-test-manifest/1.10.0-SNAPSHOT/ui-test-manifest-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/README.chromium
index af71c6d4..89f93ec 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose UI Text
 Short Name: ui-text-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/ui/ui-text-android/1.10.0-SNAPSHOT/ui-text-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/ui/ui-text-android/1.10.0-SNAPSHOT/ui-text-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/README.chromium
index 156a7fc42..c23c347 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Google Fonts integration
 Short Name: ui-text-google-fonts
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/ui/ui-text-google-fonts/1.10.0-SNAPSHOT/ui-text-google-fonts-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/ui/ui-text-google-fonts/1.10.0-SNAPSHOT/ui-text-google-fonts-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/README.chromium
index a07f0d0..afe5d6c 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Unit
 Short Name: ui-unit-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/ui/ui-unit-android/1.10.0-SNAPSHOT/ui-unit-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/ui/ui-unit-android/1.10.0-SNAPSHOT/ui-unit-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/README.chromium
index f0add0a5..34da0ae 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Util
 Short Name: ui-util-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/compose/ui/ui-util-android/1.10.0-SNAPSHOT/ui-util-android-1.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/compose/ui/ui-util-android/1.10.0-SNAPSHOT/ui-util-android-1.10.0-20251003.062603-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/README.chromium b/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/README.chromium
index ef6cee5..fabd167d 100644
--- a/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/README.chromium
@@ -1,6 +1,6 @@
 Name: ConstraintLayout
 Short Name: constraintlayout
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/constraintlayout/constraintlayout/2.3.0-SNAPSHOT/constraintlayout-2.3.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/constraintlayout/constraintlayout/2.3.0-SNAPSHOT/constraintlayout-2.3.0-20251003.062603-1.aar
 Version: 2.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/README.chromium b/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/README.chromium
index 2c8656e..0b7b580 100644
--- a/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/README.chromium
@@ -1,6 +1,6 @@
 Name: ConstraintLayout Core
 Short Name: constraintlayout-core
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/constraintlayout/constraintlayout-core/1.2.0-SNAPSHOT/constraintlayout-core-1.2.0-20251002.111255-1.jar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/constraintlayout/constraintlayout-core/1.2.0-SNAPSHOT/constraintlayout-core-1.2.0-20251003.062603-1.jar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_core_core/README.chromium b/third_party/androidx/committed/libs/androidx_core_core/README.chromium
index ada5839..58509a9 100644
--- a/third_party/androidx/committed/libs/androidx_core_core/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_core_core/README.chromium
@@ -1,6 +1,6 @@
 Name: Core
 Short Name: core
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/core/core/1.18.0-SNAPSHOT/core-1.18.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/core/core/1.18.0-SNAPSHOT/core-1.18.0-20251003.062603-1.aar
 Version: 1.18.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_core_core_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_core_core_ktx/README.chromium
index d4cf17f..eaa707c 100644
--- a/third_party/androidx/committed/libs/androidx_core_core_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_core_core_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: Core Kotlin Extensions
 Short Name: core-ktx
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/core/core-ktx/1.18.0-SNAPSHOT/core-ktx-1.18.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/core/core-ktx/1.18.0-SNAPSHOT/core-ktx-1.18.0-20251003.062603-1.aar
 Version: 1.18.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_core_core_viewtree/README.chromium b/third_party/androidx/committed/libs/androidx_core_core_viewtree/README.chromium
index 9f4d12e69..be0e49f9 100644
--- a/third_party/androidx/committed/libs/androidx_core_core_viewtree/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_core_core_viewtree/README.chromium
@@ -1,6 +1,6 @@
 Name: androidx.core:core-viewtree
 Short Name: core-viewtree
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/core/core-viewtree/1.1.0-SNAPSHOT/core-viewtree-1.1.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/core/core-viewtree/1.1.0-SNAPSHOT/core-viewtree-1.1.0-20251003.062603-1.aar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_credentials_credentials/README.chromium b/third_party/androidx/committed/libs/androidx_credentials_credentials/README.chromium
index 19541c0..73ead4b73 100644
--- a/third_party/androidx/committed/libs/androidx_credentials_credentials/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_credentials_credentials/README.chromium
@@ -1,6 +1,6 @@
 Name: Credentials
 Short Name: credentials
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/credentials/credentials/1.6.0-SNAPSHOT/credentials-1.6.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/credentials/credentials/1.6.0-SNAPSHOT/credentials-1.6.0-20251003.062603-1.aar
 Version: 1.6.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/README.chromium b/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/README.chromium
index e0156464..0847101 100644
--- a/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/README.chromium
@@ -1,6 +1,6 @@
 Name: Credentials Play Services Auth
 Short Name: credentials-play-services-auth
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/credentials/credentials-play-services-auth/1.6.0-SNAPSHOT/credentials-play-services-auth-1.6.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/credentials/credentials-play-services-auth/1.6.0-SNAPSHOT/credentials-play-services-auth-1.6.0-20251003.062603-1.aar
 Version: 1.6.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/README.chromium b/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/README.chromium
index 5aae71f..4030feb 100644
--- a/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/README.chromium
@@ -1,6 +1,6 @@
 Name: androidx.credentials.registry:registry-provider
 Short Name: registry-provider
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/credentials/registry/registry-provider/1.0.0-SNAPSHOT/registry-provider-1.0.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/credentials/registry/registry-provider/1.0.0-SNAPSHOT/registry-provider-1.0.0-20251003.062603-1.aar
 Version: 1.0.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/README.chromium b/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/README.chromium
index 0df64b9..9227cb5 100644
--- a/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/README.chromium
@@ -1,6 +1,6 @@
 Name: androidx.credentials.registry:registry-provider-play-services
 Short Name: registry-provider-play-services
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/credentials/registry/registry-provider-play-services/1.0.0-SNAPSHOT/registry-provider-play-services-1.0.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/credentials/registry/registry-provider-play-services/1.0.0-SNAPSHOT/registry-provider-play-services-1.0.0-20251003.062603-1.aar
 Version: 1.0.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/README.chromium b/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/README.chromium
index e8c8c41..55bf157 100644
--- a/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/README.chromium
@@ -1,6 +1,6 @@
 Name: Cursor Adapter
 Short Name: cursoradapter
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/cursoradapter/cursoradapter/1.1.0-SNAPSHOT/cursoradapter-1.1.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/cursoradapter/cursoradapter/1.1.0-SNAPSHOT/cursoradapter-1.1.0-20251003.062603-1.aar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_android/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_android/README.chromium
index 81ff0a7..c8dfb5ed 100644
--- a/third_party/androidx/committed/libs/androidx_datastore_datastore_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_android/README.chromium
@@ -1,6 +1,6 @@
 Name: DataStore
 Short Name: datastore-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/datastore/datastore-android/1.2.0-SNAPSHOT/datastore-android-1.2.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/datastore/datastore-android/1.2.0-SNAPSHOT/datastore-android-1.2.0-20251003.062603-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/README.chromium
index 2b1672d..2aabb211 100644
--- a/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/README.chromium
@@ -1,6 +1,6 @@
 Name: DataStore Core
 Short Name: datastore-core-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/datastore/datastore-core-android/1.2.0-SNAPSHOT/datastore-core-android-1.2.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/datastore/datastore-core-android/1.2.0-SNAPSHOT/datastore-core-android-1.2.0-20251003.062603-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/README.chromium
index f6b4a0c..140589d 100644
--- a/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/README.chromium
@@ -1,6 +1,6 @@
 Name: DataStore Core Okio
 Short Name: datastore-core-okio-jvm
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/datastore/datastore-core-okio-jvm/1.2.0-SNAPSHOT/datastore-core-okio-jvm-1.2.0-20251002.111255-1.jar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/datastore/datastore-core-okio-jvm/1.2.0-SNAPSHOT/datastore-core-okio-jvm-1.2.0-20251003.062603-1.jar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
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
index b9dfa7cad..498b75a 100644
--- 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
@@ -1,6 +1,6 @@
 Name: Preferences DataStore
 Short Name: datastore-preferences-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/datastore/datastore-preferences-android/1.2.0-SNAPSHOT/datastore-preferences-android-1.2.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/datastore/datastore-preferences-android/1.2.0-SNAPSHOT/datastore-preferences-android-1.2.0-20251003.062603-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
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
index 718e795..7d85fc2d1 100644
--- 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
@@ -1,6 +1,6 @@
 Name: Preferences DataStore Core
 Short Name: datastore-preferences-core-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/datastore/datastore-preferences-core-android/1.2.0-SNAPSHOT/datastore-preferences-core-android-1.2.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/datastore/datastore-preferences-core-android/1.2.0-SNAPSHOT/datastore-preferences-core-android-1.2.0-20251003.062603-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
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
index ae44bad..bb8d7b9 100644
--- 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
@@ -1,6 +1,6 @@
 Name: Preferences External Protobuf
 Short Name: datastore-preferences-external-protobuf
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/datastore/datastore-preferences-external-protobuf/1.2.0-SNAPSHOT/datastore-preferences-external-protobuf-1.2.0-20251002.111255-1.jar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/datastore/datastore-preferences-external-protobuf/1.2.0-SNAPSHOT/datastore-preferences-external-protobuf-1.2.0-20251003.062603-1.jar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: BSD-3-Clause
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
index 116c4960..e424f83 100644
--- 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
@@ -1,6 +1,6 @@
 Name: Preferences DataStore Proto
 Short Name: datastore-preferences-proto
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/datastore/datastore-preferences-proto/1.2.0-SNAPSHOT/datastore-preferences-proto-1.2.0-20251002.111255-1.jar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/datastore/datastore-preferences-proto/1.2.0-SNAPSHOT/datastore-preferences-proto-1.2.0-20251003.062603-1.jar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/README.chromium b/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/README.chromium
index f31b238..e4f64a0 100644
--- a/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/README.chromium
@@ -1,6 +1,6 @@
 Name: Drawer Layout
 Short Name: drawerlayout
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/drawerlayout/drawerlayout/1.3.0-SNAPSHOT/drawerlayout-1.3.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/drawerlayout/drawerlayout/1.3.0-SNAPSHOT/drawerlayout-1.3.0-20251003.062603-1.aar
 Version: 1.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
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 e4f0ae36..df447787 100644
--- a/third_party/androidx/committed/libs/androidx_emoji_emoji/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_emoji_emoji/README.chromium
@@ -1,6 +1,6 @@
 Name: Emoji
 Short Name: emoji
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/emoji/emoji/1.2.0-SNAPSHOT/emoji-1.2.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/emoji/emoji/1.2.0-SNAPSHOT/emoji-1.2.0-20251003.062603-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0, SIL Open Font License, Version 1.1, Unicode, Inc. License
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment/README.chromium
index 9600126..b06f024 100644
--- a/third_party/androidx/committed/libs/androidx_fragment_fragment/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_fragment_fragment/README.chromium
@@ -1,6 +1,6 @@
 Name: fragment
 Short Name: fragment
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/fragment/fragment/1.9.0-SNAPSHOT/fragment-1.9.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/fragment/fragment/1.9.0-SNAPSHOT/fragment-1.9.0-20251003.062603-1.aar
 Version: 1.9.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/README.chromium
index bf43a8d..38e6def 100644
--- a/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/README.chromium
@@ -1,6 +1,6 @@
 Name: Fragment Compose
 Short Name: fragment-compose
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/fragment/fragment-compose/1.9.0-SNAPSHOT/fragment-compose-1.9.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/fragment/fragment-compose/1.9.0-SNAPSHOT/fragment-compose-1.9.0-20251003.062603-1.aar
 Version: 1.9.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/README.chromium
index b5d05e5..4a7f01c2 100644
--- a/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: Fragment Kotlin Extensions
 Short Name: fragment-ktx
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/fragment/fragment-ktx/1.9.0-SNAPSHOT/fragment-ktx-1.9.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/fragment/fragment-ktx/1.9.0-SNAPSHOT/fragment-ktx-1.9.0-20251003.062603-1.aar
 Version: 1.9.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment_testing/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment_testing/README.chromium
index 3015086..35e227c8 100644
--- a/third_party/androidx/committed/libs/androidx_fragment_fragment_testing/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_fragment_fragment_testing/README.chromium
@@ -1,6 +1,6 @@
 Name: Fragment Testing Extensions
 Short Name: fragment-testing
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/fragment/fragment-testing/1.9.0-SNAPSHOT/fragment-testing-1.9.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/fragment/fragment-testing/1.9.0-SNAPSHOT/fragment-testing-1.9.0-20251003.062603-1.aar
 Version: 1.9.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment_testing_manifest/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment_testing_manifest/README.chromium
index 3da2c8de..c7e9fbb 100644
--- a/third_party/androidx/committed/libs/androidx_fragment_fragment_testing_manifest/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_fragment_fragment_testing_manifest/README.chromium
@@ -1,6 +1,6 @@
 Name: Fragment Testing Manifest dependency
 Short Name: fragment-testing-manifest
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/fragment/fragment-testing-manifest/1.9.0-SNAPSHOT/fragment-testing-manifest-1.9.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/fragment/fragment-testing-manifest/1.9.0-SNAPSHOT/fragment-testing-manifest-1.9.0-20251003.062603-1.aar
 Version: 1.9.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_graphics_graphics_path/README.chromium b/third_party/androidx/committed/libs/androidx_graphics_graphics_path/README.chromium
index 9bd895eb..8db1dbb 100644
--- a/third_party/androidx/committed/libs/androidx_graphics_graphics_path/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_graphics_graphics_path/README.chromium
@@ -1,6 +1,6 @@
 Name: Android Graphics Path
 Short Name: graphics-path
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/graphics/graphics-path/1.1.0-SNAPSHOT/graphics-path-1.1.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/graphics/graphics-path/1.1.0-SNAPSHOT/graphics-path-1.1.0-20251003.062603-1.aar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_graphics_graphics_shapes_android/README.chromium b/third_party/androidx/committed/libs/androidx_graphics_graphics_shapes_android/README.chromium
index c05e09c..fc8dbb8 100644
--- a/third_party/androidx/committed/libs/androidx_graphics_graphics_shapes_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_graphics_graphics_shapes_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Graphics Shapes
 Short Name: graphics-shapes-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/graphics/graphics-shapes-android/1.1.0-SNAPSHOT/graphics-shapes-android-1.1.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/graphics/graphics-shapes-android/1.1.0-SNAPSHOT/graphics-shapes-android-1.1.0-20251003.062603-1.aar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_interpolator_interpolator/README.chromium b/third_party/androidx/committed/libs/androidx_interpolator_interpolator/README.chromium
index b7784e9..b470385f 100644
--- a/third_party/androidx/committed/libs/androidx_interpolator_interpolator/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_interpolator_interpolator/README.chromium
@@ -1,6 +1,6 @@
 Name: Interpolators
 Short Name: interpolator
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/interpolator/interpolator/1.1.0-SNAPSHOT/interpolator-1.1.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/interpolator/interpolator/1.1.0-SNAPSHOT/interpolator-1.1.0-20251003.062603-1.aar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/README.chromium
index b67f528c..444b5f71 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle-Common for Java 8
 Short Name: lifecycle-common-java8
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/lifecycle/lifecycle-common-java8/2.10.0-SNAPSHOT/lifecycle-common-java8-2.10.0-20251002.111255-1.jar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/lifecycle/lifecycle-common-java8/2.10.0-SNAPSHOT/lifecycle-common-java8-2.10.0-20251003.062603-1.jar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/README.chromium
index 83a333df..3bcd89b 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle-Common
 Short Name: lifecycle-common-jvm
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/lifecycle/lifecycle-common-jvm/2.10.0-SNAPSHOT/lifecycle-common-jvm-2.10.0-20251002.111255-1.jar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/lifecycle/lifecycle-common-jvm/2.10.0-SNAPSHOT/lifecycle-common-jvm-2.10.0-20251003.062603-1.jar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/README.chromium
index e16b60db..391148c 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle LiveData
 Short Name: lifecycle-livedata
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/lifecycle/lifecycle-livedata/2.10.0-SNAPSHOT/lifecycle-livedata-2.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/lifecycle/lifecycle-livedata/2.10.0-SNAPSHOT/lifecycle-livedata-2.10.0-20251003.062603-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/README.chromium
index 4fa9851b..cc8908d 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle LiveData Core
 Short Name: lifecycle-livedata-core
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/lifecycle/lifecycle-livedata-core/2.10.0-SNAPSHOT/lifecycle-livedata-core-2.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/lifecycle/lifecycle-livedata-core/2.10.0-SNAPSHOT/lifecycle-livedata-core-2.10.0-20251003.062603-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/README.chromium
index c6dba7b..c920fe7 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: LiveData Core Kotlin Extensions
 Short Name: lifecycle-livedata-core-ktx
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/lifecycle/lifecycle-livedata-core-ktx/2.10.0-SNAPSHOT/lifecycle-livedata-core-ktx-2.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/lifecycle/lifecycle-livedata-core-ktx/2.10.0-SNAPSHOT/lifecycle-livedata-core-ktx-2.10.0-20251003.062603-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_ktx/README.chromium
index 020a0da..e4790ec 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: LiveData Kotlin Extensions
 Short Name: lifecycle-livedata-ktx
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/lifecycle/lifecycle-livedata-ktx/2.10.0-SNAPSHOT/lifecycle-livedata-ktx-2.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/lifecycle/lifecycle-livedata-ktx/2.10.0-SNAPSHOT/lifecycle-livedata-ktx-2.10.0-20251003.062603-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/README.chromium
index e8f39a7..ceb6698 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle Process
 Short Name: lifecycle-process
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/lifecycle/lifecycle-process/2.10.0-SNAPSHOT/lifecycle-process-2.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/lifecycle/lifecycle-process/2.10.0-SNAPSHOT/lifecycle-process-2.10.0-20251003.062603-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/README.chromium
index 43d0de7..4770cc5e 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle Runtime
 Short Name: lifecycle-runtime-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/lifecycle/lifecycle-runtime-android/2.10.0-SNAPSHOT/lifecycle-runtime-android-2.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/lifecycle/lifecycle-runtime-android/2.10.0-SNAPSHOT/lifecycle-runtime-android-2.10.0-20251003.062603-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/README.chromium
index cd542754..d56a459 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle Runtime Compose
 Short Name: lifecycle-runtime-compose-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/lifecycle/lifecycle-runtime-compose-android/2.10.0-SNAPSHOT/lifecycle-runtime-compose-android-2.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/lifecycle/lifecycle-runtime-compose-android/2.10.0-SNAPSHOT/lifecycle-runtime-compose-android-2.10.0-20251003.062603-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/README.chromium
index a7911557..46cbf68 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle Kotlin Extensions
 Short Name: lifecycle-runtime-ktx-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/lifecycle/lifecycle-runtime-ktx-android/2.10.0-SNAPSHOT/lifecycle-runtime-ktx-android-2.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/lifecycle/lifecycle-runtime-ktx-android/2.10.0-SNAPSHOT/lifecycle-runtime-ktx-android-2.10.0-20251003.062603-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/README.chromium
index 06a5953..bec89cbf 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle Service
 Short Name: lifecycle-service
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/lifecycle/lifecycle-service/2.10.0-SNAPSHOT/lifecycle-service-2.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/lifecycle/lifecycle-service/2.10.0-SNAPSHOT/lifecycle-service-2.10.0-20251003.062603-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/README.chromium
index 5728f80..3157bbc 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle ViewModel
 Short Name: lifecycle-viewmodel-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-android/2.10.0-SNAPSHOT/lifecycle-viewmodel-android-2.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-android/2.10.0-SNAPSHOT/lifecycle-viewmodel-android-2.10.0-20251003.062603-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/README.chromium
index 12d4fb23..986a9f88 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle ViewModel Compose
 Short Name: lifecycle-viewmodel-compose-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-compose-android/2.10.0-SNAPSHOT/lifecycle-viewmodel-compose-android-2.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-compose-android/2.10.0-SNAPSHOT/lifecycle-viewmodel-compose-android-2.10.0-20251003.062603-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/README.chromium
index 24ce479..74d72ccb 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle ViewModel Kotlin Extensions
 Short Name: lifecycle-viewmodel-ktx
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-ktx/2.10.0-SNAPSHOT/lifecycle-viewmodel-ktx-2.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-ktx/2.10.0-SNAPSHOT/lifecycle-viewmodel-ktx-2.10.0-20251003.062603-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/README.chromium
index 23bfaac..f9c124e 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle ViewModel with SavedState
 Short Name: lifecycle-viewmodel-savedstate-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-savedstate-android/2.10.0-SNAPSHOT/lifecycle-viewmodel-savedstate-android-2.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-savedstate-android/2.10.0-SNAPSHOT/lifecycle-viewmodel-savedstate-android-2.10.0-20251003.062603-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_loader_loader/README.chromium b/third_party/androidx/committed/libs/androidx_loader_loader/README.chromium
index 91566c32..a4e60c0 100644
--- a/third_party/androidx/committed/libs/androidx_loader_loader/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_loader_loader/README.chromium
@@ -1,6 +1,6 @@
 Name: loader
 Short Name: loader
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/loader/loader/1.2.0-SNAPSHOT/loader-1.2.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/loader/loader/1.2.0-SNAPSHOT/loader-1.2.0-20251003.062603-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_media_media/README.chromium b/third_party/androidx/committed/libs/androidx_media_media/README.chromium
index 0eaee4b..7d28a4b 100644
--- a/third_party/androidx/committed/libs/androidx_media_media/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_media_media/README.chromium
@@ -1,6 +1,6 @@
 Name: Media
 Short Name: media
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/media/media/1.8.0-SNAPSHOT/media-1.8.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/media/media/1.8.0-SNAPSHOT/media-1.8.0-20251003.062603-1.aar
 Version: 1.8.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/README.chromium
index 63caa62..41cc8b4 100644
--- a/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Navigation Common
 Short Name: navigation-common-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/navigation/navigation-common-android/2.10.0-SNAPSHOT/navigation-common-android-2.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/navigation/navigation-common-android/2.10.0-SNAPSHOT/navigation-common-android-2.10.0-20251003.062603-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/README.chromium
index 1e0e9aa7..6aac317 100644
--- a/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Navigation
 Short Name: navigation-compose-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/navigation/navigation-compose-android/2.10.0-SNAPSHOT/navigation-compose-android-2.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/navigation/navigation-compose-android/2.10.0-SNAPSHOT/navigation-compose-android-2.10.0-20251003.062603-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/README.chromium
index ffdedf0..3551d74 100644
--- a/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Navigation Runtime
 Short Name: navigation-runtime-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/navigation/navigation-runtime-android/2.10.0-SNAPSHOT/navigation-runtime-android-2.10.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/navigation/navigation-runtime-android/2.10.0-SNAPSHOT/navigation-runtime-android-2.10.0-20251003.062603-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium
index 406f686..77f36e7 100644
--- a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Navigation Event
 Short Name: navigationevent-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/navigationevent/navigationevent-android/1.0.0-SNAPSHOT/navigationevent-android-1.0.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/navigationevent/navigationevent-android/1.0.0-SNAPSHOT/navigationevent-android-1.0.0-20251003.062603-1.aar
 Version: 1.0.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_compose_android/README.chromium
index 8c06c52f..9864ac7 100644
--- a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_compose_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_compose_android/README.chromium
@@ -1,6 +1,6 @@
 Name: NavigationEvent Compose
 Short Name: navigationevent-compose-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/navigationevent/navigationevent-compose-android/1.0.0-SNAPSHOT/navigationevent-compose-android-1.0.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/navigationevent/navigationevent-compose-android/1.0.0-SNAPSHOT/navigationevent-compose-android-1.0.0-20251003.062603-1.aar
 Version: 1.0.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_paging_paging_common_android/README.chromium b/third_party/androidx/committed/libs/androidx_paging_paging_common_android/README.chromium
index 17a97fa..a4af328 100644
--- a/third_party/androidx/committed/libs/androidx_paging_paging_common_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_paging_paging_common_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Paging-Common
 Short Name: paging-common-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/paging/paging-common-android/3.4.0-SNAPSHOT/paging-common-android-3.4.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/paging/paging-common-android/3.4.0-SNAPSHOT/paging-common-android-3.4.0-20251003.062603-1.aar
 Version: 3.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_paging_paging_common_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_paging_paging_common_ktx/README.chromium
index 9903a0154..fcf4dc7 100644
--- a/third_party/androidx/committed/libs/androidx_paging_paging_common_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_paging_paging_common_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: Paging-Common Kotlin Extensions
 Short Name: paging-common-ktx
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/paging/paging-common-ktx/3.4.0-SNAPSHOT/paging-common-ktx-3.4.0-20251002.111255-1.jar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/paging/paging-common-ktx/3.4.0-SNAPSHOT/paging-common-ktx-3.4.0-20251003.062603-1.jar
 Version: 3.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_paging_paging_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_paging_paging_compose_android/README.chromium
index cb44ed2..f52af3c 100644
--- a/third_party/androidx/committed/libs/androidx_paging_paging_compose_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_paging_paging_compose_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Paging-Compose
 Short Name: paging-compose-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/paging/paging-compose-android/3.4.0-SNAPSHOT/paging-compose-android-3.4.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/paging/paging-compose-android/3.4.0-SNAPSHOT/paging-compose-android-3.4.0-20251003.062603-1.aar
 Version: 3.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_paging_paging_runtime/README.chromium b/third_party/androidx/committed/libs/androidx_paging_paging_runtime/README.chromium
index c2fba53..119aba9 100644
--- a/third_party/androidx/committed/libs/androidx_paging_paging_runtime/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_paging_paging_runtime/README.chromium
@@ -1,6 +1,6 @@
 Name: Paging-Runtime
 Short Name: paging-runtime
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/paging/paging-runtime/3.4.0-SNAPSHOT/paging-runtime-3.4.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/paging/paging-runtime/3.4.0-SNAPSHOT/paging-runtime-3.4.0-20251003.062603-1.aar
 Version: 3.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_palette_palette/README.chromium b/third_party/androidx/committed/libs/androidx_palette_palette/README.chromium
index f5e72dc7..028d394b 100644
--- a/third_party/androidx/committed/libs/androidx_palette_palette/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_palette_palette/README.chromium
@@ -1,6 +1,6 @@
 Name: Palette
 Short Name: palette
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/palette/palette/1.1.0-SNAPSHOT/palette-1.1.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/palette/palette/1.1.0-SNAPSHOT/palette-1.1.0-20251003.062603-1.aar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
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 c52afba..5ff3b02 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,6 +1,6 @@
 Name: androidx.pdf:pdf-document-service
 Short Name: pdf-document-service
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/pdf/pdf-document-service/1.0.0-SNAPSHOT/pdf-document-service-1.0.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/pdf/pdf-document-service/1.0.0-SNAPSHOT/pdf-document-service-1.0.0-20251003.062603-1.aar
 Version: 1.0.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
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 3fb662e..5a01e3e 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,6 +1,6 @@
 Name: androidx.pdf:pdf-viewer
 Short Name: pdf-viewer
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/pdf/pdf-viewer/1.0.0-SNAPSHOT/pdf-viewer-1.0.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/pdf/pdf-viewer/1.0.0-SNAPSHOT/pdf-viewer-1.0.0-20251003.062603-1.aar
 Version: 1.0.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
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 012e392..f6323e9 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,6 +1,6 @@
 Name: androidx.pdf:pdf-viewer-fragment
 Short Name: pdf-viewer-fragment
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/pdf/pdf-viewer-fragment/1.0.0-SNAPSHOT/pdf-viewer-fragment-1.0.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/pdf/pdf-viewer-fragment/1.0.0-SNAPSHOT/pdf-viewer-fragment-1.0.0-20251003.062603-1.aar
 Version: 1.0.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_preference_preference/README.chromium b/third_party/androidx/committed/libs/androidx_preference_preference/README.chromium
index fe69e7d..a5a3525 100644
--- a/third_party/androidx/committed/libs/androidx_preference_preference/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_preference_preference/README.chromium
@@ -1,6 +1,6 @@
 Name: Preference
 Short Name: preference
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/preference/preference/1.3.0-SNAPSHOT/preference-1.3.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/preference/preference/1.3.0-SNAPSHOT/preference-1.3.0-20251003.062603-1.aar
 Version: 1.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/README.chromium b/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/README.chromium
index 15791dfe..4a0413c4c 100644
--- a/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/README.chromium
@@ -1,6 +1,6 @@
 Name: Profile Installer
 Short Name: profileinstaller
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/profileinstaller/profileinstaller/1.5.0-SNAPSHOT/profileinstaller-1.5.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/profileinstaller/profileinstaller/1.5.0-SNAPSHOT/profileinstaller-1.5.0-20251003.062603-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/README.chromium b/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/README.chromium
index 02c1cab..4466a9f 100644
--- a/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/README.chromium
@@ -1,6 +1,6 @@
 Name: RecyclerView
 Short Name: recyclerview
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/recyclerview/recyclerview/1.5.0-SNAPSHOT/recyclerview-1.5.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/recyclerview/recyclerview/1.5.0-SNAPSHOT/recyclerview-1.5.0-20251003.062603-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/README.chromium b/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/README.chromium
index 517bb18..0c1acf2e 100644
--- a/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/README.chromium
@@ -1,6 +1,6 @@
 Name: Resource Inspection - Annotations
 Short Name: resourceinspection-annotation
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/resourceinspection/resourceinspection-annotation/1.1.0-SNAPSHOT/resourceinspection-annotation-1.1.0-20251002.111255-1.jar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/resourceinspection/resourceinspection-annotation/1.1.0-SNAPSHOT/resourceinspection-annotation-1.1.0-20251003.062603-1.jar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/README.chromium b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/README.chromium
index 44ebe403..7f8ceb5 100644
--- a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Saved State
 Short Name: savedstate-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/savedstate/savedstate-android/1.4.0-SNAPSHOT/savedstate-android-1.4.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/savedstate/savedstate-android/1.4.0-SNAPSHOT/savedstate-android-1.4.0-20251003.062603-1.aar
 Version: 1.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/README.chromium
index 91376fc..f39b411b 100644
--- a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Saved State Compose
 Short Name: savedstate-compose-android
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/savedstate/savedstate-compose-android/1.4.0-SNAPSHOT/savedstate-compose-android-1.4.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/savedstate/savedstate-compose-android/1.4.0-SNAPSHOT/savedstate-compose-android-1.4.0-20251003.062603-1.aar
 Version: 1.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/README.chromium
index 0b91b2f0..cf530c5 100644
--- a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: SavedState Kotlin Extensions
 Short Name: savedstate-ktx
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/savedstate/savedstate-ktx/1.4.0-SNAPSHOT/savedstate-ktx-1.4.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/savedstate/savedstate-ktx/1.4.0-SNAPSHOT/savedstate-ktx-1.4.0-20251003.062603-1.aar
 Version: 1.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/README.chromium b/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/README.chromium
index fef29e0..73ddeaa 100644
--- a/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/README.chromium
@@ -1,6 +1,6 @@
 Name: Sliding Pane Layout
 Short Name: slidingpanelayout
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/slidingpanelayout/slidingpanelayout/1.3.0-SNAPSHOT/slidingpanelayout-1.3.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/slidingpanelayout/slidingpanelayout/1.3.0-SNAPSHOT/slidingpanelayout-1.3.0-20251003.062603-1.aar
 Version: 1.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_swiperefreshlayout_swiperefreshlayout/README.chromium b/third_party/androidx/committed/libs/androidx_swiperefreshlayout_swiperefreshlayout/README.chromium
index ce59bb5b..2fa8b43 100644
--- a/third_party/androidx/committed/libs/androidx_swiperefreshlayout_swiperefreshlayout/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_swiperefreshlayout_swiperefreshlayout/README.chromium
@@ -1,6 +1,6 @@
 Name: Swipe Refresh Layout
 Short Name: swiperefreshlayout
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/swiperefreshlayout/swiperefreshlayout/1.2.0-SNAPSHOT/swiperefreshlayout-1.2.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/swiperefreshlayout/swiperefreshlayout/1.2.0-SNAPSHOT/swiperefreshlayout-1.2.0-20251003.062603-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator/README.chromium b/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator/README.chromium
index 76bfaf8..34ba37e 100644
--- a/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator/README.chromium
@@ -1,6 +1,6 @@
 Name: UIAutomator
 Short Name: uiautomator
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/test/uiautomator/uiautomator/2.4.0-SNAPSHOT/uiautomator-2.4.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/test/uiautomator/uiautomator/2.4.0-SNAPSHOT/uiautomator-2.4.0-20251003.062603-1.aar
 Version: 2.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_transition_transition/README.chromium b/third_party/androidx/committed/libs/androidx_transition_transition/README.chromium
index 5a8b8cc..b7b817d 100644
--- a/third_party/androidx/committed/libs/androidx_transition_transition/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_transition_transition/README.chromium
@@ -1,6 +1,6 @@
 Name: Transition
 Short Name: transition
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/transition/transition/1.7.0-SNAPSHOT/transition-1.7.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/transition/transition/1.7.0-SNAPSHOT/transition-1.7.0-20251003.062603-1.aar
 Version: 1.7.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/README.chromium b/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/README.chromium
index 6e32816..47989fd 100644
--- a/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/README.chromium
@@ -1,6 +1,6 @@
 Name: ViewPager2
 Short Name: viewpager2
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/viewpager2/viewpager2/1.2.0-SNAPSHOT/viewpager2-1.2.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/viewpager2/viewpager2/1.2.0-SNAPSHOT/viewpager2-1.2.0-20251003.062603-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_webkit_webkit/README.chromium b/third_party/androidx/committed/libs/androidx_webkit_webkit/README.chromium
index 895e439..ad711891 100644
--- a/third_party/androidx/committed/libs/androidx_webkit_webkit/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_webkit_webkit/README.chromium
@@ -1,6 +1,6 @@
 Name: Webkit
 Short Name: webkit
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/webkit/webkit/1.15.0-SNAPSHOT/webkit-1.15.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/webkit/webkit/1.15.0-SNAPSHOT/webkit-1.15.0-20251003.062603-1.aar
 Version: 1.15.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/README.chromium b/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/README.chromium
index 12b59df4..d291e19a 100644
--- a/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/README.chromium
@@ -1,6 +1,6 @@
 Name: WindowManager Sidecar
 Short Name: sidecar
-URL: https://androidx.dev/snapshots/builds/14203925/artifacts/repository/androidx/window/sidecar/sidecar/1.0.0-SNAPSHOT/sidecar-1.0.0-20251002.111255-1.aar
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/window/sidecar/sidecar/1.0.0-SNAPSHOT/sidecar-1.0.0-20251003.062603-1.aar
 Version: 1.0.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_window_window/README.chromium b/third_party/androidx/committed/libs/androidx_window_window/README.chromium
index bdafdb53..716d35e 100644
--- a/third_party/androidx/committed/libs/androidx_window_window/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_window_window/README.chromium
@@ -1,7 +1,7 @@
 Name: WindowManager
 Short Name: window
-URL: https://dl.google.com/dl/android/maven2/androidx/window/window/1.5.0/window-1.5.0.aar
-Version: 1.5.0
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/window/window/1.6.0-SNAPSHOT/window-1.6.0-20251003.062603-1.aar
+Version: 1.6.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
 License File: LICENSE
@@ -13,7 +13,7 @@
 Description:
 WindowManager Jetpack library. Currently only provides additional functionality on foldable devices.
 
-See also: https://developer.android.com/jetpack/androidx/releases/window#1.5.0
+See also: https://developer.android.com/jetpack/androidx/releases/window#1.6.0-SNAPSHOT
 
 
 Local Modifications:
diff --git a/third_party/androidx/committed/libs/androidx_window_window_core_android/README.chromium b/third_party/androidx/committed/libs/androidx_window_window_core_android/README.chromium
index 4a62928..6cc8b81 100644
--- a/third_party/androidx/committed/libs/androidx_window_window_core_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_window_window_core_android/README.chromium
@@ -1,7 +1,7 @@
 Name: WindowManager Core
 Short Name: window-core-android
-URL: https://dl.google.com/dl/android/maven2/androidx/window/window-core-android/1.5.0/window-core-android-1.5.0.aar
-Version: 1.5.0
+URL: https://androidx.dev/snapshots/builds/14209644/artifacts/repository/androidx/window/window-core-android/1.6.0-SNAPSHOT/window-core-android-1.6.0-20251003.062603-1.aar
+Version: 1.6.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
 License File: LICENSE
@@ -13,7 +13,7 @@
 Description:
 WindowManager Core Library.
 
-See also: https://developer.android.com/jetpack/androidx/releases/window#1.5.0
+See also: https://developer.android.com/jetpack/androidx/releases/window#1.6.0-SNAPSHOT
 
 
 Local Modifications:
diff --git a/third_party/angle b/third_party/angle
index 538129c..f6b74ac 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit 538129c6b3c17dc864101c7a4af4b74b00706f82
+Subproject commit f6b74ac4a5d4c6ff43f9da1fa7ded6c5d1a4cceb
diff --git a/third_party/blink/renderer/core/annotation/annotation_agent_container_impl.cc b/third_party/blink/renderer/core/annotation/annotation_agent_container_impl.cc
index 6f38239..912a726 100644
--- a/third_party/blink/renderer/core/annotation/annotation_agent_container_impl.cc
+++ b/third_party/blink/renderer/core/annotation/annotation_agent_container_impl.cc
@@ -355,8 +355,15 @@
     return false;
   }
 
-  if (GetFrame().Selection().SelectedText().empty()) {
-    return false;
+  if (RuntimeEnabledFeatures::
+          NonEmptyVisibleTextSelectionForTextFragmentEnabled()) {
+    if (!GetFrame().Selection().HasVisibleText()) {
+      return false;
+    }
+  } else {
+    if (GetFrame().Selection().SelectedText().empty()) {
+      return false;
+    }
   }
 
   if (GetFrame().IsOutermostMainFrame()) {
diff --git a/third_party/blink/renderer/core/css/css_syntax_definition.cc b/third_party/blink/renderer/core/css/css_syntax_definition.cc
index aa8b36f..c9cf668e 100644
--- a/third_party/blink/renderer/core/css/css_syntax_definition.cc
+++ b/third_party/blink/renderer/core/css/css_syntax_definition.cc
@@ -196,8 +196,7 @@
       CSSParserContext::ParserModeOverridingScope scope(context,
                                                         kHTMLStandardMode);
       return css_parsing_utils::ConsumeLengthOrPercent(
-          stream, context, CSSPrimitiveValue::ValueRange::kAll,
-          css_parsing_utils::UnitlessQuirk::kForbid, kCSSAnchorQueryTypesAll);
+          stream, context, CSSPrimitiveValue::ValueRange::kAll);
     }
     case CSSSyntaxType::kColor: {
       CSSParserContext::ParserModeOverridingScope scope(context,
diff --git a/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc b/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc
index 245a5dd3..2392e41f 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc
@@ -244,8 +244,8 @@
   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
   CustomProperty property(AtomicString("--x"), GetDocument());
 
-  // We can't parse anchor queries as a <length>, because it can't be resolved
-  // into a pixel value at style time.
+  // Anchor queries are not allowed in registered custom properties for
+  // <length>.
   EXPECT_FALSE(
       ParseValue(property, "anchor(--foo top)", CSSParserLocalContext()));
   EXPECT_FALSE(ParseValue(property, "anchor-size(--foo width)",
@@ -256,32 +256,15 @@
   RegisterProperty(GetDocument(), "--x", "<length-percentage>", "0px", false);
   CustomProperty property(AtomicString("--x"), GetDocument());
 
-  {
-    const CSSValue* value =
-        ParseValue(property, "anchor(--foo top)", CSSParserLocalContext());
-    ASSERT_TRUE(value);
-    EXPECT_EQ("anchor(--foo top)", value->CssText());
-  }
-
-  {
-    const CSSValue* value = ParseValue(property, "anchor-size(--foo width)",
-                                       CSSParserLocalContext());
-    ASSERT_TRUE(value);
-    EXPECT_EQ("anchor-size(--foo width)", value->CssText());
-  }
-
-  {
-    // There are no restrictions on what anchor queries are allowed in a custom
-    // property, so mixing anchor() and anchor-size() is also allowed, although
-    // using it in any builtin property via var() makes it invalid at
-    // computed-value time.
-    const CSSValue* value = ParseValue(
-        property, "calc(anchor(--foo top) + anchor-size(--foo width))",
-        CSSParserLocalContext());
-    ASSERT_TRUE(value);
-    EXPECT_EQ("calc(anchor(--foo top) + anchor-size(--foo width))",
-              value->CssText());
-  }
+  // Anchor queries are not allowed in registered custom properties for
+  // <length-percentage>.
+  EXPECT_FALSE(
+      ParseValue(property, "anchor(--foo top)", CSSParserLocalContext()));
+  EXPECT_FALSE(ParseValue(property, "anchor-size(--foo width)",
+                          CSSParserLocalContext()));
+  EXPECT_FALSE(ParseValue(property,
+                          "calc(anchor(--foo top) + anchor-size(--foo width))",
+                          CSSParserLocalContext()));
 }
 
 TEST_F(CustomPropertyTest, ValueMode) {
diff --git a/third_party/blink/renderer/core/css/remote_font_face_source.cc b/third_party/blink/renderer/core/css/remote_font_face_source.cc
index 7477480..fb5bd10 100644
--- a/third_party/blink/renderer/core/css/remote_font_face_source.cc
+++ b/third_party/blink/renderer/core/css/remote_font_face_source.cc
@@ -65,6 +65,16 @@
     return kSwapPeriod;
   }
 
+  auto* window =
+      DynamicTo<LocalDOMWindow>(font_selector_->GetExecutionContext());
+  if (window && window->document() && window->document()->Printing()) {
+    // If the page is printing, the font won't finish loading until the page is
+    // resumed. There are problems discussed in crbug.com/346799729.
+    // Currently, to avoid printing invisible text, enter the swap period
+    // immediately, and render with a fallback fontface.
+    return kSwapPeriod;
+  }
+
   switch (phase_) {
     case kNoLimitExceeded:
     case kShortLimitExceeded:
diff --git a/third_party/blink/renderer/core/dom/element_test.cc b/third_party/blink/renderer/core/dom/element_test.cc
index 7f88388..0e5f225c 100644
--- a/third_party/blink/renderer/core/dom/element_test.cc
+++ b/third_party/blink/renderer/core/dom/element_test.cc
@@ -619,29 +619,25 @@
   auto* not_fg = document.getElementById(AtomicString("not_fg"));
   ASSERT_TRUE(not_fg);
 
-  FocusgroupBehavior not_fg_behavior = not_fg->GetFocusgroupData().behavior;
-  EXPECT_EQ(not_fg_behavior, FocusgroupBehavior::kNoBehavior);
+  EXPECT_EQ(
+      not_fg->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kNoBehavior, FocusgroupFlags::kNone));
 
   // Empty focusgroup attribute should be invalid (requires behavior token)
   auto* fg_empty = document.getElementById(AtomicString("fg_empty"));
   ASSERT_TRUE(fg_empty);
 
-  FocusgroupBehavior fg_empty_behavior = fg_empty->GetFocusgroupData().behavior;
-  EXPECT_EQ(fg_empty_behavior, FocusgroupBehavior::kNoBehavior);
+  EXPECT_EQ(
+      fg_empty->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kNoBehavior, FocusgroupFlags::kNone));
 
   // Toolbar behavior with default axes
   auto* fg_toolbar = document.getElementById(AtomicString("fg_toolbar"));
   ASSERT_TRUE(fg_toolbar);
 
-  FocusgroupBehavior fg_toolbar_behavior =
-      fg_toolbar->GetFocusgroupData().behavior;
-  FocusgroupFlags fg_toolbar_flags = fg_toolbar->GetFocusgroupData().flags;
-  EXPECT_EQ(fg_toolbar_behavior, FocusgroupBehavior::kToolbar);
-  EXPECT_TRUE(fg_toolbar_flags & FocusgroupFlags::kInline);
-  EXPECT_TRUE(fg_toolbar_flags & FocusgroupFlags::kBlock);
-  EXPECT_FALSE(fg_toolbar_flags & FocusgroupFlags::kExtend);
-  EXPECT_FALSE(fg_toolbar_flags & FocusgroupFlags::kWrapInline);
-  EXPECT_FALSE(fg_toolbar_flags & FocusgroupFlags::kWrapBlock);
+  EXPECT_EQ(fg_toolbar->GetFocusgroupData(),
+            FocusgroupData(FocusgroupBehavior::kToolbar,
+                           FocusgroupFlags::kInline | FocusgroupFlags::kBlock));
 }
 
 TEST_F(ElementTest, ParseFocusgroupAttrSupportedAxesAreValid) {
@@ -661,61 +657,49 @@
   auto* fg1 = document.getElementById(AtomicString("fg1"));
   ASSERT_TRUE(fg1);
 
-  FocusgroupBehavior fg1_behavior = fg1->GetFocusgroupData().behavior;
-  FocusgroupFlags fg1_flags = fg1->GetFocusgroupData().flags;
-  EXPECT_EQ(fg1_behavior, FocusgroupBehavior::kToolbar);
-  EXPECT_TRUE(fg1_flags & FocusgroupFlags::kInline);
-  EXPECT_FALSE(fg1_flags & FocusgroupFlags::kBlock);
+  EXPECT_EQ(
+      fg1->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kToolbar, FocusgroupFlags::kInline));
 
   // 2. Only block should be supported.
   auto* fg2 = document.getElementById(AtomicString("fg2"));
   EXPECT_TRUE(fg2);
 
-  FocusgroupBehavior fg2_behavior = fg2->GetFocusgroupData().behavior;
-  FocusgroupFlags fg2_flags = fg2->GetFocusgroupData().flags;
-  EXPECT_EQ(fg2_behavior, FocusgroupBehavior::kTablist);
-  EXPECT_FALSE(fg2_flags & FocusgroupFlags::kInline);
-  EXPECT_TRUE(fg2_flags & FocusgroupFlags::kBlock);
+  EXPECT_EQ(
+      fg2->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kTablist, FocusgroupFlags::kBlock));
 
   // 3. No axis specified so both should be supported
   auto* fg3 = document.getElementById(AtomicString("fg3"));
   ASSERT_TRUE(fg3);
 
-  FocusgroupBehavior fg3_behavior = fg3->GetFocusgroupData().behavior;
-  FocusgroupFlags fg3_flags = fg3->GetFocusgroupData().flags;
-  EXPECT_EQ(fg3_behavior, FocusgroupBehavior::kListbox);
-  EXPECT_TRUE(fg3_flags & FocusgroupFlags::kInline);
-  EXPECT_TRUE(fg3_flags & FocusgroupFlags::kBlock);
+  EXPECT_EQ(fg3->GetFocusgroupData(),
+            FocusgroupData(FocusgroupBehavior::kListbox,
+                           FocusgroupFlags::kInline | FocusgroupFlags::kBlock));
 
   // 4. Only support inline because it's specified.
   auto* fg3_a = document.getElementById(AtomicString("fg3_a"));
   ASSERT_TRUE(fg3_a);
 
-  FocusgroupBehavior fg3_a_behavior = fg3_a->GetFocusgroupData().behavior;
-  FocusgroupFlags fg3_a_flags = fg3_a->GetFocusgroupData().flags;
-  EXPECT_EQ(fg3_a_behavior, FocusgroupBehavior::kMenu);
-  EXPECT_TRUE(fg3_a_flags & FocusgroupFlags::kInline);
-  EXPECT_FALSE(fg3_a_flags & FocusgroupFlags::kBlock);
+  EXPECT_EQ(
+      fg3_a->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kMenu, FocusgroupFlags::kInline));
 
   // 5. Only support block because it's specified.
   auto* fg3_b = document.getElementById(AtomicString("fg3_b"));
   ASSERT_TRUE(fg3_b);
 
-  FocusgroupBehavior fg3_b_behavior = fg3_b->GetFocusgroupData().behavior;
-  FocusgroupFlags fg3_b_flags = fg3_b->GetFocusgroupData().flags;
-  EXPECT_EQ(fg3_b_behavior, FocusgroupBehavior::kMenubar);
-  EXPECT_FALSE(fg3_b_flags & FocusgroupFlags::kInline);
-  EXPECT_TRUE(fg3_b_flags & FocusgroupFlags::kBlock);
+  EXPECT_EQ(
+      fg3_b->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kMenubar, FocusgroupFlags::kBlock));
 
   // 6. Child specifying only behavior should still support both axes.
   auto* fg3_b_1 = document.getElementById(AtomicString("fg3_b_1"));
   ASSERT_TRUE(fg3_b_1);
 
-  FocusgroupBehavior fg3_b_1_behavior = fg3_b_1->GetFocusgroupData().behavior;
-  FocusgroupFlags fg3_b_1_flags = fg3_b_1->GetFocusgroupData().flags;
-  EXPECT_EQ(fg3_b_1_behavior, FocusgroupBehavior::kRadiogroup);
-  EXPECT_TRUE(fg3_b_1_flags & FocusgroupFlags::kInline);
-  EXPECT_TRUE(fg3_b_1_flags & FocusgroupFlags::kBlock);
+  EXPECT_EQ(fg3_b_1->GetFocusgroupData(),
+            FocusgroupData(FocusgroupBehavior::kRadiogroup,
+                           FocusgroupFlags::kInline | FocusgroupFlags::kBlock));
 }
 
 TEST_F(ElementTest, ParseFocusgroupAttrWrapIgnoredInDescendantsWithoutOwnWrap) {
@@ -763,77 +747,68 @@
   ASSERT_TRUE(fg11);
   ASSERT_TRUE(fg12);
 
-  FocusgroupBehavior fg1_behavior = fg1->GetFocusgroupData().behavior;
-  FocusgroupFlags fg1_flags = fg1->GetFocusgroupData().flags;
-  EXPECT_NE(fg1_behavior, FocusgroupBehavior::kNoBehavior);
-  EXPECT_FALSE(fg1_flags & FocusgroupFlags::kWrapInline);
-  EXPECT_FALSE(fg1_flags & FocusgroupFlags::kWrapBlock);
+  // Parent supports both axes but no wrap - children should not inherit wrap
+  EXPECT_EQ(fg1->GetFocusgroupData(),
+            FocusgroupData(FocusgroupBehavior::kToolbar,
+                           FocusgroupFlags::kInline | FocusgroupFlags::kBlock));
 
-  FocusgroupBehavior fg2_behavior = fg2->GetFocusgroupData().behavior;
-  FocusgroupFlags fg2_flags = fg2->GetFocusgroupData().flags;
-  EXPECT_NE(fg2_behavior, FocusgroupBehavior::kNoBehavior);
-  EXPECT_TRUE(fg2_flags & FocusgroupFlags::kWrapInline);
-  EXPECT_FALSE(fg2_flags & FocusgroupFlags::kWrapBlock);
+  EXPECT_EQ(
+      fg2->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kToolbar,
+                     FocusgroupFlags::kInline | FocusgroupFlags::kWrapInline));
 
-  FocusgroupBehavior fg3_behavior = fg3->GetFocusgroupData().behavior;
-  FocusgroupFlags fg3_flags = fg3->GetFocusgroupData().flags;
-  EXPECT_NE(fg3_behavior, FocusgroupBehavior::kNoBehavior);
-  EXPECT_FALSE(fg3_flags & FocusgroupFlags::kWrapInline);
-  EXPECT_TRUE(fg3_flags & FocusgroupFlags::kWrapBlock);
+  EXPECT_EQ(
+      fg3->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kToolbar,
+                     FocusgroupFlags::kBlock | FocusgroupFlags::kWrapBlock));
 
-  FocusgroupBehavior fg4_behavior = fg4->GetFocusgroupData().behavior;
-  FocusgroupFlags fg4_flags = fg4->GetFocusgroupData().flags;
-  EXPECT_NE(fg4_behavior, FocusgroupBehavior::kNoBehavior);
-  EXPECT_TRUE(fg4_flags & FocusgroupFlags::kWrapInline);
-  EXPECT_TRUE(fg4_flags & FocusgroupFlags::kWrapBlock);
+  EXPECT_EQ(fg4->GetFocusgroupData(),
+            FocusgroupData(FocusgroupBehavior::kToolbar,
+                           FocusgroupFlags::kInline | FocusgroupFlags::kBlock |
+                               FocusgroupFlags::kWrapInline |
+                               FocusgroupFlags::kWrapBlock));
 
-  FocusgroupBehavior fg5_behavior = fg5->GetFocusgroupData().behavior;
-  FocusgroupFlags fg5_flags = fg5->GetFocusgroupData().flags;
-  EXPECT_NE(fg5_behavior, FocusgroupBehavior::kNoBehavior);
-  EXPECT_FALSE(fg5_flags & FocusgroupFlags::kWrapInline);
-  EXPECT_FALSE(fg5_flags & FocusgroupFlags::kWrapBlock);
+  // Parent supports only inline axis - children inherit this restriction
+  EXPECT_EQ(
+      fg5->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kToolbar, FocusgroupFlags::kInline));
 
-  FocusgroupBehavior fg6_behavior = fg6->GetFocusgroupData().behavior;
-  FocusgroupFlags fg6_flags = fg6->GetFocusgroupData().flags;
-  EXPECT_NE(fg6_behavior, FocusgroupBehavior::kNoBehavior);
-  EXPECT_TRUE(fg6_flags & FocusgroupFlags::kWrapInline);
-  EXPECT_FALSE(fg6_flags & FocusgroupFlags::kWrapBlock);
+  EXPECT_EQ(
+      fg6->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kToolbar,
+                     FocusgroupFlags::kInline | FocusgroupFlags::kWrapInline));
 
-  FocusgroupBehavior fg7_behavior = fg7->GetFocusgroupData().behavior;
-  FocusgroupFlags fg7_flags = fg7->GetFocusgroupData().flags;
-  EXPECT_NE(fg7_behavior, FocusgroupBehavior::kNoBehavior);
-  EXPECT_FALSE(fg7_flags & FocusgroupFlags::kWrapInline);
-  EXPECT_TRUE(fg7_flags & FocusgroupFlags::kWrapBlock);
+  EXPECT_EQ(
+      fg7->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kToolbar,
+                     FocusgroupFlags::kBlock | FocusgroupFlags::kWrapBlock));
 
-  FocusgroupBehavior fg8_behavior = fg8->GetFocusgroupData().behavior;
-  FocusgroupFlags fg8_flags = fg8->GetFocusgroupData().flags;
-  EXPECT_NE(fg8_behavior, FocusgroupBehavior::kNoBehavior);
-  EXPECT_TRUE(fg8_flags & FocusgroupFlags::kWrapInline);
-  EXPECT_TRUE(fg8_flags & FocusgroupFlags::kWrapBlock);
+  EXPECT_EQ(fg8->GetFocusgroupData(),
+            FocusgroupData(FocusgroupBehavior::kToolbar,
+                           FocusgroupFlags::kInline | FocusgroupFlags::kBlock |
+                               FocusgroupFlags::kWrapInline |
+                               FocusgroupFlags::kWrapBlock));
 
-  FocusgroupBehavior fg9_behavior = fg9->GetFocusgroupData().behavior;
-  FocusgroupFlags fg9_flags = fg9->GetFocusgroupData().flags;
-  EXPECT_NE(fg9_behavior, FocusgroupBehavior::kNoBehavior);
-  EXPECT_FALSE(fg9_flags & FocusgroupFlags::kWrapInline);
-  EXPECT_FALSE(fg9_flags & FocusgroupFlags::kWrapBlock);
+  // Parent supports only block axis - children inherit this restriction
+  EXPECT_EQ(
+      fg9->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kToolbar, FocusgroupFlags::kBlock));
 
-  FocusgroupBehavior fg10_behavior = fg10->GetFocusgroupData().behavior;
-  FocusgroupFlags fg10_flags = fg10->GetFocusgroupData().flags;
-  EXPECT_NE(fg10_behavior, FocusgroupBehavior::kNoBehavior);
-  EXPECT_TRUE(fg10_flags & FocusgroupFlags::kWrapInline);
-  EXPECT_FALSE(fg10_flags & FocusgroupFlags::kWrapBlock);
+  EXPECT_EQ(
+      fg10->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kToolbar,
+                     FocusgroupFlags::kInline | FocusgroupFlags::kWrapInline));
 
-  FocusgroupBehavior fg11_behavior = fg11->GetFocusgroupData().behavior;
-  FocusgroupFlags fg11_flags = fg11->GetFocusgroupData().flags;
-  EXPECT_NE(fg11_behavior, FocusgroupBehavior::kNoBehavior);
-  EXPECT_FALSE(fg11_flags & FocusgroupFlags::kWrapInline);
-  EXPECT_TRUE(fg11_flags & FocusgroupFlags::kWrapBlock);
+  EXPECT_EQ(
+      fg11->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kToolbar,
+                     FocusgroupFlags::kBlock | FocusgroupFlags::kWrapBlock));
 
-  FocusgroupBehavior fg12_behavior = fg12->GetFocusgroupData().behavior;
-  FocusgroupFlags fg12_flags = fg12->GetFocusgroupData().flags;
-  EXPECT_NE(fg12_behavior, FocusgroupBehavior::kNoBehavior);
-  EXPECT_TRUE(fg12_flags & FocusgroupFlags::kWrapInline);
-  EXPECT_TRUE(fg12_flags & FocusgroupFlags::kWrapBlock);
+  EXPECT_EQ(fg12->GetFocusgroupData(),
+            FocusgroupData(FocusgroupBehavior::kToolbar,
+                           FocusgroupFlags::kInline | FocusgroupFlags::kBlock |
+                               FocusgroupFlags::kWrapInline |
+                               FocusgroupFlags::kWrapBlock));
 }
 
 TEST_F(ElementTest, ParseFocusgroupAttrGrid) {
@@ -905,41 +880,45 @@
   FocusgroupData e14_data = e14->GetFocusgroupData();
   FocusgroupData e15_data = e15->GetFocusgroupData();
 
-  EXPECT_EQ(e1_data.behavior, FocusgroupBehavior::kGrid);
-  EXPECT_EQ(e2_data.behavior, FocusgroupBehavior::kGrid);
-
-  EXPECT_EQ(e3_data.behavior, FocusgroupBehavior::kGrid);
-  EXPECT_EQ(e3_data.flags,
-            (FocusgroupFlags::kWrapInline | FocusgroupFlags::kWrapBlock));
-  EXPECT_EQ(e4_data.behavior, FocusgroupBehavior::kGrid);
-  EXPECT_EQ(e4_data.flags, (FocusgroupFlags::kWrapInline));
-  EXPECT_EQ(e5_data.flags, (FocusgroupFlags::kWrapBlock));
-  EXPECT_EQ(e5_data.behavior, FocusgroupBehavior::kGrid);
-  EXPECT_EQ(e6_data.flags,
-            (FocusgroupFlags::kWrapInline | FocusgroupFlags::kWrapBlock));
-  EXPECT_EQ(e6_data.behavior, FocusgroupBehavior::kGrid);
-  EXPECT_EQ(e7_data.flags,
-            (FocusgroupFlags::kRowFlow | FocusgroupFlags::kColFlow));
-  EXPECT_EQ(e7_data.behavior, FocusgroupBehavior::kGrid);
-  EXPECT_EQ(e8_data.flags, (FocusgroupFlags::kRowFlow));
-  EXPECT_EQ(e8_data.behavior, FocusgroupBehavior::kGrid);
-  EXPECT_EQ(e9_data.flags, (FocusgroupFlags::kColFlow));
-  EXPECT_EQ(e9_data.behavior, FocusgroupBehavior::kGrid);
-  EXPECT_EQ(e10_data.flags,
-            (FocusgroupFlags::kRowFlow | FocusgroupFlags::kColFlow));
-  EXPECT_EQ(e10_data.behavior, FocusgroupBehavior::kGrid);
-  EXPECT_EQ(e11_data.flags, (FocusgroupFlags::kWrapInline));
-  EXPECT_EQ(e11_data.behavior, FocusgroupBehavior::kGrid);
-  EXPECT_EQ(e12_data.flags,
-            (FocusgroupFlags::kWrapInline | FocusgroupFlags::kColFlow));
-  EXPECT_EQ(e12_data.behavior, FocusgroupBehavior::kGrid);
-  EXPECT_EQ(e13_data.flags, FocusgroupFlags::kWrapBlock);
-  EXPECT_EQ(e13_data.behavior, FocusgroupBehavior::kGrid);
-  EXPECT_EQ(e14_data.flags,
-            (FocusgroupFlags::kWrapBlock | FocusgroupFlags::kRowFlow));
-  EXPECT_EQ(e14_data.behavior, FocusgroupBehavior::kGrid);
+  EXPECT_EQ(e1_data,
+            FocusgroupData(FocusgroupBehavior::kGrid, FocusgroupFlags::kNone));
+  EXPECT_EQ(e2_data,
+            FocusgroupData(FocusgroupBehavior::kGrid, FocusgroupFlags::kNone));
+  EXPECT_EQ(e3_data, FocusgroupData(FocusgroupBehavior::kGrid,
+                                    FocusgroupFlags::kWrapInline |
+                                        FocusgroupFlags::kWrapBlock));
+  EXPECT_EQ(e4_data, FocusgroupData(FocusgroupBehavior::kGrid,
+                                    FocusgroupFlags::kWrapInline));
+  EXPECT_EQ(e5_data, FocusgroupData(FocusgroupBehavior::kGrid,
+                                    FocusgroupFlags::kWrapBlock));
+  EXPECT_EQ(e6_data, FocusgroupData(FocusgroupBehavior::kGrid,
+                                    FocusgroupFlags::kWrapInline |
+                                        FocusgroupFlags::kWrapBlock));
+  EXPECT_EQ(e7_data, FocusgroupData(FocusgroupBehavior::kGrid,
+                                    FocusgroupFlags::kRowFlow |
+                                        FocusgroupFlags::kColFlow));
+  EXPECT_EQ(e8_data, FocusgroupData(FocusgroupBehavior::kGrid,
+                                    FocusgroupFlags::kRowFlow));
+  EXPECT_EQ(e9_data, FocusgroupData(FocusgroupBehavior::kGrid,
+                                    FocusgroupFlags::kColFlow));
+  EXPECT_EQ(e10_data, FocusgroupData(FocusgroupBehavior::kGrid,
+                                     FocusgroupFlags::kRowFlow |
+                                         FocusgroupFlags::kColFlow));
+  // e11 has conflicting wrap/flow for row axis, so should be invalid.
+  EXPECT_EQ(e11_data, FocusgroupData(FocusgroupBehavior::kNoBehavior,
+                                     FocusgroupFlags::kNone));
+  EXPECT_EQ(e12_data, FocusgroupData(FocusgroupBehavior::kGrid,
+                                     FocusgroupFlags::kWrapInline |
+                                         FocusgroupFlags::kColFlow));
+  // e13 has conflicting wrap/flow for column axis, so should be invalid.
+  EXPECT_EQ(e13_data, FocusgroupData(FocusgroupBehavior::kNoBehavior,
+                                     FocusgroupFlags::kNone));
+  EXPECT_EQ(e14_data, FocusgroupData(FocusgroupBehavior::kGrid,
+                                     FocusgroupFlags::kWrapBlock |
+                                         FocusgroupFlags::kRowFlow));
   // e15 should be invalid since "flow" isn't a behavior token
-  EXPECT_EQ(e15_data.behavior, FocusgroupBehavior::kNoBehavior);
+  EXPECT_EQ(e15_data, FocusgroupData(FocusgroupBehavior::kNoBehavior,
+                                     FocusgroupFlags::kNone));
 }
 
 TEST_F(ElementTest, ParseFocusgroupAttrOptOutNone) {
@@ -957,19 +936,17 @@
   ASSERT_TRUE(b);
   ASSERT_TRUE(c);
 
-  FocusgroupBehavior a_behavior = a->GetFocusgroupData().behavior;
-  FocusgroupBehavior b_behavior = b->GetFocusgroupData().behavior;
-  FocusgroupBehavior c_behavior = c->GetFocusgroupData().behavior;
-
-  EXPECT_EQ(a_behavior, FocusgroupBehavior::kOptOut);
+  EXPECT_EQ(a->GetFocusgroupData(), FocusgroupData(FocusgroupBehavior::kOptOut,
+                                                   FocusgroupFlags::kNone));
   EXPECT_FALSE(focusgroup::IsActualFocusgroup(a->GetFocusgroupData()));
 
   // 'none' combined with other tokens should still opt-out (others ignored).
-  EXPECT_EQ(b_behavior, FocusgroupBehavior::kOptOut);
+  EXPECT_EQ(b->GetFocusgroupData(), FocusgroupData(FocusgroupBehavior::kOptOut,
+                                                   FocusgroupFlags::kNone));
   EXPECT_FALSE(focusgroup::IsActualFocusgroup(b->GetFocusgroupData()));
 
   EXPECT_TRUE(focusgroup::IsActualFocusgroup(c->GetFocusgroupData()));
-  EXPECT_NE(c_behavior, FocusgroupBehavior::kNoBehavior);
+  EXPECT_NE(c->GetFocusgroupData().behavior, FocusgroupBehavior::kNoBehavior);
 }
 
 TEST_F(ElementTest, ParseFocusgroupAttrNoMemoryToken) {
@@ -984,20 +961,19 @@
   ASSERT_TRUE(a);
   ASSERT_TRUE(b);
 
-  FocusgroupData a_data = a->GetFocusgroupData();
-  FocusgroupData b_data = b->GetFocusgroupData();
-
   // Default axes (inline+block) plus no-memory.
-  EXPECT_TRUE(focusgroup::IsActualFocusgroup(a_data));
-  EXPECT_TRUE(a_data.flags & FocusgroupFlags::kInline);
-  EXPECT_TRUE(a_data.flags & FocusgroupFlags::kBlock);
-  EXPECT_TRUE(a_data.flags & FocusgroupFlags::kNoMemory);
+  EXPECT_EQ(a->GetFocusgroupData(),
+            FocusgroupData(FocusgroupBehavior::kToolbar,
+                           FocusgroupFlags::kInline | FocusgroupFlags::kBlock |
+                               FocusgroupFlags::kNoMemory));
+  EXPECT_TRUE(focusgroup::IsActualFocusgroup(a->GetFocusgroupData()));
 
   // Explicit inline axis only + no-memory.
-  EXPECT_TRUE(focusgroup::IsActualFocusgroup(b_data));
-  EXPECT_TRUE(b_data.flags & FocusgroupFlags::kInline);
-  EXPECT_FALSE(b_data.flags & FocusgroupFlags::kBlock);
-  EXPECT_TRUE(b_data.flags & FocusgroupFlags::kNoMemory);
+  EXPECT_EQ(
+      b->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kListbox,
+                     FocusgroupFlags::kInline | FocusgroupFlags::kNoMemory));
+  EXPECT_TRUE(focusgroup::IsActualFocusgroup(b->GetFocusgroupData()));
 }
 
 TEST_F(ElementTest, ParseFocusgroupAttrValueRecomputedAfterDOMStructureChange) {
@@ -1015,9 +991,10 @@
   auto* fg2 = document.getElementById(AtomicString("fg2"));
   ASSERT_TRUE(fg2);
 
-  FocusgroupData fg2_data = fg2->GetFocusgroupData();
-  EXPECT_NE(fg2_data.behavior, FocusgroupBehavior::kNoBehavior);
-  EXPECT_TRUE(fg2_data.flags & FocusgroupFlags::kWrapInline);
+  EXPECT_EQ(
+      fg2->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kMenu,
+                     FocusgroupFlags::kInline | FocusgroupFlags::kWrapInline));
 
   // 2. Move |fg2| from |fg1| to |not-fg|.
   auto* not_fg = document.getElementById(AtomicString("not-fg"));
@@ -1027,9 +1004,10 @@
 
   // 3. Validate that the focusgroup properties were updated correctly on |fg2|
   // after they moved to a different ancestor. (No change)
-  fg2_data = fg2->GetFocusgroupData();
-  EXPECT_NE(fg2_data.behavior, FocusgroupBehavior::kNoBehavior);
-  EXPECT_TRUE(fg2_data.flags & FocusgroupFlags::kWrapInline);
+  EXPECT_EQ(
+      fg2->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kMenu,
+                     FocusgroupFlags::kInline | FocusgroupFlags::kWrapInline));
 }
 
 TEST_F(ElementTest, ParseFocusgroupAttrValueClearedAfterNodeRemoved) {
@@ -1045,58 +1023,57 @@
   auto* fg1 = document.getElementById(AtomicString("fg1"));
   ASSERT_TRUE(fg1);
 
-  FocusgroupBehavior fg1_behavior = fg1->GetFocusgroupData().behavior;
-  EXPECT_NE(fg1_behavior, FocusgroupBehavior::kNoBehavior);
+  EXPECT_NE(fg1->GetFocusgroupData().behavior, FocusgroupBehavior::kNoBehavior);
 
   auto* fg2 = document.getElementById(AtomicString("fg2"));
   ASSERT_TRUE(fg2);
 
-  FocusgroupBehavior fg2_behavior = fg2->GetFocusgroupData().behavior;
-  EXPECT_NE(fg2_behavior, FocusgroupBehavior::kNoBehavior);
+  EXPECT_NE(fg2->GetFocusgroupData().behavior, FocusgroupBehavior::kNoBehavior);
 
   // 2. Remove |fg1| from the DOM.
   fg1->remove();
 
   // 3. Validate that the focusgroup properties were cleared from both
   // focusgroups.
-  fg1_behavior = fg1->GetFocusgroupData().behavior;
-  EXPECT_EQ(fg1_behavior, FocusgroupBehavior::kNoBehavior);
+  EXPECT_EQ(
+      fg1->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kNoBehavior, FocusgroupFlags::kNone));
 
-  fg2_behavior = fg2->GetFocusgroupData().behavior;
-  EXPECT_EQ(fg2_behavior, FocusgroupBehavior::kNoBehavior);
+  EXPECT_EQ(
+      fg2->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kNoBehavior, FocusgroupFlags::kNone));
 }
 
 TEST_F(ElementTest, FocusgroupFlagsToString) {
   // Only test flag combinations that the parser can currently produce.
   FocusgroupData none_data{FocusgroupBehavior::kNoBehavior,
                            FocusgroupFlags::kNone};
-  EXPECT_EQ("FocusgroupData(None)",
+  EXPECT_EQ("No behavior",
             focusgroup::FocusgroupDataToStringForTesting(none_data));
 
   // Behavior tokens - toolbar with inline axis.
   FocusgroupData toolbar_inline_data{FocusgroupBehavior::kToolbar,
                                      FocusgroupFlags::kInline};
-  EXPECT_EQ("FocusgroupData(Toolbar:FocusgroupFlags(Inline))",
+  EXPECT_EQ("toolbar:(inline)",
             focusgroup::FocusgroupDataToStringForTesting(toolbar_inline_data));
 
   // Behavior tokens - tablist with inline axis.
   FocusgroupData tablist_inline_data{FocusgroupBehavior::kTablist,
                                      FocusgroupFlags::kInline};
-  EXPECT_EQ("FocusgroupData(Tablist:FocusgroupFlags(Inline))",
+  EXPECT_EQ("tablist:(inline)",
             focusgroup::FocusgroupDataToStringForTesting(tablist_inline_data));
 
   // Behavior tokens - listbox with block axis.
   FocusgroupData listbox_block_data{FocusgroupBehavior::kListbox,
                                     FocusgroupFlags::kBlock};
-  EXPECT_EQ("FocusgroupData(Listbox:FocusgroupFlags(Block))",
+  EXPECT_EQ("listbox:(block)",
             focusgroup::FocusgroupDataToStringForTesting(listbox_block_data));
 
   // Behavior tokens - radiogroup with block axis.
   FocusgroupData radiogroup_block_data{FocusgroupBehavior::kRadiogroup,
                                        FocusgroupFlags::kBlock};
-  EXPECT_EQ(
-      "FocusgroupData(Radiogroup:FocusgroupFlags(Block))",
-      focusgroup::FocusgroupDataToStringForTesting(radiogroup_block_data));
+  EXPECT_EQ("radiogroup:(block)", focusgroup::FocusgroupDataToStringForTesting(
+                                      radiogroup_block_data));
 
   // Linear focusgroup with wrap inline only.
   FocusgroupData toolbar_wrap_inline_data{
@@ -1104,38 +1081,38 @@
       static_cast<FocusgroupFlags>(FocusgroupFlags::kInline |
                                    FocusgroupFlags::kWrapInline)};
   EXPECT_EQ(
-      "FocusgroupData(Toolbar:FocusgroupFlags(Inline|WrapInline))",
+      "toolbar:(inline|wrap|row-wrap)",
       focusgroup::FocusgroupDataToStringForTesting(toolbar_wrap_inline_data));
 
   // Grid basic.
   FocusgroupData grid_basic_data{FocusgroupBehavior::kGrid,
                                  FocusgroupFlags::kNone};
-  EXPECT_EQ("FocusgroupData(Grid:FocusgroupFlags())",
+  EXPECT_EQ("grid:()",
             focusgroup::FocusgroupDataToStringForTesting(grid_basic_data));
 
   // Grid with row wrap only.
   FocusgroupData grid_wrap_inline_data{FocusgroupBehavior::kGrid,
                                        FocusgroupFlags::kWrapInline};
   EXPECT_EQ(
-      "FocusgroupData(Grid:FocusgroupFlags(WrapInline))",
+      "grid:(wrap|row-wrap)",
       focusgroup::FocusgroupDataToStringForTesting(grid_wrap_inline_data));
 
   // Grid with row flow only.
   FocusgroupData grid_row_flow_data{FocusgroupBehavior::kGrid,
                                     FocusgroupFlags::kRowFlow};
-  EXPECT_EQ("FocusgroupData(Grid:FocusgroupFlags(RowFlow))",
+  EXPECT_EQ("grid:(flow|row-flow)",
             focusgroup::FocusgroupDataToStringForTesting(grid_row_flow_data));
 
   // Grid with column flow only.
   FocusgroupData grid_col_flow_data{FocusgroupBehavior::kGrid,
                                     FocusgroupFlags::kColFlow};
-  EXPECT_EQ("FocusgroupData(Grid:FocusgroupFlags(ColFlow))",
+  EXPECT_EQ("grid:(flow|col-flow)",
             focusgroup::FocusgroupDataToStringForTesting(grid_col_flow_data));
 
   // Opt-out.
   FocusgroupData opt_out_data{FocusgroupBehavior::kOptOut,
                               FocusgroupFlags::kNone};
-  EXPECT_EQ("FocusgroupData(OptOut)",
+  EXPECT_EQ("none:()",
             focusgroup::FocusgroupDataToStringForTesting(opt_out_data));
 
   // No-memory modifier with block axis.
@@ -1144,7 +1121,7 @@
       static_cast<FocusgroupFlags>(FocusgroupFlags::kBlock |
                                    FocusgroupFlags::kNoMemory)};
   EXPECT_EQ(
-      "FocusgroupData(Toolbar:FocusgroupFlags(Block|NoMemory))",
+      "toolbar:(block|no-memory)",
       focusgroup::FocusgroupDataToStringForTesting(toolbar_no_memory_data));
 }
 
@@ -1483,93 +1460,75 @@
     <div id=valid_menu focusgroup="menu"></div>
     <div id=valid_menubar focusgroup="menubar"></div>
     <div id=valid_none focusgroup="none"></div>
-    <div id=multiple_behaviors focusgroup="toolbar menu"></div>
   )HTML");
 
   // Empty focusgroup should be invalid
   auto* invalid_empty = document.getElementById(AtomicString("invalid_empty"));
   ASSERT_TRUE(invalid_empty);
-  FocusgroupBehavior invalid_empty_behavior =
-      invalid_empty->GetFocusgroupData().behavior;
-  EXPECT_EQ(invalid_empty_behavior, FocusgroupBehavior::kNoBehavior);
+  EXPECT_EQ(
+      invalid_empty->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kNoBehavior, FocusgroupFlags::kNone));
 
   // Non-behavior token first should be invalid
   auto* invalid_inline_first =
       document.getElementById(AtomicString("invalid_inline_first"));
   ASSERT_TRUE(invalid_inline_first);
-  FocusgroupBehavior invalid_inline_first_behavior =
-      invalid_inline_first->GetFocusgroupData().behavior;
-  EXPECT_EQ(invalid_inline_first_behavior, FocusgroupBehavior::kNoBehavior);
+  EXPECT_EQ(
+      invalid_inline_first->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kNoBehavior, FocusgroupFlags::kNone));
 
   auto* invalid_wrap_first =
       document.getElementById(AtomicString("invalid_wrap_first"));
   ASSERT_TRUE(invalid_wrap_first);
-  FocusgroupBehavior invalid_wrap_first_behavior =
-      invalid_wrap_first->GetFocusgroupData().behavior;
-  EXPECT_EQ(invalid_wrap_first_behavior, FocusgroupBehavior::kNoBehavior);
+  EXPECT_EQ(
+      invalid_wrap_first->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kNoBehavior, FocusgroupFlags::kNone));
 
   // Valid behavior tokens should work
   auto* valid_toolbar = document.getElementById(AtomicString("valid_toolbar"));
   ASSERT_TRUE(valid_toolbar);
-  FocusgroupBehavior toolbar_behavior =
-      valid_toolbar->GetFocusgroupData().behavior;
-  FocusgroupFlags toolbar_flags = valid_toolbar->GetFocusgroupData().flags;
-  EXPECT_EQ(toolbar_behavior, FocusgroupBehavior::kToolbar);
-  EXPECT_TRUE(toolbar_flags & FocusgroupFlags::kInline);
-  EXPECT_TRUE(toolbar_flags & FocusgroupFlags::kBlock);
+  EXPECT_EQ(valid_toolbar->GetFocusgroupData(),
+            FocusgroupData(FocusgroupBehavior::kToolbar,
+                           FocusgroupFlags::kInline | FocusgroupFlags::kBlock));
 
   auto* valid_tablist = document.getElementById(AtomicString("valid_tablist"));
   ASSERT_TRUE(valid_tablist);
-  FocusgroupBehavior tablist_behavior =
-      valid_tablist->GetFocusgroupData().behavior;
-  FocusgroupFlags tablist_flags = valid_tablist->GetFocusgroupData().flags;
-  EXPECT_EQ(tablist_behavior, FocusgroupBehavior::kTablist);
-  EXPECT_TRUE(tablist_flags & FocusgroupFlags::kInline);
-  EXPECT_FALSE(tablist_flags & FocusgroupFlags::kBlock);
+  EXPECT_EQ(
+      valid_tablist->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kTablist, FocusgroupFlags::kInline));
 
   auto* valid_radiogroup =
       document.getElementById(AtomicString("valid_radiogroup"));
   ASSERT_TRUE(valid_radiogroup);
-  FocusgroupBehavior radiogroup_behavior =
-      valid_radiogroup->GetFocusgroupData().behavior;
-  FocusgroupFlags radiogroup_flags =
-      valid_radiogroup->GetFocusgroupData().flags;
-  EXPECT_EQ(radiogroup_behavior, FocusgroupBehavior::kRadiogroup);
-  EXPECT_FALSE(radiogroup_flags & FocusgroupFlags::kInline);
-  EXPECT_TRUE(radiogroup_flags & FocusgroupFlags::kBlock);
+  EXPECT_EQ(
+      valid_radiogroup->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kRadiogroup, FocusgroupFlags::kBlock));
 
   auto* valid_listbox = document.getElementById(AtomicString("valid_listbox"));
   ASSERT_TRUE(valid_listbox);
-  FocusgroupBehavior listbox_behavior =
-      valid_listbox->GetFocusgroupData().behavior;
-  FocusgroupFlags listbox_flags = valid_listbox->GetFocusgroupData().flags;
-  EXPECT_EQ(listbox_behavior, FocusgroupBehavior::kListbox);
-  EXPECT_TRUE(listbox_flags & FocusgroupFlags::kWrapInline);
-  EXPECT_TRUE(listbox_flags & FocusgroupFlags::kWrapBlock);
+  EXPECT_EQ(valid_listbox->GetFocusgroupData(),
+            FocusgroupData(FocusgroupBehavior::kListbox,
+                           FocusgroupFlags::kInline | FocusgroupFlags::kBlock |
+                               FocusgroupFlags::kWrapInline |
+                               FocusgroupFlags::kWrapBlock));
 
   auto* valid_menu = document.getElementById(AtomicString("valid_menu"));
   ASSERT_TRUE(valid_menu);
-  FocusgroupBehavior menu_behavior = valid_menu->GetFocusgroupData().behavior;
-  EXPECT_EQ(menu_behavior, FocusgroupBehavior::kMenu);
+  EXPECT_EQ(valid_menu->GetFocusgroupData(),
+            FocusgroupData(FocusgroupBehavior::kMenu,
+                           FocusgroupFlags::kInline | FocusgroupFlags::kBlock));
 
   auto* valid_menubar = document.getElementById(AtomicString("valid_menubar"));
   ASSERT_TRUE(valid_menubar);
-  FocusgroupBehavior menubar_behavior =
-      valid_menubar->GetFocusgroupData().behavior;
-  EXPECT_EQ(menubar_behavior, FocusgroupBehavior::kMenubar);
+  EXPECT_EQ(valid_menubar->GetFocusgroupData(),
+            FocusgroupData(FocusgroupBehavior::kMenubar,
+                           FocusgroupFlags::kInline | FocusgroupFlags::kBlock));
 
   auto* valid_none = document.getElementById(AtomicString("valid_none"));
   ASSERT_TRUE(valid_none);
-  FocusgroupBehavior none_behavior = valid_none->GetFocusgroupData().behavior;
-  EXPECT_EQ(none_behavior, FocusgroupBehavior::kOptOut);
-
-  // Multiple behavior tokens should be invalid
-  auto* multiple_behaviors =
-      document.getElementById(AtomicString("multiple_behaviors"));
-  ASSERT_TRUE(multiple_behaviors);
-  FocusgroupBehavior multiple_behavior =
-      multiple_behaviors->GetFocusgroupData().behavior;
-  EXPECT_EQ(multiple_behavior, FocusgroupBehavior::kNoBehavior);
+  EXPECT_EQ(
+      valid_none->GetFocusgroupData(),
+      FocusgroupData(FocusgroupBehavior::kOptOut, FocusgroupFlags::kNone));
 }
 
 // Provide assertion-prettify function for gtest.
@@ -1577,6 +1536,9 @@
 void PrintTo(FocusgroupFlags flags, std::ostream* os) {
   *os << FocusgroupFlagsToStringForTesting(flags).Utf8().c_str();
 }
+void PrintTo(FocusgroupData data, std::ostream* os) {
+  *os << FocusgroupDataToStringForTesting(data).Utf8().c_str();
+}
 }  // namespace focusgroup
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/focusgroup_flags.cc b/third_party/blink/renderer/core/dom/focusgroup_flags.cc
index 47510fd1..f9bf6363 100644
--- a/third_party/blink/renderer/core/dom/focusgroup_flags.cc
+++ b/third_party/blink/renderer/core/dom/focusgroup_flags.cc
@@ -22,6 +22,121 @@
 
 namespace blink::focusgroup {
 
+namespace {
+struct FlagMapping {
+  const char* token;
+  FocusgroupFlags flag;
+};
+
+struct BehaviorMapping {
+  const char* token;
+  FocusgroupBehavior behavior;
+  ax::mojom::blink::Role aria_role;
+};
+
+// List of behavior flags and corresponding ARIA role mappings.
+// This should be kept in sync with FocusgroupBehavior.
+constexpr BehaviorMapping kBehaviorMap[] = {
+    {"toolbar", FocusgroupBehavior::kToolbar, ax::mojom::blink::Role::kToolbar},
+    {"tablist", FocusgroupBehavior::kTablist, ax::mojom::blink::Role::kTabList},
+    {"radiogroup", FocusgroupBehavior::kRadiogroup,
+     ax::mojom::blink::Role::kRadioGroup},
+    {"listbox", FocusgroupBehavior::kListbox, ax::mojom::blink::Role::kListBox},
+    {"menu", FocusgroupBehavior::kMenu, ax::mojom::blink::Role::kMenu},
+    {"menubar", FocusgroupBehavior::kMenubar, ax::mojom::blink::Role::kMenuBar},
+    {"grid", FocusgroupBehavior::kGrid, ax::mojom::blink::Role::kGrid},
+    {"none", FocusgroupBehavior::kOptOut, ax::mojom::blink::Role::kUnknown}};
+
+// Unified mapping of all recognized modifier tokens.
+// This should be kept in sync with FocusgroupFlags.
+constexpr FlagMapping kModifierMap[] = {
+    {"inline", FocusgroupFlags::kInline},
+    {"block", FocusgroupFlags::kBlock},
+    {"wrap", FocusgroupFlags::kWrapInline | FocusgroupFlags::kWrapBlock},
+    {"row-wrap", FocusgroupFlags::kWrapInline},
+    {"col-wrap", FocusgroupFlags::kWrapBlock},
+    {"flow", FocusgroupFlags::kRowFlow | FocusgroupFlags::kColFlow},
+    {"row-flow", FocusgroupFlags::kRowFlow},
+    {"col-flow", FocusgroupFlags::kColFlow},
+    {"no-memory", FocusgroupFlags::kNoMemory},
+    // Deprecated: {"extend", FocusgroupFlags::kExtend},
+};
+
+// Returns true if a flag contains a modifier only meaningful for grid
+// focusgroups.
+inline bool IsGridOnlyFlag(FocusgroupFlags flag) {
+  // The grid behavior and flow flags are grid-only.
+  bool any_flow =
+      flag & (FocusgroupFlags::kRowFlow | FocusgroupFlags::kColFlow);
+
+  // Wrapping in a single axis is grid-only.
+  bool wrap_inline = flag & FocusgroupFlags::kWrapInline;
+  bool wrap_block = flag & FocusgroupFlags::kWrapBlock;
+  bool exactly_one_wrap = wrap_inline != wrap_block;
+  return any_flow || exactly_one_wrap;
+}
+
+// Returns a string representation of all valid behavior tokens.
+String ValidBehaviorTokenListString(ExecutionContext* context) {
+  const bool is_grid_enabled =
+      RuntimeEnabledFeatures::FocusgroupGridEnabled(context);
+
+  std::string assembled;
+  for (const auto& behavior_mapping : kBehaviorMap) {
+    // Filter out grid token when grid is disabled.
+    if (!is_grid_enabled &&
+        behavior_mapping.behavior == FocusgroupBehavior::kGrid) {
+      continue;
+    }
+    if (!assembled.empty()) {
+      assembled.append(", ");
+    }
+    DCHECK_NE(behavior_mapping.token, String());
+    assembled.append(behavior_mapping.token);
+  }
+  return String(assembled.c_str());
+}
+
+String ValidTokenListString(ExecutionContext* context) {
+  const bool is_grid_enabled =
+      RuntimeEnabledFeatures::FocusgroupGridEnabled(context);
+
+  std::string assembled;
+  for (const auto& mapping : kModifierMap) {
+    // Filter out grid-only tokens when grid is disabled.
+    if (!is_grid_enabled && IsGridOnlyFlag(mapping.flag)) {
+      continue;
+    }
+    if (!assembled.empty()) {
+      assembled.append(", ");
+    }
+    DCHECK_NE(mapping.token, String());
+    assembled.append(mapping.token);
+  }
+  return String(assembled.c_str());
+}
+
+// Returns the corresponding flag for a recognized token, or kNone if invalid.
+FocusgroupFlags FocusgroupFlagFromString(const AtomicString& token) {
+  for (const auto& td : kModifierMap) {
+    if (token == td.token) {
+      return td.flag;
+    }
+  }
+  return FocusgroupFlags::kNone;
+}
+
+FocusgroupBehavior FocusgroupBehaviorFromString(const AtomicString& token) {
+  for (const auto& td : kBehaviorMap) {
+    if (token == td.token) {
+      return td.behavior;
+    }
+  }
+  return FocusgroupBehavior::kNoBehavior;
+}
+
+}  // namespace
+
 FocusgroupData FindNearestFocusgroupAncestorData(const Element* element) {
   Element* ancestor = FlatTreeTraversal::ParentElement(*element);
   while (ancestor) {
@@ -40,10 +155,11 @@
   DCHECK(element);
   ExecutionContext* context = element->GetExecutionContext();
   DCHECK(RuntimeEnabledFeatures::FocusgroupEnabled(context));
+  const bool is_grid_enabled =
+      RuntimeEnabledFeatures::FocusgroupGridEnabled(context);
 
   UseCounter::Count(context, WebFeature::kFocusgroup);
 
-  // 1. Parse the input.
   bool has_inline = false;
   bool has_block = false;
   bool has_wrap = false;
@@ -53,209 +169,152 @@
   bool has_row_flow = false;
   bool has_col_flow = false;
   bool has_no_memory = false;
-  StringBuilder invalid_tokens;
 
-  SpaceSplitString tokens(input);
-
-  // Check if first token is a behavior token
-  if (tokens.size() == 0) {
-    element->GetDocument().AddConsoleMessage(MakeGarbageCollected<
-                                             ConsoleMessage>(
-        mojom::blink::ConsoleMessageSource::kOther,
-        mojom::blink::ConsoleMessageLevel::kError,
-        "Focusgroup attribute requires a behavior token as the first value."));
-    return {};
-  }
-
-  // Validate that first token is a behavior token
-  AtomicString first_token = tokens[0].LowerASCII();
-  bool first_token_is_behavior =
-      (first_token == "toolbar" || first_token == "tablist" ||
-       first_token == "radiogroup" || first_token == "listbox" ||
-       first_token == "menu" || first_token == "menubar" ||
-       first_token == "grid" || first_token == "none");
-
-  if (!first_token_is_behavior) {
+  // Helpers to avoid repeated enum boilerplate for console messages.
+  auto Warn = [&](const String& msg) {
     element->GetDocument().AddConsoleMessage(
         MakeGarbageCollected<ConsoleMessage>(
             mojom::blink::ConsoleMessageSource::kOther,
-            mojom::blink::ConsoleMessageLevel::kError,
-            StrCat({"Focusgroup attribute requires a behavior token (toolbar, "
-                    "tablist, radiogroup, listbox, menu, menubar, grid, none) "
-                    "as the first value. Found: '",
-                    first_token, "'."})));
+            mojom::blink::ConsoleMessageLevel::kWarning, msg));
+  };
+  auto Error = [&](const String& msg) {
+    element->GetDocument().AddConsoleMessage(
+        MakeGarbageCollected<ConsoleMessage>(
+            mojom::blink::ConsoleMessageSource::kOther,
+            mojom::blink::ConsoleMessageLevel::kError, msg));
+  };
+
+  SpaceSplitString tokens(input);
+
+  // Build a consolidated error message for missing/invalid first token.
+  auto FirstTokenErrorMessage = [&]() {
+    return String(StrCat({"focusgroup requires a behavior token (",
+                          ValidBehaviorTokenListString(context),
+                          ") or 'none' as the first value."}));
+  };
+
+  // Two step process - first parse all flags, then validate the combination for
+  // the given behavior.
+
+  // 1. Parse the input.
+  // Handle empty input (no tokens case).
+  if (tokens.size() == 0) {
+    Error(FirstTokenErrorMessage());
     return {};
   }
 
+  // Validate and consume the first token before iterating the rest.
+  AtomicString first_token = tokens[0].LowerASCII();
+  // First token is the single allowed behavior.
   FocusgroupData data;
-  for (unsigned i = 0; i < tokens.size(); i++) {
-    AtomicString lowercase_token = tokens[i].LowerASCII();
-    if (lowercase_token == "toolbar") {
-      if (data.behavior != FocusgroupBehavior::kNoBehavior) {
-        element->GetDocument().AddConsoleMessage(
-            MakeGarbageCollected<ConsoleMessage>(
-                mojom::blink::ConsoleMessageSource::kOther,
-                mojom::blink::ConsoleMessageLevel::kError,
-                "Focusgroup attribute can only specify one behavior token."));
-        return {};
-      }
-      data.behavior = FocusgroupBehavior::kToolbar;
-    } else if (lowercase_token == "tablist") {
-      if (data.behavior != FocusgroupBehavior::kNoBehavior) {
-        element->GetDocument().AddConsoleMessage(
-            MakeGarbageCollected<ConsoleMessage>(
-                mojom::blink::ConsoleMessageSource::kOther,
-                mojom::blink::ConsoleMessageLevel::kError,
-                "Focusgroup attribute can only specify one behavior token."));
-        return {};
-      }
-      data.behavior = FocusgroupBehavior::kTablist;
-    } else if (lowercase_token == "radiogroup") {
-      if (data.behavior != FocusgroupBehavior::kNoBehavior) {
-        element->GetDocument().AddConsoleMessage(
-            MakeGarbageCollected<ConsoleMessage>(
-                mojom::blink::ConsoleMessageSource::kOther,
-                mojom::blink::ConsoleMessageLevel::kError,
-                "Focusgroup attribute can only specify one behavior token."));
-        return {};
-      }
-      data.behavior = FocusgroupBehavior::kRadiogroup;
-    } else if (lowercase_token == "listbox") {
-      if (data.behavior != FocusgroupBehavior::kNoBehavior) {
-        element->GetDocument().AddConsoleMessage(
-            MakeGarbageCollected<ConsoleMessage>(
-                mojom::blink::ConsoleMessageSource::kOther,
-                mojom::blink::ConsoleMessageLevel::kError,
-                "Focusgroup attribute can only specify one behavior token."));
-        return {};
-      }
-      data.behavior = FocusgroupBehavior::kListbox;
-    } else if (lowercase_token == "menu") {
-      if (data.behavior != FocusgroupBehavior::kNoBehavior) {
-        element->GetDocument().AddConsoleMessage(
-            MakeGarbageCollected<ConsoleMessage>(
-                mojom::blink::ConsoleMessageSource::kOther,
-                mojom::blink::ConsoleMessageLevel::kError,
-                "Focusgroup attribute can only specify one behavior token."));
-        return {};
-      }
-      data.behavior = FocusgroupBehavior::kMenu;
-    } else if (lowercase_token == "menubar") {
-      if (data.behavior != FocusgroupBehavior::kNoBehavior) {
-        element->GetDocument().AddConsoleMessage(
-            MakeGarbageCollected<ConsoleMessage>(
-                mojom::blink::ConsoleMessageSource::kOther,
-                mojom::blink::ConsoleMessageLevel::kError,
-                "Focusgroup attribute can only specify one behavior token."));
-        return {};
-      }
-      data.behavior = FocusgroupBehavior::kMenubar;
-    } else if (lowercase_token == "grid" &&
-               RuntimeEnabledFeatures::FocusgroupGridEnabled(
-                   element->GetExecutionContext())) {
-      if (data.behavior != FocusgroupBehavior::kNoBehavior) {
-        element->GetDocument().AddConsoleMessage(
-            MakeGarbageCollected<ConsoleMessage>(
-                mojom::blink::ConsoleMessageSource::kOther,
-                mojom::blink::ConsoleMessageLevel::kError,
-                "Focusgroup attribute can only specify one behavior token."));
-        return {};
-      }
-      data.behavior = FocusgroupBehavior::kGrid;
-    } else if (lowercase_token == "none") {
-      if (data.behavior != FocusgroupBehavior::kNoBehavior) {
-        element->GetDocument().AddConsoleMessage(
-            MakeGarbageCollected<ConsoleMessage>(
-                mojom::blink::ConsoleMessageSource::kOther,
-                mojom::blink::ConsoleMessageLevel::kError,
-                "Focusgroup attribute can only specify one behavior token."));
-        return {};
-      }
-      data.behavior = FocusgroupBehavior::kOptOut;
-    } else if (lowercase_token == "inline") {
-      has_inline = true;
-    } else if (lowercase_token == "block") {
-      has_block = true;
-    } else if (lowercase_token == "wrap") {
-      has_wrap = true;
-    } else if (lowercase_token == "row-wrap") {
-      has_row_wrap = true;
-    } else if (lowercase_token == "col-wrap") {
-      has_col_wrap = true;
-    } else if (lowercase_token == "flow") {
-      has_flow = true;
-    } else if (lowercase_token == "row-flow") {
-      has_row_flow = true;
-    } else if (lowercase_token == "col-flow") {
-      has_col_flow = true;
-    } else if (lowercase_token == "no-memory") {
-      has_no_memory = true;
-    } else {
-      if (!invalid_tokens.empty())
-        invalid_tokens.Append(", ");
+  data.behavior = FocusgroupBehaviorFromString(first_token);
 
-      // We don't use |lowercase_token| here since that string value will be
-      // logged in the console and we want it to match the input.
+  if (data.behavior == FocusgroupBehavior::kNoBehavior) {
+    // Unrecognized first token, emit error and return.
+    Error(StrCat({FirstTokenErrorMessage(), " Found: '", first_token, "'."}));
+    return {};
+  }
+
+  if (data.behavior == FocusgroupBehavior::kGrid && !is_grid_enabled) {
+    Error(
+        "Focusgroup behavior 'grid' is not supported because the "
+        "FocusgroupGrid feature is disabled.");
+    return {};
+  }
+
+  if (data.behavior == FocusgroupBehavior::kOptOut) {
+    if (tokens.size() > 1) {
+      Warn(
+          "focusgroup attribute value 'none' disables focusgroup behavior; all "
+          "other tokens are ignored.");
+    }
+    return {FocusgroupBehavior::kOptOut, FocusgroupFlags::kNone};
+  }
+
+  StringBuilder invalid_tokens;
+  // Start at the second token.
+  for (unsigned i = 1; i < tokens.size(); i++) {
+    AtomicString lowercase_token = tokens[i].LowerASCII();
+    // The fist token is always a behavior, subsequent tokens are modifiers.
+    FocusgroupFlags flag = FocusgroupFlagFromString(lowercase_token);
+    // If this is a grid-only modifier flag and the grid feature is disabled,
+    // warn and ignore it (do not classify as invalid for easier to understand
+    // warnings).
+    if (IsGridOnlyFlag(flag) && !is_grid_enabled) {
+      Warn(StrCat({"focusgroup attribute value '", lowercase_token,
+                   "' ignored because grid focusgroups are disabled."}));
+      continue;
+    }
+
+    // Handle unrecognized tokens.
+    if (flag == FocusgroupFlags::kNone) {
+      if (!invalid_tokens.empty()) {
+        invalid_tokens.Append(", ");
+      }
       invalid_tokens.Append(tokens[i]);
+      continue;
+    }
+
+    // Handle other tokens.
+    if (flag & FocusgroupFlags::kNoMemory) {
+      has_no_memory = true;
+    } else if (flag & FocusgroupFlags::kInline) {
+      has_inline = true;
+    } else if (flag & FocusgroupFlags::kBlock) {
+      has_block = true;
+    } else if (flag & FocusgroupFlags::kWrapInline &&
+               flag & FocusgroupFlags::kWrapBlock) {
+      has_wrap = true;
+    } else if (flag & FocusgroupFlags::kWrapInline) {
+      CHECK(is_grid_enabled);
+      has_row_wrap = true;
+    } else if (flag & FocusgroupFlags::kWrapBlock) {
+      CHECK(is_grid_enabled);
+      has_col_wrap = true;
+    } else if (flag & FocusgroupFlags::kRowFlow &&
+               flag & FocusgroupFlags::kColFlow) {
+      CHECK(is_grid_enabled);
+      has_flow = true;
+    } else if (flag & FocusgroupFlags::kRowFlow) {
+      CHECK(is_grid_enabled);
+      has_row_flow = true;
+    } else if (flag & FocusgroupFlags::kColFlow) {
+      CHECK(is_grid_enabled);
+      has_col_flow = true;
     }
   }
 
   if (!invalid_tokens.empty()) {
-    element->GetDocument().AddConsoleMessage(
-        MakeGarbageCollected<ConsoleMessage>(
-            mojom::blink::ConsoleMessageSource::kOther,
-            mojom::blink::ConsoleMessageLevel::kError,
-            StrCat({"Unrecognized focusgroup attribute values: ",
-                    invalid_tokens.ReleaseString()})));
+    StringBuilder builder;
+    builder.Append("Unrecognized focusgroup attribute values encountered: ");
+    builder.Append(invalid_tokens.ReleaseString());
+    builder.Append(". Valid tokens are: ");
+    builder.Append(ValidTokenListString(context));
+    builder.Append('.');
+    Warn(builder.ToString());
   }
 
-  // Check if any behavior was specified (required)
-  if (data.behavior == FocusgroupBehavior::kNoBehavior) {
-    element->GetDocument().AddConsoleMessage(
-        MakeGarbageCollected<ConsoleMessage>(
-            mojom::blink::ConsoleMessageSource::kOther,
-            mojom::blink::ConsoleMessageLevel::kError,
-            "Focusgroup attribute requires a behavior token."));
-    return {};
+  // Set the memory flag before the branch between grid and linear focusgroups.
+  if (has_no_memory) {
+    data.flags |= FocusgroupFlags::kNoMemory;
   }
 
-  // Opt-out short-circuits all other semantics. If combined with any other
-  // recognized token emit a console message and ignore the others.
-  if (data.behavior == FocusgroupBehavior::kOptOut) {
-    if (data.flags != FocusgroupFlags::kNone) {
-      element->GetDocument().AddConsoleMessage(
-          MakeGarbageCollected<ConsoleMessage>(
-              mojom::blink::ConsoleMessageSource::kOther,
-              mojom::blink::ConsoleMessageLevel::kError,
-              "Focusgroup attribute value 'none' cannot be combined with other"
-              " focusgroup attribute values; all others ignored."));
-    }
-    // Return early for opt-out behavior - no additional flags needed
-    return data;
-  }
+  // 2. Go over the set flags and ensure the combination is valid.
 
-  // 2. Apply the grid focusgroup logic:
-  //     * 'grid' can only be set on an HTML table element.
-  //     * The grid-related wrap/flow can only be set on a grid focusgroup.
+  // Grid focusgroup specific validation and flag setting.
   if (data.behavior == FocusgroupBehavior::kGrid) {
     // Set the wrap/flow flags, if specified.
     if (has_wrap) {
       data.flags |= FocusgroupFlags::kWrapInline | FocusgroupFlags::kWrapBlock;
       if (has_row_wrap) {
-        element->GetDocument().AddConsoleMessage(
-            MakeGarbageCollected<ConsoleMessage>(
-                mojom::blink::ConsoleMessageSource::kOther,
-                mojom::blink::ConsoleMessageLevel::kWarning,
-                "Focusgroup attribute value 'row-wrap' present, but can be "
-                "omitted because focusgroup already wraps in both axes."));
+        Warn(
+            "Focusgroup attribute value 'row-wrap' present, but can be "
+            "omitted because focusgroup already wraps in both axes.");
       }
       if (has_col_wrap) {
-        element->GetDocument().AddConsoleMessage(
-            MakeGarbageCollected<ConsoleMessage>(
-                mojom::blink::ConsoleMessageSource::kOther,
-                mojom::blink::ConsoleMessageLevel::kWarning,
-                "Focusgroup attribute value 'col-wrap' present, but can be "
-                "omitted because focusgroup already wraps in both axes."));
+        Warn(
+            "Focusgroup attribute value 'col-wrap' present, but can be "
+            "omitted because focusgroup already wraps in both axes.");
       }
     } else {
       if (has_row_wrap)
@@ -264,168 +323,119 @@
         data.flags |= FocusgroupFlags::kWrapBlock;
 
       if (has_row_wrap && has_col_wrap) {
-        element->GetDocument().AddConsoleMessage(
-            MakeGarbageCollected<ConsoleMessage>(
-                mojom::blink::ConsoleMessageSource::kOther,
-                mojom::blink::ConsoleMessageLevel::kWarning,
-                "Focusgroup attribute values 'row-wrap col-wrap' should be "
-                "replaced by 'wrap'."));
+        Warn(
+            "Focusgroup attribute values 'row-wrap col-wrap' should be "
+            "replaced by 'wrap'.");
       }
     }
 
     if (has_flow) {
       if (data.flags & FocusgroupFlags::kWrapInline ||
           data.flags & FocusgroupFlags::kWrapBlock) {
-        element->GetDocument().AddConsoleMessage(MakeGarbageCollected<
-                                                 ConsoleMessage>(
-            mojom::blink::ConsoleMessageSource::kOther,
-            mojom::blink::ConsoleMessageLevel::kError,
+        Error(
             "Focusgroup attribute value 'flow' present, but focusgroup already "
-            "set to wrap in at least one axis."));
+            "set to wrap in at least one axis.");
+        return {};
       } else {
         data.flags |= FocusgroupFlags::kRowFlow | FocusgroupFlags::kColFlow;
         if (has_row_flow) {
-          element->GetDocument().AddConsoleMessage(
-              MakeGarbageCollected<ConsoleMessage>(
-                  mojom::blink::ConsoleMessageSource::kOther,
-                  mojom::blink::ConsoleMessageLevel::kWarning,
-                  "Focusgroup attribute value 'row-flow' present, but can be "
-                  "omitted because focusgroup already flows in both axes."));
+          Warn(
+              "Focusgroup attribute value 'row-flow' present, but can be "
+              "omitted because focusgroup already flows in both axes.");
         }
         if (has_col_flow) {
-          element->GetDocument().AddConsoleMessage(
-              MakeGarbageCollected<ConsoleMessage>(
-                  mojom::blink::ConsoleMessageSource::kOther,
-                  mojom::blink::ConsoleMessageLevel::kWarning,
-                  "Focusgroup attribute value 'col-flow' present, but can be "
-                  "omitted because focusgroup already flows in both axes."));
+          Warn(
+              "Focusgroup attribute value 'col-flow' present, but can be "
+              "omitted because focusgroup already flows in both axes.");
         }
       }
     } else {
       if (has_row_flow) {
         if (data.flags & FocusgroupFlags::kWrapInline) {
-          element->GetDocument().AddConsoleMessage(
-              MakeGarbageCollected<ConsoleMessage>(
-                  mojom::blink::ConsoleMessageSource::kOther,
-                  mojom::blink::ConsoleMessageLevel::kError,
-                  "Focusgroup attribute value 'row-flow' present, but "
-                  "focusgroup already wraps in the row axis."));
+          Error(
+              "Focusgroup attribute value 'row-flow' present, but "
+              "focusgroup already wraps in the row axis.");
+          return {};
         } else {
           data.flags |= FocusgroupFlags::kRowFlow;
         }
       }
       if (has_col_flow) {
         if (data.flags & FocusgroupFlags::kWrapBlock) {
-          element->GetDocument().AddConsoleMessage(
-              MakeGarbageCollected<ConsoleMessage>(
-                  mojom::blink::ConsoleMessageSource::kOther,
-                  mojom::blink::ConsoleMessageLevel::kError,
-                  "Focusgroup attribute value 'col-flow' present, but "
-                  "focusgroup already wraps in the column axis."));
+          Error(
+              "Focusgroup attribute value 'col-flow' present, but "
+              "focusgroup already wraps in the column axis.");
+          return {};
         } else {
           data.flags |= FocusgroupFlags::kColFlow;
         }
       }
       if (data.flags & FocusgroupFlags::kRowFlow &&
           data.flags & FocusgroupFlags::kColFlow) {
-        element->GetDocument().AddConsoleMessage(
-            MakeGarbageCollected<ConsoleMessage>(
-                mojom::blink::ConsoleMessageSource::kOther,
-                mojom::blink::ConsoleMessageLevel::kWarning,
-                "Focusgroup attribute values 'row-flow col-flow' should be "
-                "replaced by 'flow'."));
+        Warn(
+            "Focusgroup attribute values 'row-flow col-flow' should be "
+            "replaced by 'flow'.");
       }
     }
 
     // These values are reserved for linear focusgroups.
     if (has_inline) {
-      element->GetDocument().AddConsoleMessage(
-          MakeGarbageCollected<ConsoleMessage>(
-              mojom::blink::ConsoleMessageSource::kOther,
-              mojom::blink::ConsoleMessageLevel::kError,
-              "Focusgroup attribute value 'inline' present, but has no effect "
-              "on grid focusgroups."));
+      Warn(
+          "Focusgroup attribute value 'inline' is not valid for grid "
+          "focusgroups; use row-wrap/col-wrap or flow modifiers instead.");
     }
     if (has_block) {
-      element->GetDocument().AddConsoleMessage(
-          MakeGarbageCollected<ConsoleMessage>(
-              mojom::blink::ConsoleMessageSource::kOther,
-              mojom::blink::ConsoleMessageLevel::kError,
-              "Focusgroup attribute value 'block' present, but has no effect "
-              "on grid focusgroups."));
-    }
-
-    if (has_no_memory) {
-      data.flags |= FocusgroupFlags::kNoMemory;
+      Warn(
+          "Focusgroup attribute value 'block' is not valid for grid "
+          "focusgroups; use row-wrap/col-wrap or flow modifiers instead.");
     }
     return data;
   }
 
-  // At this point, we are necessarily in a linear focusgroup. Any grid
-  // focusgroup should have returned above.
-
+  // Linear focusgroup specific validation and flag setting.
   if (has_row_wrap) {
-    element->GetDocument().AddConsoleMessage(
-        MakeGarbageCollected<ConsoleMessage>(
-            mojom::blink::ConsoleMessageSource::kOther,
-            mojom::blink::ConsoleMessageLevel::kError,
-            "Focusgroup attribute value 'row-wrap' present, but has no effect "
-            "on linear focusgroups."));
+    Warn(
+        "Focusgroup attribute value 'row-wrap' is only valid for grid "
+        "focusgroups; use 'wrap' for linear focusgroups instead.");
   }
   if (has_col_wrap) {
-    element->GetDocument().AddConsoleMessage(
-        MakeGarbageCollected<ConsoleMessage>(
-            mojom::blink::ConsoleMessageSource::kOther,
-            mojom::blink::ConsoleMessageLevel::kError,
-            "Focusgroup attribute value 'col-wrap' present, but has no effect "
-            "on linear focusgroups."));
+    Warn(
+        "Focusgroup attribute value 'col-wrap' is only valid for grid "
+        "focusgroups; use 'wrap' for linear focusgroups instead.");
   }
   if (has_flow) {
-    element->GetDocument().AddConsoleMessage(
-        MakeGarbageCollected<ConsoleMessage>(
-            mojom::blink::ConsoleMessageSource::kOther,
-            mojom::blink::ConsoleMessageLevel::kError,
-            "Focusgroup attribute value 'flow' present, but has no effect on "
-            "linear focusgroups."));
+    Warn(
+        "Focusgroup attribute value 'flow' is only valid for grid "
+        "focusgroups.");
   }
   if (has_row_flow) {
-    element->GetDocument().AddConsoleMessage(
-        MakeGarbageCollected<ConsoleMessage>(
-            mojom::blink::ConsoleMessageSource::kOther,
-            mojom::blink::ConsoleMessageLevel::kError,
-            "Focusgroup attribute value 'row-flow' present, but has no effect "
-            "on linear focusgroups."));
+    Warn(
+        "Focusgroup attribute value 'row-flow' is only valid for grid "
+        "focusgroups.");
   }
   if (has_col_flow) {
-    element->GetDocument().AddConsoleMessage(
-        MakeGarbageCollected<ConsoleMessage>(
-            mojom::blink::ConsoleMessageSource::kOther,
-            mojom::blink::ConsoleMessageLevel::kError,
-            "Focusgroup attribute value 'col-flow' present, but has no effect "
-            "on linear focusgroups."));
+    Warn(
+        "Focusgroup attribute value 'col-flow' is only valid for grid "
+        "focusgroups.");
   }
-
-  // 4. Set the axis supported on that linear focusgroup.
-  if (has_inline) {
-    data.flags |= FocusgroupFlags::kInline;
-  }
-  if (has_block) {
-    data.flags |= FocusgroupFlags::kBlock;
+  if (has_inline && has_block) {
+    Warn(
+        "Focusgroup attribute values 'inline' and 'block' used together "
+        "are redundant (this is the default behavior for linear focusgroups) "
+        "and can be omitted.");
   }
 
   // When no axis is specified for linear focusgroups, it means that the
   // focusgroup should handle both.
   if (!has_inline && !has_block) {
     data.flags |= FocusgroupFlags::kInline | FocusgroupFlags::kBlock;
-  }
-
-  if (has_inline && has_block) {
-    element->GetDocument().AddConsoleMessage(MakeGarbageCollected<
-                                             ConsoleMessage>(
-        mojom::blink::ConsoleMessageSource::kOther,
-        mojom::blink::ConsoleMessageLevel::kWarning,
-        "'inline' and 'block' focusgroup attribute values used together "
-        "are redundant (this is the default behavior) and can be omitted."));
+  } else {
+    if (has_inline) {
+      data.flags |= FocusgroupFlags::kInline;
+    }
+    if (has_block) {
+      data.flags |= FocusgroupFlags::kBlock;
+    }
   }
 
   // 6. Determine in what axis a linear focusgroup should wrap. This needs to be
@@ -439,75 +449,41 @@
     }
   }
 
-  if (has_no_memory) {
-    data.flags |= FocusgroupFlags::kNoMemory;
-  }
   return data;
 }
 
 String FocusgroupDataToStringForTesting(const FocusgroupData& data) {
   StringBuilder builder;
-  builder.Append("FocusgroupData(");
-  switch (data.behavior) {
-    case FocusgroupBehavior::kToolbar:
-      builder.Append("Toolbar");
+  // Handle "no behavior" first.
+  if (data.behavior == FocusgroupBehavior::kNoBehavior) {
+    builder.Append("No behavior");
+    return builder.ToString();
+  }
+
+  for (const auto& behavior_mapping : kBehaviorMap) {
+    if (data.behavior == behavior_mapping.behavior) {
+      builder.Append(behavior_mapping.token);
       break;
-    case FocusgroupBehavior::kTablist:
-      builder.Append("Tablist");
-      break;
-    case FocusgroupBehavior::kRadiogroup:
-      builder.Append("Radiogroup");
-      break;
-    case FocusgroupBehavior::kListbox:
-      builder.Append("Listbox");
-      break;
-    case FocusgroupBehavior::kMenu:
-      builder.Append("Menu");
-      break;
-    case FocusgroupBehavior::kMenubar:
-      builder.Append("Menubar");
-      break;
-    case FocusgroupBehavior::kGrid:
-      builder.Append("Grid");
-      break;
-    case FocusgroupBehavior::kOptOut:
-      builder.Append("OptOut)");
-      return builder.ToString();
-    case FocusgroupBehavior::kNoBehavior:
-      builder.Append("None)");
-      return builder.ToString();
+    }
   }
 
   builder.Append(':');
   builder.Append(FocusgroupFlagsToStringForTesting(data.flags));
-  builder.Append(')');
   return builder.ToString();
 }
 
 String FocusgroupFlagsToStringForTesting(FocusgroupFlags flags) {
-  Vector<const char*> names;
-  names.ReserveInitialCapacity(9);
-  auto append_flag_name_if_set = [&](FocusgroupFlags flag, const char* name) {
-    if (flags & flag) {
-      names.push_back(name);
-    }
-  };
-
-  // Modifier flags only.
-  append_flag_name_if_set(FocusgroupFlags::kInline, "Inline");
-  append_flag_name_if_set(FocusgroupFlags::kBlock, "Block");
-  append_flag_name_if_set(FocusgroupFlags::kWrapInline, "WrapInline");
-  append_flag_name_if_set(FocusgroupFlags::kWrapBlock, "WrapBlock");
-  append_flag_name_if_set(FocusgroupFlags::kRowFlow, "RowFlow");
-  append_flag_name_if_set(FocusgroupFlags::kColFlow, "ColFlow");
-  append_flag_name_if_set(FocusgroupFlags::kNoMemory, "NoMemory");
   StringBuilder builder;
-  builder.Append("FocusgroupFlags(");
-  for (wtf_size_t i = 0; i < names.size(); ++i) {
-    if (i) {
-      builder.Append('|');
+  builder.Append('(');
+  for (const auto& modifier_mapping : kModifierMap) {
+    if (flags & modifier_mapping.flag) {
+      // Append '|' if this is not the first flag. (account for the opening
+      // paren).
+      if (builder.length() > 1) {
+        builder.Append('|');
+      }
+      builder.Append(modifier_mapping.token);
     }
-    builder.Append(names[i]);
   }
   builder.Append(')');
   return builder.ToString();
@@ -525,33 +501,17 @@
 }
 
 ax::mojom::blink::Role FocusgroupMinimumAriaRole(const FocusgroupData& data) {
-  // Return appropriate role based on behavior token.
-  if (data.behavior == FocusgroupBehavior::kToolbar) {
-    return ax::mojom::blink::Role::kToolbar;
+  // This function should not be called on non-focusgroups, including opted out
+  // elements.
+  CHECK(IsActualFocusgroup(data));
+  // Return appropriate role based on behavior token mapping.
+  for (const auto& behavior_mapping : kBehaviorMap) {
+    if (data.behavior == behavior_mapping.behavior) {
+      return behavior_mapping.aria_role;
+    }
   }
-  if (data.behavior == FocusgroupBehavior::kTablist) {
-    return ax::mojom::blink::Role::kTabList;
-  }
-  if (data.behavior == FocusgroupBehavior::kRadiogroup) {
-    return ax::mojom::blink::Role::kRadioGroup;
-  }
-  if (data.behavior == FocusgroupBehavior::kListbox) {
-    return ax::mojom::blink::Role::kListBox;
-  }
-  if (data.behavior == FocusgroupBehavior::kMenu) {
-    return ax::mojom::blink::Role::kMenu;
-  }
-  if (data.behavior == FocusgroupBehavior::kMenubar) {
-    return ax::mojom::blink::Role::kMenuBar;
-  }
-  if (data.behavior == FocusgroupBehavior::kGrid) {
-    return ax::mojom::blink::Role::kGrid;
-  }
-
-  // Default case should never be reached because this function should only be
-  // called with valid focusgroup flags (i.e. not kNone or kOptOut).
-  NOTREACHED() << "FocusgroupMinimumAriaRole called with invalid behavior "
-               << FocusgroupDataToStringForTesting(data);
+  NOTREACHED() << "Unmapped focusgroup behavior: "
+               << static_cast<int>(data.behavior);
 }
 
 }  // namespace blink::focusgroup
diff --git a/third_party/blink/renderer/core/dom/focusgroup_flags.h b/third_party/blink/renderer/core/dom/focusgroup_flags.h
index ebc29e2..60ad7d1 100644
--- a/third_party/blink/renderer/core/dom/focusgroup_flags.h
+++ b/third_party/blink/renderer/core/dom/focusgroup_flags.h
@@ -87,11 +87,14 @@
 struct FocusgroupData {
   FocusgroupBehavior behavior = FocusgroupBehavior::kNoBehavior;
   FocusgroupFlags flags = FocusgroupFlags::kNone;
+
+  bool operator==(const FocusgroupData& other) const = default;
+  bool operator!=(const FocusgroupData& other) const = default;
 };
 
 FocusgroupData FindNearestFocusgroupAncestorData(const Element* element);
-FocusgroupData ParseFocusgroup(const Element* element,
-                               const AtomicString& input);
+CORE_EXPORT FocusgroupData ParseFocusgroup(const Element* element,
+                                           const AtomicString& input);
 
 // Exported helper for tests and logging to obtain a string form.
 CORE_EXPORT String FocusgroupDataToStringForTesting(const FocusgroupData& data);
diff --git a/third_party/blink/renderer/core/dom/focusgroup_flags_test.cc b/third_party/blink/renderer/core/dom/focusgroup_flags_test.cc
new file mode 100644
index 0000000..9345922
--- /dev/null
+++ b/third_party/blink/renderer/core/dom/focusgroup_flags_test.cc
@@ -0,0 +1,181 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/dom/focusgroup_flags.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/html/html_div_element.h"
+#include "third_party/blink/renderer/core/html/html_table_element.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
+
+namespace blink::focusgroup {
+
+class FocusgroupFlagsTest : public SimTest {
+ protected:
+  void SetUp() override { SimTest::SetUp(); }
+
+  Vector<String>& RawConsoleMessages() { return ConsoleMessages(); }
+
+  void ClearConsoleMessages() { RawConsoleMessages().clear(); }
+
+  Vector<String> CopyConsoleMessages() { return RawConsoleMessages(); }
+};
+
+TEST_F(FocusgroupFlagsTest, EmptyAttributeGeneratesError) {
+  ScopedFocusgroupForTest focusgroup_scope(true);
+
+  auto* element = MakeGarbageCollected<HTMLDivElement>(GetDocument());
+  GetDocument().body()->appendChild(element);
+
+  ClearConsoleMessages();
+  FocusgroupData result = ParseFocusgroup(element, AtomicString(""));
+
+  EXPECT_EQ(result.behavior, FocusgroupBehavior::kNoBehavior);
+  EXPECT_EQ(result.flags, FocusgroupFlags::kNone);
+
+  auto messages = CopyConsoleMessages();
+  ASSERT_EQ(messages.size(), 1u);
+  EXPECT_TRUE(messages[0].Contains("focusgroup requires a behavior token"));
+  EXPECT_TRUE(messages[0].Contains("first value"));
+}
+
+TEST_F(FocusgroupFlagsTest, InvalidFirstTokenGeneratesError) {
+  ScopedFocusgroupForTest focusgroup_scope(true);
+
+  auto* element = MakeGarbageCollected<HTMLDivElement>(GetDocument());
+  GetDocument().body()->appendChild(element);
+
+  ClearConsoleMessages();
+  FocusgroupData result = ParseFocusgroup(element, AtomicString("invalid"));
+
+  EXPECT_EQ(result.behavior, FocusgroupBehavior::kNoBehavior);
+  EXPECT_EQ(result.flags, FocusgroupFlags::kNone);
+
+  auto messages = CopyConsoleMessages();
+  ASSERT_EQ(messages.size(), 1u);
+  EXPECT_TRUE(messages[0].Contains("focusgroup requires a behavior token"));
+  EXPECT_TRUE(messages[0].Contains("Found: 'invalid'"));
+}
+
+TEST_F(FocusgroupFlagsTest, MultipleBehaviorTokensGenerateWarning) {
+  ScopedFocusgroupForTest focusgroup_scope(true);
+
+  auto* element = MakeGarbageCollected<HTMLDivElement>(GetDocument());
+  GetDocument().body()->appendChild(element);
+
+  ClearConsoleMessages();
+  FocusgroupData result =
+      ParseFocusgroup(element, AtomicString("toolbar tablist"));
+
+  // Current implementation: toolbar is parsed as behavior, tablist as invalid
+  // modifier
+  EXPECT_EQ(result.behavior, FocusgroupBehavior::kToolbar);
+  EXPECT_EQ(result.flags, (FocusgroupFlags::kInline | FocusgroupFlags::kBlock));
+
+  auto messages = CopyConsoleMessages();
+  ASSERT_GE(messages.size(), 1u);
+  EXPECT_TRUE(messages[0].Contains("Unrecognized focusgroup attribute values"));
+  EXPECT_TRUE(messages[0].Contains("tablist"));
+}
+
+TEST_F(FocusgroupFlagsTest, UnknownTokenGeneratesWarning) {
+  ScopedFocusgroupForTest focusgroup_scope(true);
+
+  auto* element = MakeGarbageCollected<HTMLDivElement>(GetDocument());
+  GetDocument().body()->appendChild(element);
+
+  ClearConsoleMessages();
+  FocusgroupData result =
+      ParseFocusgroup(element, AtomicString("toolbar unknown"));
+  // Default axes (inline|block) are added for linear focusgroups when not
+  // specified.
+  EXPECT_EQ(result.behavior, FocusgroupBehavior::kToolbar);
+  EXPECT_EQ(result.flags, (FocusgroupFlags::kInline | FocusgroupFlags::kBlock));
+  auto messages = CopyConsoleMessages();
+  ASSERT_GE(messages.size(), 1u);
+  EXPECT_TRUE(messages[0].Contains("Unrecognized focusgroup attribute values"));
+  EXPECT_TRUE(messages[0].Contains("unknown"));
+  EXPECT_TRUE(messages[0].Contains("Valid tokens are"));
+}
+
+TEST_F(FocusgroupFlagsTest, NoneWithOtherTokensGeneratesWarning) {
+  ScopedFocusgroupForTest focusgroup_scope(true);
+
+  auto* element = MakeGarbageCollected<HTMLDivElement>(GetDocument());
+  GetDocument().body()->appendChild(element);
+
+  ClearConsoleMessages();
+  FocusgroupData result = ParseFocusgroup(element, AtomicString("none inline"));
+
+  EXPECT_EQ(result.behavior, FocusgroupBehavior::kOptOut);
+  EXPECT_EQ(result.flags, FocusgroupFlags::kNone);
+
+  auto messages = CopyConsoleMessages();
+  ASSERT_EQ(messages.size(), 1u);
+  EXPECT_TRUE(messages[0].Contains("disables focusgroup behavior"));
+  EXPECT_TRUE(messages[0].Contains("all other tokens are ignored"));
+}
+
+TEST_F(FocusgroupFlagsTest, RedundantInlineBlockGeneratesWarning) {
+  ScopedFocusgroupForTest focusgroup_scope(true);
+
+  auto* element = MakeGarbageCollected<HTMLDivElement>(GetDocument());
+  GetDocument().body()->appendChild(element);
+
+  ClearConsoleMessages();
+  FocusgroupData result =
+      ParseFocusgroup(element, AtomicString("toolbar inline block"));
+
+  EXPECT_EQ(result.behavior, FocusgroupBehavior::kToolbar);
+  EXPECT_EQ(result.flags, FocusgroupFlags::kInline | FocusgroupFlags::kBlock);
+  auto messages = CopyConsoleMessages();
+  ASSERT_GE(messages.size(), 1u);
+  EXPECT_TRUE(messages[0].Contains("redundant"));
+  EXPECT_TRUE(messages[0].Contains("default behavior for linear focusgroups"));
+}
+
+TEST_F(FocusgroupFlagsTest, InvalidAxisForGridGeneratesError) {
+  ScopedFocusgroupForTest focusgroup_scope(true);
+  ScopedFocusgroupGridForTest grid_scope(true);
+
+  auto* element = MakeGarbageCollected<HTMLTableElement>(GetDocument());
+  GetDocument().body()->appendChild(element);
+
+  ClearConsoleMessages();
+  FocusgroupData result = ParseFocusgroup(element, AtomicString("grid inline"));
+
+  EXPECT_EQ(result.behavior, FocusgroupBehavior::kGrid);
+  EXPECT_EQ(result.flags, FocusgroupFlags::kNone);
+
+  auto messages = CopyConsoleMessages();
+  ASSERT_EQ(messages.size(), 1u);
+  EXPECT_TRUE(messages[0].Contains("not valid for grid focusgroups"));
+  EXPECT_TRUE(messages[0].Contains("row-wrap/col-wrap or flow modifiers"));
+}
+
+TEST_F(FocusgroupFlagsTest, GridTokensOnLinearGenerateError) {
+  ScopedFocusgroupForTest focusgroup_scope(true);
+
+  auto* element = MakeGarbageCollected<HTMLDivElement>(GetDocument());
+  GetDocument().body()->appendChild(element);
+
+  ClearConsoleMessages();
+  FocusgroupData result =
+      ParseFocusgroup(element, AtomicString("toolbar row-wrap"));
+
+  // Linear focusgroup adds default axes; row-wrap ignored with error.
+  EXPECT_EQ(result.behavior, FocusgroupBehavior::kToolbar);
+  EXPECT_EQ(result.flags, (FocusgroupFlags::kInline | FocusgroupFlags::kBlock));
+  auto messages = CopyConsoleMessages();
+  ASSERT_GE(messages.size(), 1u);
+  EXPECT_TRUE(messages[0].Contains("only valid for grid focusgroups"));
+  EXPECT_TRUE(messages[0].Contains("use 'wrap' for linear focusgroups"));
+}
+
+}  // namespace blink::focusgroup
diff --git a/third_party/blink/renderer/core/editing/frame_selection.cc b/third_party/blink/renderer/core/editing/frame_selection.cc
index bff538d2..43f45710 100644
--- a/third_party/blink/renderer/core/editing/frame_selection.cc
+++ b/third_party/blink/renderer/core/editing/frame_selection.cc
@@ -1212,6 +1212,12 @@
                  .Build());
 }
 
+bool FrameSelection::HasVisibleText() const {
+  const EphemeralRange range =
+      ComputeVisibleSelectionInDOMTree().ToNormalizedEphemeralRange();
+  return !PlainText(range, TextIteratorBehavior()).empty();
+}
+
 PhysicalRect FrameSelection::AbsoluteUnclippedBounds() const {
   LocalFrameView* view = frame_->View();
   LayoutView* layout_view = frame_->ContentLayoutObject();
diff --git a/third_party/blink/renderer/core/editing/frame_selection.h b/third_party/blink/renderer/core/editing/frame_selection.h
index 53fa6af..4377b26 100644
--- a/third_party/blink/renderer/core/editing/frame_selection.h
+++ b/third_party/blink/renderer/core/editing/frame_selection.h
@@ -291,6 +291,9 @@
   String SelectedText(const TextIteratorBehavior&) const;
   String SelectedText() const;
   String SelectedTextForClipboard() const;
+  // Returns true if the current selection corresponds to a non-empty visible
+  // text range within this frame.
+  bool HasVisibleText() const;
 
   // This returns last layouted selection bounds of LayoutSelection rather than
   // SelectionEditor keeps.
diff --git a/third_party/blink/renderer/core/editing/frame_selection_test.cc b/third_party/blink/renderer/core/editing/frame_selection_test.cc
index 3d77140..7f3d77a 100644
--- a/third_party/blink/renderer/core/editing/frame_selection_test.cc
+++ b/third_party/blink/renderer/core/editing/frame_selection_test.cc
@@ -1457,6 +1457,54 @@
   EXPECT_EQ("foo\nbar\nbaz", Selection().SelectedTextForClipboard());
 }
 
+TEST_F(FrameSelectionTest, HasVisibleText) {
+  Selection().SetSelection(
+      SetSelectionTextToBody("<div contenteditable>^foo|</div>"),
+      SetSelectionOptions());
+  EXPECT_FALSE(VisibleSelectionInDOMTree().IsNone());
+  EXPECT_TRUE(Selection().HasVisibleText());
+  EXPECT_EQ_SELECTED_TEXT("foo");
+}
+
+TEST_F(FrameSelectionTest, HasVisibleTextWithInput) {
+  // File
+  Selection().SetSelection(SetSelectionTextToBody("^<input type=file>|"),
+                           SetSelectionOptions());
+  EXPECT_FALSE(VisibleSelectionInDOMTree().IsNone());
+  EXPECT_FALSE(Selection().HasVisibleText());
+  // Checkbox
+  Selection().SetSelection(SetSelectionTextToBody("^<input type=checkbox>|"),
+                           SetSelectionOptions());
+  EXPECT_FALSE(VisibleSelectionInDOMTree().IsNone());
+  EXPECT_FALSE(Selection().HasVisibleText());
+  // Radio
+  Selection().SetSelection(SetSelectionTextToBody("^<input type=radio>|"),
+                           SetSelectionOptions());
+  EXPECT_FALSE(VisibleSelectionInDOMTree().IsNone());
+  EXPECT_FALSE(Selection().HasVisibleText());
+  // Date
+  Selection().SetSelection(SetSelectionTextToBody("^<input type=date>|"),
+                           SetSelectionOptions());
+  EXPECT_FALSE(VisibleSelectionInDOMTree().IsNone());
+  EXPECT_FALSE(Selection().HasVisibleText());
+}
+
+TEST_F(FrameSelectionTest, HasVisibleTextInShadowTree) {
+  SetBodyContent("<p id='host'></p>");
+  ShadowRoot* shadow_root = SetShadowContent("foo", "host");
+  EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone());
+
+  Node* text_node = shadow_root->firstChild();
+  Selection().SetSelection(
+      SelectionInDOMTree::Builder()
+          .SetBaseAndExtent(Position(text_node, 0), Position(text_node, 3))
+          .Build(),
+      SetSelectionOptions());
+  EXPECT_FALSE(Selection().GetSelectionInDOMTree().IsNone());
+  EXPECT_TRUE(Selection().HasVisibleText());
+  EXPECT_EQ_SELECTED_TEXT("foo");
+}
+
 // For https://crbug.com/1177295
 TEST_F(FrameSelectionTest, PositionDisconnectedInFlatTree) {
   SetBodyContent("<div id=host>x</div>y");
diff --git a/third_party/blink/renderer/core/fragment_directive/text_fragment_handler.cc b/third_party/blink/renderer/core/fragment_directive/text_fragment_handler.cc
index f5a89a6..4d535572 100644
--- a/third_party/blink/renderer/core/fragment_directive/text_fragment_handler.cc
+++ b/third_party/blink/renderer/core/fragment_directive/text_fragment_handler.cc
@@ -253,8 +253,16 @@
     return;
   }
 
-  if (frame->Selection().SelectedText().empty())
-    return;
+  if (RuntimeEnabledFeatures::
+          NonEmptyVisibleTextSelectionForTextFragmentEnabled()) {
+    if (!frame->Selection().HasVisibleText()) {
+      return;
+    }
+  } else {
+    if (frame->Selection().SelectedText().empty()) {
+      return;
+    }
+  }
 
   if (!frame->GetTextFragmentHandler())
     frame->CreateTextFragmentHandler();
diff --git a/third_party/blink/renderer/core/fragment_directive/text_fragment_handler.h b/third_party/blink/renderer/core/fragment_directive/text_fragment_handler.h
index 4e66798..71a2109 100644
--- a/third_party/blink/renderer/core/fragment_directive/text_fragment_handler.h
+++ b/third_party/blink/renderer/core/fragment_directive/text_fragment_handler.h
@@ -70,6 +70,7 @@
   FRIEND_TEST_ALL_PREFIXES(TextFragmentHandlerTest,
                            IfGeneratorResetShouldRecordCorrectError);
   FRIEND_TEST_ALL_PREFIXES(TextFragmentHandlerTest, NotGenerated);
+  FRIEND_TEST_ALL_PREFIXES(TextFragmentHandlerTest, NotGeneratedWithFileInput);
   // Returns whether preemptive generation should run for the given frame.
   static bool ShouldPreemptivelyGenerateFor(LocalFrame* frame);
 
diff --git a/third_party/blink/renderer/core/fragment_directive/text_fragment_handler_test.cc b/third_party/blink/renderer/core/fragment_directive/text_fragment_handler_test.cc
index 527f93a5..45b2840b 100644
--- a/third_party/blink/renderer/core/fragment_directive/text_fragment_handler_test.cc
+++ b/third_party/blink/renderer/core/fragment_directive/text_fragment_handler_test.cc
@@ -1057,6 +1057,25 @@
   EXPECT_EQ(expected_error, GetTextFragmentHandler().error_);
 }
 
+// https://crbug.com/447973114
+TEST_F(TextFragmentHandlerTest, NotGeneratedWithFileInput) {
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <input type="file">
+  )HTML");
+  GetDocument().GetFrame()->Selection().SelectAll();
+  // This shouldn't crash.
+  TextFragmentHandler::OpenedContextMenuOverSelection(GetDocument().GetFrame());
+
+  EXPECT_EQ(RequestSelector(), "");
+
+  shared_highlighting::LinkGenerationError expected_error =
+      shared_highlighting::LinkGenerationError::kNotGenerated;
+  EXPECT_EQ(expected_error, GetTextFragmentHandler().error_);
+}
+
 TEST_F(TextFragmentHandlerTest, InvalidateOverflowOnRemoval) {
   SimRequest request(
       "https://example.com/"
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 fe4178a..92ab923 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
@@ -69,7 +69,6 @@
 
 namespace blink {
 
-class CanvasResourceProvider;
 class CanvasElementHitTestRegion;
 class ComputedStyle;
 class Document;
@@ -280,7 +279,6 @@
   virtual void LangAttributeChanged() {}
   virtual String GetIdFromControl(const Element* element) { return String(); }
   virtual int LayerCount() const { return 0; }
-  virtual bool IsCanvas2DResourceProviderValid() { NOTREACHED(); }
 
   // If the ResourceProvider currently exists, replaces it with a newly-created
   // CanvasResourceProvider.
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 4eb6f77..7d3cc0d 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
@@ -788,24 +788,18 @@
   // checks whether the `desynchronized` attribute is set on the context, but
   // only WebGL and Canvas2D have specific flows for low latency (for other
   // context types, setting the attribute is a no-op).
-  if (LowLatencyEnabled() && (IsWebGL() || IsRenderingContext2D())) {
-    bool resource_is_paintable =
-        IsRenderingContext2D()
-            ? RenderingContext()->IsCanvas2DResourceProviderValid()
-            : true;
-    if (frame_dispatcher_ && !dirty_rect_.IsEmpty() && resource_is_paintable) {
-      if (scoped_refptr<CanvasResource> canvas_resource =
-              context_->PaintRenderingResultsToResource(kBackBuffer, reason)) {
-        const gfx::Rect src_rect(Size());
-        dirty_rect_.Intersect(src_rect);
-        const gfx::Rect int_dirty = dirty_rect_;
-        const SkIRect damage_rect =
-            SkIRect::MakeXYWH(int_dirty.x(), int_dirty.y(), int_dirty.width(),
-                              int_dirty.height());
-        frame_dispatcher_->DispatchFrame(std::move(canvas_resource),
-                                         damage_rect, IsOpaque());
-        dirty_rect_ = gfx::Rect();
-      }
+  if (LowLatencyEnabled() && (IsWebGL() || IsRenderingContext2D()) &&
+      frame_dispatcher_ && !dirty_rect_.IsEmpty()) {
+    if (scoped_refptr<CanvasResource> canvas_resource =
+            context_->PaintRenderingResultsToResource(kBackBuffer, reason)) {
+      const gfx::Rect src_rect(Size());
+      dirty_rect_.Intersect(src_rect);
+      const gfx::Rect int_dirty = dirty_rect_;
+      const SkIRect damage_rect = SkIRect::MakeXYWH(
+          int_dirty.x(), int_dirty.y(), int_dirty.width(), int_dirty.height());
+      frame_dispatcher_->DispatchFrame(std::move(canvas_resource), damage_rect,
+                                       IsOpaque());
+      dirty_rect_ = gfx::Rect();
     }
   }
 
diff --git a/third_party/blink/renderer/core/html/forms/file_input_type_test.cc b/third_party/blink/renderer/core/html/forms/file_input_type_test.cc
index 43c232f0..f53e13a 100644
--- a/third_party/blink/renderer/core/html/forms/file_input_type_test.cc
+++ b/third_party/blink/renderer/core/html/forms/file_input_type_test.cc
@@ -61,7 +61,9 @@
   // Non-native file.
   KURL url("filesystem:http://example.com/isolated/hash/non-native-file");
   files.push_back(CreateFileChooserFileInfoFileSystem(
-      url, base::Time::FromMillisecondsSinceUnixEpoch(1.0 * kMsPerDay + 3),
+      url,
+      base::Time::FromMillisecondsSinceUnixEpoch(
+          base::Time::kMillisecondsPerDay + 3),
       64));
 
   ScopedNullExecutionContext execution_context;
@@ -78,7 +80,7 @@
   EXPECT_EQ("non-native-file", list->item(1)->name());
   EXPECT_EQ(url, list->item(1)->FileSystemURL());
   EXPECT_EQ(64u, list->item(1)->size());
-  EXPECT_EQ(1.0 * kMsPerDay + 3, list->item(1)->lastModified());
+  EXPECT_EQ(base::Time::kMillisecondsPerDay + 3, list->item(1)->lastModified());
 }
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc
index 5ca9e74d..d794303 100644
--- a/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc
@@ -1983,9 +1983,10 @@
   //
   // See third_party/blink/renderer/core/layout/gap/README.md for more.
   void BuildMainGaps(const GridLayoutData& layout_data) {
+    const auto& rows = layout_data.Rows();
     const Vector<LayoutUnit> row_tracks =
-        LayoutGrid::ComputeExpandedPositions(layout_data.Rows());
-    row_gutter_size_ = layout_data.Rows().GutterSize();
+        LayoutGrid::ComputeExpandedPositions(rows);
+    row_gutter_size_ = rows.GutterSize();
     wtf_size_t row_track_count = row_tracks.size();
 
     // CSS Gaps[1] defines an intersection point to exist in the center of gaps.
@@ -1995,7 +1996,15 @@
     // range [1, `row_track_count` - 1).
     //
     // [1] https://www.w3.org/TR/css-gaps-1/#gap-intersection-point
+    // TODO(samomekarajr): This is currently O(nlogn) but can be optimized to
+    // be O(n) if we find the first range index and increment it as we go.
     for (wtf_size_t i = 1; i < row_track_count - 1; ++i) {
+      const wtf_size_t range_index = rows.RangeIndexFromGridLine(i);
+      if (rows.RangeProperties(range_index)
+              .HasProperty(TrackSpanProperties::kIsCollapsed)) {
+        continue;
+      }
+
       LayoutUnit row_midpoint =
           LayoutUnit(row_tracks[i] - (row_gutter_size_ / 2.0f));
       MainGap main_gap = MainGap(row_midpoint);
@@ -2007,9 +2016,10 @@
   }
 
   void BuildCrossGaps(const GridLayoutData& layout_data) {
+    const auto& columns = layout_data.Columns();
     const Vector<LayoutUnit> col_tracks =
-        LayoutGrid::ComputeExpandedPositions(layout_data.Columns());
-    col_gutter_size_ = layout_data.Columns().GutterSize();
+        LayoutGrid::ComputeExpandedPositions(columns);
+    col_gutter_size_ = columns.GutterSize();
     wtf_size_t col_track_count = col_tracks.size();
 
     // CSS Gaps defines an intersection point to exist in the center
@@ -2018,7 +2028,14 @@
     // track, and the last gap ends at the second-to-last track. So gaps are
     // defined in the track range [1, `col_track_count` - 1).
     // See: https://www.w3.org/TR/css-gaps-1/#gap-intersection-point
+    // TODO(samomekarajr): This is currently O(nlogn) but can be optimized to
+    // be O(n) if we find the first range index and increment it as we go.
     for (wtf_size_t i = 1; i < col_track_count - 1; ++i) {
+      const wtf_size_t range_index = columns.RangeIndexFromGridLine(i);
+      if (columns.RangeProperties(range_index)
+              .HasProperty(TrackSpanProperties::kIsCollapsed)) {
+        continue;
+      }
       LayoutUnit col_midpoint =
           LayoutUnit(col_tracks[i] - (col_gutter_size_ / 2.0f));
       LogicalOffset cross_gap_offset =
@@ -2927,12 +2944,16 @@
       const LayoutUnit row_gap_start_offset =
           row_gap_midpoint - half_row_gap_size;
       // If the gap start is beyond the fragmentainer space, this is the first
-      // gap we know doesn't fit in this fragmentainer, so get the set idx for
-      // the previous gap since that will be the gap we need to consider for
-      // suppression.
-      if (row_gap_start_offset > fragmentainer_space &&
-          fragment_main_gaps.size() > 0) {
-        current_processed_gap_set_idx = (*track_idx_to_set_idx)[gap_index - 1];
+      // gap we know doesn't fit in this fragmentainer, so we should break.
+      if (row_gap_start_offset > fragmentainer_space) {
+        // If we have placed gaps in this fragment, we need to check if the last
+        // placed gap needs to be suppressed. Hence, we get the set index for
+        // the previous gap since that will be the gap to consider for
+        // suppression.
+        if (fragment_main_gaps.size() > 0) {
+          current_processed_gap_set_idx =
+              (*track_idx_to_set_idx)[gap_index - 1];
+        }
         break;
       }
 
diff --git a/third_party/blink/renderer/core/loader/render_blocking_resource_manager_test.cc b/third_party/blink/renderer/core/loader/render_blocking_resource_manager_test.cc
index 997a8ec6..a567705 100644
--- a/third_party/blink/renderer/core/loader/render_blocking_resource_manager_test.cc
+++ b/third_party/blink/renderer/core/loader/render_blocking_resource_manager_test.cc
@@ -636,6 +636,81 @@
   font_resource.Complete();
 }
 
+TEST_F(RenderBlockingResourceManagerTest, PausedPageBlocksFontLoading) {
+  SimRequest main_resource("https://example.com", "text/html");
+  SimSubresourceRequest font_resource("https://example.com/font.woff2",
+                                      "font/woff2");
+  LoadURL("https://example.com");
+  main_resource.Complete(R"HTML(
+    <!doctype html>
+    <style>
+      @font-face {
+        font-family: custom-font;
+        src: url(https://example.com/font.woff2) format("woff2");
+      }
+      #target {
+        font-size: 10px;
+        position:relative;
+      }
+      @media print {
+        #target {
+            font: 25px/1 custom-font, monospace;
+        }
+      }
+    </style>
+    <span id=target style="">0123456789</span>
+  )HTML");
+
+  auto expected_web_font_width = 250;
+
+  Compositor().BeginFrame();
+  auto original_width = GetTarget()->OffsetWidth();
+  EXPECT_GT(expected_web_font_width, original_width);
+  EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
+
+  {
+    // The "custom-font" has not loaded yet.
+    // Print and apply "font: 25px/1 custom-font, monospace" to #target.
+    GetDocument().GetFrame()->StartPrinting(
+        WebPrintParams(gfx::SizeF(300, 400)));
+
+    Compositor().BeginFrame();
+    auto fallback_font_width = GetTarget()->OffsetWidth();
+    // The font size is changed from 10px to 25px.
+    EXPECT_GT(fallback_font_width, original_width);
+    // The web font has not applied yet.
+    EXPECT_GT(expected_web_font_width, fallback_font_width);
+    // The font won't load until the page is resumed, it should render with the
+    // fallback font to avoid invisible text.
+    EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
+    GetDocument().GetFrame()->EndPrinting();
+  }
+
+  Compositor().BeginFrame();
+  // The font size is changed back to 10px.
+  EXPECT_EQ(original_width, GetTarget()->OffsetWidth());
+  EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
+
+  // Simulate the font resource being fully loaded after the page resumes.
+  font_resource.Complete(ReadAhemWoff2());
+  Compositor().BeginFrame();
+  EXPECT_EQ(original_width, GetTarget()->OffsetWidth());
+  EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
+
+  {
+    // The "custom-font" has loaded now.
+    // Print and apply again "font: 25px/1 custom-font, monospace" to #target.
+    GetDocument().GetFrame()->StartPrinting(
+        WebPrintParams(gfx::SizeF(300, 400)));
+
+    Compositor().BeginFrame();
+    // Now that the web font has loaded, it should be used.
+    EXPECT_EQ(expected_web_font_width, GetTarget()->OffsetWidth());
+    EXPECT_FALSE(GetTargetFont().ShouldSkipDrawing());
+    GetDocument().GetFrame()->EndPrinting();
+  }
+}
+
 class RenderBlockingFontTest : public RenderBlockingResourceManagerTest {
  public:
   void SetUp() override {
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
index 43bba8b6..ae9f99c 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
@@ -29,7 +29,6 @@
 namespace blink {
 
 class CanvasContextCreationAttributesCore;
-class CanvasResourceProvider;
 class ImageBitmap;
 class ImageEncodeOptions;
 class
diff --git a/third_party/blink/renderer/core/page/context_menu_controller_test.cc b/third_party/blink/renderer/core/page/context_menu_controller_test.cc
index c50fcf4..2299984 100644
--- a/third_party/blink/renderer/core/page/context_menu_controller_test.cc
+++ b/third_party/blink/renderer/core/page/context_menu_controller_test.cc
@@ -2255,6 +2255,18 @@
   EXPECT_EQ(context_menu_data.selected_text, "A test_all B");
 }
 
+// http://crbug.com/447973114
+TEST_F(ContextMenuControllerTest, FileInputSelectAllShowsContextMenuNoCrash) {
+  Document* document = GetDocument();
+  document->documentElement()->SetInnerHTMLWithoutTrustedTypes(
+      "<input type=file id=test>");
+  document->UpdateStyleAndLayout(DocumentUpdateReason::kTest);
+  document->GetFrame()->Selection().SelectAll();
+  Element* element = document->getElementById(AtomicString("test"));
+  // Passed without crashing.
+  EXPECT_TRUE(ShowContextMenuForElement(element, kMenuSourceMouse));
+}
+
 class ContextMenuControllerRemoteParentFrameTest : public testing::Test {
  public:
   ContextMenuControllerRemoteParentFrameTest() = default;
diff --git a/third_party/blink/renderer/core/page/focus_controller.cc b/third_party/blink/renderer/core/page/focus_controller.cc
index 782a28ae..778043d6 100644
--- a/third_party/blink/renderer/core/page/focus_controller.cc
+++ b/third_party/blink/renderer/core/page/focus_controller.cc
@@ -133,10 +133,6 @@
                           ScrollMarkerGroup::ScrollMarkerMode::kLinks);
 }
 
-bool IsScrollerInTabsMode(const Element& scroller) {
-  return IsScrollerInMode(scroller, ScrollMarkerGroup::ScrollMarkerMode::kTabs);
-}
-
 bool IsScrollMarkerFromScrollerInTabsMode(const Element& maybe_scroll_marker) {
   auto* scroll_marker =
       DynamicTo<ScrollMarkerPseudoElement>(maybe_scroll_marker);
@@ -288,20 +284,13 @@
   }
   // In the `tabs` mode, the ::scroll-marker pseudo-element is a focus
   // navigation scope owner for its associated originating element. This means
-  // that the backwards tab focus moves from the content to the scroll marker,
-  // but for carousel we want to go: The ultimate originating element of the
-  // ::scroll-marker,
-  // ::scroll-buttons, ::scroll-marker.
-  // Here it would be equal to finding the rightmost carousel pseudo-element, as
-  // it would be either scroll button or active ::scroll-marker.
+  // that the backwards tab focus moves from the content to the scroll marker.
   if (RuntimeEnabledFeatures::CSSScrollMarkerGroupModesEnabled()) {
     if (auto* scroll_marker = DynamicTo<ScrollMarkerPseudoElement>(
             current.GetPseudoElement(kPseudoIdScrollMarker))) {
-      if (scroll_marker->IsSelected()) {
-        Element* scroller = scroll_marker->ScrollMarkerGroup()->parentElement();
-        if (IsScrollerInTabsMode(*scroller)) {
-          return GetPrevInCarouselOrder(*scroller, kPseudoIdNone);
-        }
+      if (scroll_marker->IsSelected() &&
+          IsScrollMarkerFromScrollerInTabsMode(*scroll_marker)) {
+        return scroll_marker;
       }
     }
   }
@@ -1044,6 +1033,11 @@
   return IsReadingFlowScopeOwner(&element) && element.IsKeyboardFocusableSlow();
 }
 
+inline bool IsKeyboardFocusableScrollMarkerOwner(const Element& element) {
+  return IsScrollMarkerFromScrollerInTabsMode(element) &&
+         element.IsKeyboardFocusableSlow();
+}
+
 inline bool IsKeyboardFocusableShadowHost(const Element& element) {
   return IsShadowHostWithoutCustomFocusLogic(element) &&
          (element.IsKeyboardFocusableSlow() ||
@@ -1276,6 +1270,20 @@
       return found;
     }
 
+    if (IsKeyboardFocusableScrollMarkerOwner(*found) &&
+        RuntimeEnabledFeatures::CSSScrollMarkerGroupModesEnabled() &&
+        found != scope.Owner()) {
+      ScopedFocusNavigation inner_scope =
+          ScopedFocusNavigation::OwnedByScrollMarker(
+              const_cast<Element&>(*found), owner_map);
+      Element* found_in_inner_focus_scope =
+          FindFocusableElementRecursivelyBackward(inner_scope, owner_map);
+      if (found_in_inner_focus_scope) {
+        return found_in_inner_focus_scope;
+      }
+      return found;
+    }
+
     // Now |found| is on a focusable reading flow owner. Find inside
     // container backwards. If any focusable element is found, return it,
     // otherwise return the container itself.
diff --git a/third_party/blink/renderer/core/page/focus_controller_test.cc b/third_party/blink/renderer/core/page/focus_controller_test.cc
index 80a9dbb..dcf74ce7 100644
--- a/third_party/blink/renderer/core/page/focus_controller_test.cc
+++ b/third_party/blink/renderer/core/page/focus_controller_test.cc
@@ -1185,46 +1185,29 @@
   Element* after_first_scroll_marker =
       after_first_child->GetPseudoElement(kPseudoIdScrollMarker);
 
-  std::array<Element*, 15> forward_order = {pre_input,
-                                            before_first_scroll_marker,
-                                            before_first_child,
-                                            before_block_start_button,
-                                            before_inline_start_button,
-                                            before_inline_end_button,
-                                            before_block_end_button,
-                                            before_scroller,
-                                            after_first_scroll_marker,
-                                            after_block_start_button,
-                                            after_inline_start_button,
-                                            after_inline_end_button,
-                                            after_block_end_button,
-                                            after_scroller,
-                                            post_input};
+  std::array<Element*, 15> order = {pre_input,
+                                    before_first_scroll_marker,
+                                    before_first_child,
+                                    before_block_start_button,
+                                    before_inline_start_button,
+                                    before_inline_end_button,
+                                    before_block_end_button,
+                                    before_scroller,
+                                    after_first_scroll_marker,
+                                    after_block_start_button,
+                                    after_inline_start_button,
+                                    after_inline_end_button,
+                                    after_block_end_button,
+                                    after_scroller,
+                                    post_input};
 
-  std::array<Element*, 14> backward_order = {pre_input,
-                                             before_first_scroll_marker,
-                                             before_block_start_button,
-                                             before_inline_start_button,
-                                             before_inline_end_button,
-                                             before_block_end_button,
-                                             before_scroller,
-                                             after_first_scroll_marker,
-                                             after_block_start_button,
-                                             after_inline_start_button,
-                                             after_inline_end_button,
-                                             after_block_end_button,
-                                             after_scroller,
-                                             post_input};
-
-  for (std::size_t i = 0u; i < forward_order.size() - 1; ++i) {
-    EXPECT_EQ(forward_order[i + 1],
-              FindFocusableElementAfter(*forward_order[i],
-                                        mojom::blink::FocusType::kForward));
+  for (std::size_t i = 0u; i < order.size() - 1; ++i) {
+    EXPECT_EQ(order[i + 1], FindFocusableElementAfter(
+                                *order[i], mojom::blink::FocusType::kForward));
   }
-  for (std::size_t i = 0u; i < backward_order.size() - 1; ++i) {
-    EXPECT_EQ(backward_order[i],
-              FindFocusableElementAfter(*backward_order[i + 1],
-                                        mojom::blink::FocusType::kBackward));
+  for (std::size_t i = 0u; i < order.size() - 1; ++i) {
+    EXPECT_EQ(order[i], FindFocusableElementAfter(
+                            *order[i + 1], mojom::blink::FocusType::kBackward));
   }
 
   GetFocusController().SetActive(true);
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 4ad95ce3..0364108 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
@@ -166,6 +166,7 @@
   V8GPUTextureFormat getTextureFormat() const;
 
   virtual bool CanCreateCanvas2dResourceProvider() = 0;
+  virtual bool IsCanvas2DResourceProviderValid() { NOTREACHED(); }
   virtual CanvasResourceProvider* GetOrCreateCanvas2DResourceProvider() = 0;
 
   String lang() const;
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 662aa59..3b235e63 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
@@ -20,9 +20,6 @@
 
 namespace blink {
 
-BASE_FEATURE(kRTCAlignReceivedEncodedVideoTransforms,
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 RtpReceiverState::RtpReceiverState(
     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> signaling_task_runner,
@@ -162,10 +159,7 @@
       CHECK(webrtc_receiver_->media_type() == webrtc::MediaType::VIDEO);
       encoded_video_transformer_ =
           std::make_unique<RTCEncodedVideoStreamTransformer>(
-              main_task_runner_, base::FeatureList::IsEnabled(
-                                     kRTCAlignReceivedEncodedVideoTransforms)
-                                     ? std::move(decode_metronome)
-                                     : nullptr);
+              main_task_runner_, std::move(decode_metronome));
       webrtc_receiver_->SetFrameTransformer(
           encoded_video_transformer_->Delegate());
     }
diff --git a/third_party/blink/renderer/platform/fonts/shaping/caching_word_shape_iterator.cc b/third_party/blink/renderer/platform/fonts/shaping/caching_word_shape_iterator.cc
index cf2186a..caa5024 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/caching_word_shape_iterator.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/caching_word_shape_iterator.cc
@@ -21,7 +21,6 @@
   if (!shape_result)
     return nullptr;
 
-  shape_result->SetDeprecatedInkBounds(shape_result->ComputeInkBounds());
   if (cache_entry)
     *cache_entry = shape_result;
 
@@ -35,32 +34,7 @@
     return result;
   }
 
-  ShapeResult* spacing_result = result->ApplySpacingToCopy(spacing_, word_run);
-  gfx::RectF ink_bounds = spacing_result->ComputeInkBounds();
-  DCHECK_GE(ink_bounds.width(), 0);
-
-  // Return bounds as is because glyph bounding box is in logical space.
-  if (spacing_result->Width() >= 0) {
-    spacing_result->SetDeprecatedInkBounds(ink_bounds);
-    return spacing_result;
-  }
-
-  // Negative word-spacing and/or letter-spacing may cause some glyphs to
-  // overflow the left boundary and result negative measured width. Adjust glyph
-  // bounds accordingly to cover the overflow.
-  // The negative width should be clamped to 0 in CSS box model, but it's up to
-  // caller's responsibility.
-  float left = std::min(spacing_result->Width(), ink_bounds.width());
-  if (left < ink_bounds.x()) {
-    // The right edge should be the width of the first character in most cases,
-    // but computing it requires re-measuring bounding box of each glyph. Leave
-    // it unchanged, which gives an excessive right edge but assures it covers
-    // all glyphs.
-    ink_bounds.Outset(gfx::OutsetsF().set_left(ink_bounds.x() - left));
-  }
-
-  spacing_result->SetDeprecatedInkBounds(ink_bounds);
-  return spacing_result;
+  return result->ApplySpacingToCopy(spacing_, word_run);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.cc b/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.cc
index ed217461..a8178fd 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.cc
@@ -54,7 +54,7 @@
       if (run.Rtl())
         width -= word_result->Width();
       if (glyph_bounds) {
-        gfx::RectF adjusted_bounds = word_result->GetDeprecatedInkBounds();
+        gfx::RectF adjusted_bounds = word_result->ComputeInkBounds();
         // Translate glyph bounds to the current glyph position which
         // is the total width before this glyph.
         adjusted_bounds.set_x(adjusted_bounds.x() + width);
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_fuzzer.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_fuzzer.cc
index 8f6702c..bacce514 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_fuzzer.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_fuzzer.cc
@@ -11,11 +11,10 @@
 #include "base/command_line.h"
 #include "third_party/blink/renderer/platform/fonts/font.h"
 #include "third_party/blink/renderer/platform/fonts/font_cache.h"
-#include "third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.h"
+#include "third_party/blink/renderer/platform/fonts/plain_text_node.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
 #include "third_party/blink/renderer/platform/fonts/text_fragment_paint_info.h"
-#include "third_party/blink/renderer/platform/fonts/text_run_paint_info.h"
 #include "third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.h"
 #include "third_party/blink/renderer/platform/testing/task_environment.h"
 
@@ -64,25 +63,23 @@
   bloberizer_ng.Blobs();
 
   // Bloberize
-  CachingWordShaper word_shaper(font);
-  TextRun text_run(string);
   constexpr unsigned word_length = 7;
   unsigned state = 0;
-  for (unsigned from = 0; from < text_run.length(); from += word_length) {
-    unsigned to = std::min(from + word_length, text_run.length());
+  for (unsigned from = 0; from < string.length(); from += word_length) {
+    unsigned to = std::min(from + word_length, string.length());
     bool is_rtl = state & 0x2;
     bool is_override = state & 0x4;
     ++state;
 
-    TextRun subrun(StringView(text_run.ToStringView(), from, to - from),
+    TextRun subrun(StringView(string, from, to - from),
                    is_rtl ? TextDirection::kRtl : TextDirection::kLtr,
                    is_override);
 
-    TextRunPaintInfo subrun_info(subrun);
-    ShapeResultBuffer buffer;
-    word_shaper.FillResultBuffer(subrun, &buffer);
+    PlainTextNode* node = MakeGarbageCollected<PlainTextNode>(
+        subrun, /* normalize_space */ false, font, /* supports_bidi */ true,
+        nullptr);
     ShapeResultBloberizer::FillGlyphs bloberizer(
-        font.GetFontDescription(), subrun_info, buffer,
+        font.GetFontDescription(), *node,
         ShapeResultBloberizer::Type::kEmitText);
     bloberizer.Blobs();
   }
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 ca8863e..e285d560 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -86,7 +86,6 @@
 struct SameSizeAsShapeResult {
   Vector<int> character_position_;
   Vector<UntracedMember<void*>, 1> runs_;
-  UntracedMember<void*> deprecated_ink_bounds_;
   float width;
   unsigned start_index_;
   unsigned bitfields;
@@ -429,7 +428,6 @@
 ShapeResult::~ShapeResult() = default;
 
 void ShapeResult::Trace(Visitor* visitor) const {
-  visitor->Trace(deprecated_ink_bounds_);
   visitor->Trace(runs_);
   visitor->Trace(character_position_);
 }
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 2d3d592..031b3cf 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
@@ -106,11 +106,6 @@
   float spacing;
 };
 
-struct DeprecatedInkBounds : public GarbageCollected<DeprecatedInkBounds> {
-  void Trace(Visitor*) const {}
-  gfx::RectF ink_bounds;
-};
-
 // BreakGlyphsOption - allows OffsetForPosition to consider graphemes
 // separations inside a glyph. It allows the function to return a point inside
 // a glyph when multiple graphemes share a glyph (for example, in a ligature)
@@ -381,19 +376,6 @@
   // quite expensive and involves measuring each glyph accumulating the bounds.
   gfx::RectF ComputeInkBounds() const;
 
-  // Only used by CachingWordShapeIterator
-  // TODO(eae): Remove once LayoutNG lands. https://crbug.com/591099
-  void SetDeprecatedInkBounds(gfx::RectF ink_bounds) {
-    if (!deprecated_ink_bounds_) {
-      deprecated_ink_bounds_ = MakeGarbageCollected<DeprecatedInkBounds>();
-    }
-    deprecated_ink_bounds_->ink_bounds = ink_bounds;
-  }
-  gfx::RectF GetDeprecatedInkBounds() const {
-    DCHECK(deprecated_ink_bounds_);
-    return deprecated_ink_bounds_->ink_bounds;
-  }
-
   String ToString() const;
   void ToString(StringBuilder*) const;
 
@@ -489,11 +471,6 @@
 
   HeapVector<Member<ShapeResultRun>, 1> runs_;
 
-  // Only used by CachingWordShapeIterator and stored here for memory reduction
-  // reasons. See https://crbug.com/955776
-  // TODO(eae): Remove once LayoutNG lands. https://crbug.com/591099
-  Member<DeprecatedInkBounds> deprecated_ink_bounds_ = nullptr;
-
   // The total width. This is the sum of `ShapeResultRun::width_`.
   // It's mutable because `RecalcCharacterPositions()` recalculates this.
   // This should be in sync with `CharacterPositionData::width_`.
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc
index 59869a8..1e911e54 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc
@@ -16,7 +16,6 @@
 #include "third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
-#include "third_party/blink/renderer/platform/fonts/text_run_paint_info.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/text/text_break_iterator.h"
 #include "third_party/blink/renderer/platform/text/text_run.h"
@@ -26,12 +25,6 @@
 namespace {
 
 // A helper for FillGlyphsSlow().
-inline const ShapeResult* GetShapeResult(
-    const Member<const ShapeResult>& item) {
-  return item.Get();
-}
-
-// A helper for FillGlyphsSlow().
 inline const ShapeResult* GetShapeResult(const PlainTextItem& item) {
   return item.GetShapeResult();
 }
@@ -452,30 +445,6 @@
 
 ShapeResultBloberizer::FillGlyphs::FillGlyphs(
     const FontDescription& font_description,
-    const TextRunPaintInfo& run_info,
-    const ShapeResultBuffer& result_buffer,
-    const Type type)
-    : ShapeResultBloberizer(font_description, type) {
-  if (CanUseFastPath(run_info.from, run_info.to, run_info.run.length(),
-                     result_buffer.HasVerticalOffsets())) {
-    DVLOG(4) << "FillGlyphs fast path";
-    DCHECK(!result_buffer.HasVerticalOffsets());
-    DCHECK_NE(type_, ShapeResultBloberizer::Type::kTextIntercepts);
-    DCHECK_NE(type_, ShapeResultBloberizer::Type::kEmitText);
-    advance_ =
-        FillFastHorizontalGlyphs(result_buffer, run_info.run.Direction());
-    return;
-  }
-
-  DVLOG(4) << "FillGlyphs slow path";
-
-  auto results = result_buffer.results_;
-  FillGlyphsSlow(run_info.run.ToStringView(), run_info.run.Direction(), results,
-                 run_info.from, run_info.to);
-}
-
-ShapeResultBloberizer::FillGlyphs::FillGlyphs(
-    const FontDescription& font_description,
     const PlainTextNode& node,
     const Type type)
     : ShapeResultBloberizer(font_description, type) {
@@ -630,24 +599,6 @@
          type_ != ShapeResultBloberizer::Type::kEmitText;
 }
 
-float ShapeResultBloberizer::FillFastHorizontalGlyphs(
-    const ShapeResultBuffer& result_buffer,
-    TextDirection text_direction) {
-  DCHECK(!result_buffer.HasVerticalOffsets());
-  DCHECK_NE(type_, ShapeResultBloberizer::Type::kTextIntercepts);
-
-  float advance = 0;
-  auto results = result_buffer.results_;
-
-  for (unsigned i = 0; i < results.size(); ++i) {
-    const auto& word_result =
-        IsLtr(text_direction) ? results[i] : results[results.size() - 1 - i];
-    advance = FillFastHorizontalGlyphs(word_result.Get(), advance);
-  }
-
-  return advance;
-}
-
 float ShapeResultBloberizer::FillFastHorizontalGlyphs(const ShapeResult* result,
                                                       float initial_advance) {
   DCHECK(!result->HasVerticalOffsets());
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h
index fe21240..0da670c 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h
@@ -8,7 +8,6 @@
 #include "cc/paint/node_id.h"
 #include "third_party/blink/renderer/platform/fonts/canvas_rotation_in_vertical.h"
 #include "third_party/blink/renderer/platform/fonts/glyph.h"
-#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.h"
 #include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -26,7 +25,7 @@
 
 class FontDescription;
 class PlainTextNode;
-struct TextRunPaintInfo;
+class ShapeResultView;
 
 class PLATFORM_EXPORT ShapeResultBloberizer {
   STACK_ALLOCATED();
@@ -123,7 +122,6 @@
                       unsigned length,
                       bool has_vertical_offsets);
   bool CanUseFastPath(unsigned from, unsigned to, const ShapeResultView*);
-  float FillFastHorizontalGlyphs(const ShapeResultBuffer&, TextDirection);
   float FillFastHorizontalGlyphs(const ShapeResult*, float advance = 0);
   static void AddFastHorizontalGlyphToBloberizer(void* context,
                                                  unsigned,
@@ -227,10 +225,7 @@
 
 struct PLATFORM_EXPORT ShapeResultBloberizer::FillGlyphs
     : public ShapeResultBloberizer {
-  FillGlyphs(const FontDescription&,
-             const TextRunPaintInfo&,
-             const ShapeResultBuffer&,
-             Type);
+  // This doesn't work for RTL. See PlainTextPainter::DrawWithBidiReorder().
   FillGlyphs(const FontDescription& font_description,
              const PlainTextNode& node,
              Type type);
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer_test.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer_test.cc
index 79dfba68..f2c8c8e 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer_test.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer_test.cc
@@ -13,12 +13,12 @@
 #include "third_party/blink/renderer/platform/fonts/character_range.h"
 #include "third_party/blink/renderer/platform/fonts/font.h"
 #include "third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.h"
-#include "third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.h"
+#include "third_party/blink/renderer/platform/fonts/plain_text_node.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
 #include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
 #include "third_party/blink/renderer/platform/fonts/text_fragment_paint_info.h"
-#include "third_party/blink/renderer/platform/fonts/text_run_paint_info.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/testing/font_test_base.h"
 #include "third_party/blink/renderer/platform/testing/font_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
@@ -337,89 +337,44 @@
   // "/. ." with an accent mark over the first dot.
   const UChar kStr[] = {0x2F, 0x301, 0x2E, 0x20, 0x2E};
   TextRun text_run{base::span(kStr)};
-  TextRunPaintInfo run_info(text_run);
-  run_info.to = 3;
 
   Font* font = MakeGarbageCollected<Font>(font_description);
-  CachingWordShaper word_shaper(*font);
-  ShapeResultBuffer buffer;
-  word_shaper.FillResultBuffer(text_run, &buffer);
+  PlainTextNode* node = MakeGarbageCollected<PlainTextNode>(
+      text_run, /* normalize_space */ false, *font, /* supports_bidi */ true,
+      /* cache */ nullptr);
   ShapeResultBloberizer::FillGlyphs bloberizer(
-      font->GetFontDescription(), run_info, buffer,
+      font->GetFontDescription(), *node,
       ShapeResultBloberizer::Type::kEmitText);
 
   Font* reference_font = MakeGarbageCollected<Font>(font_description);
   reference_font->SetCanShapeWordByWordForTesting(false);
 
-  CachingWordShaper reference_word_shaper(*reference_font);
-  ShapeResultBuffer reference_buffer;
-  reference_word_shaper.FillResultBuffer(text_run, &reference_buffer);
+  PlainTextNode* reference_node = MakeGarbageCollected<PlainTextNode>(
+      text_run, /* normalize_space */ false, *reference_font,
+      /* supports_bidi */ true,
+      /* cache */ nullptr);
   ShapeResultBloberizer::FillGlyphs reference_bloberizer(
-      reference_font->GetFontDescription(), run_info, reference_buffer,
+      reference_font->GetFontDescription(), *reference_node,
       ShapeResultBloberizer::Type::kEmitText);
 
   const auto& glyphs =
       ShapeResultBloberizerTestInfo::PendingRunGlyphs(bloberizer);
-  ASSERT_EQ(glyphs.size(), 3ul);
+  ASSERT_EQ(glyphs.size(), 5ul);
   const auto reference_glyphs =
       ShapeResultBloberizerTestInfo::PendingRunGlyphs(reference_bloberizer);
-  ASSERT_EQ(reference_glyphs.size(), 3ul);
-
-  EXPECT_EQ(reference_glyphs[0], glyphs[0]);
-  EXPECT_EQ(reference_glyphs[1], glyphs[1]);
-  EXPECT_EQ(reference_glyphs[2], glyphs[2]);
-
-  CheckBlobBuffer(
-      bloberizer.Blobs(),
-      {{
-          {3,
-           text_run.ToStringView()
-               .ToString()
-               .Substring(run_info.from, run_info.to - run_info.from)
-               .Utf8(),
-           ExpectedRun::ClusterDirection::kAscending},
-      }});
-}
-
-// Tests that filling a glyph buffer for a specific range returns the same
-// results when shaping word by word as when shaping the full run in one go.
-TEST_F(ShapeResultBloberizerTest, CommonAccentRightToLeftFillGlyphBuffer) {
-  // "[] []" with an accent mark over the last square bracket.
-  const UChar kStr[] = {0x5B, 0x5D, 0x20, 0x5B, 0x301, 0x5D};
-  TextRun text_run(StringView(base::span(kStr)), TextDirection::kRtl);
-  TextRunPaintInfo run_info(text_run);
-  run_info.from = 1;
-
-  Font* font = MakeGarbageCollected<Font>(font_description);
-  CachingWordShaper word_shaper(*font);
-  ShapeResultBuffer buffer;
-  word_shaper.FillResultBuffer(text_run, &buffer);
-  ShapeResultBloberizer::FillGlyphs bloberizer(
-      font->GetFontDescription(), run_info, buffer,
-      ShapeResultBloberizer::Type::kEmitText);
-
-  Font* reference_font = MakeGarbageCollected<Font>(font_description);
-  reference_font->SetCanShapeWordByWordForTesting(false);
-
-  CachingWordShaper reference_word_shaper(*reference_font);
-  ShapeResultBuffer reference_buffer;
-  reference_word_shaper.FillResultBuffer(text_run, &reference_buffer);
-  ShapeResultBloberizer::FillGlyphs reference_bloberizer(
-      reference_font->GetFontDescription(), run_info, reference_buffer,
-      ShapeResultBloberizer::Type::kEmitText);
-
-  const auto& glyphs =
-      ShapeResultBloberizerTestInfo::PendingRunGlyphs(bloberizer);
-  ASSERT_EQ(5u, glyphs.size());
-  const auto reference_glyphs =
-      ShapeResultBloberizerTestInfo::PendingRunGlyphs(reference_bloberizer);
-  ASSERT_EQ(5u, reference_glyphs.size());
+  ASSERT_EQ(reference_glyphs.size(), 5ul);
 
   EXPECT_EQ(reference_glyphs[0], glyphs[0]);
   EXPECT_EQ(reference_glyphs[1], glyphs[1]);
   EXPECT_EQ(reference_glyphs[2], glyphs[2]);
   EXPECT_EQ(reference_glyphs[3], glyphs[3]);
   EXPECT_EQ(reference_glyphs[4], glyphs[4]);
+
+  CheckBlobBuffer(bloberizer.Blobs(),
+                  {{
+                      {5, text_run.ToStringView().ToString().Utf8(),
+                       ExpectedRun::ClusterDirection::kAscending},
+                  }});
 }
 
 TEST_F(ShapeResultBloberizerTest, CommonAccentRightToLeftFillGlyphBufferNG) {
@@ -628,21 +583,17 @@
   TextRun text_run{base::span(kStr)};
 
   Font* font = MakeGarbageCollected<Font>(font_description);
-  CachingWordShaper shaper(*font);
+  PlainTextNode* node = MakeGarbageCollected<PlainTextNode>(
+      text_run, /* normalize_space */ false, *font, /* supports_bidi */ false,
+      /* cache */ nullptr);
   gfx::RectF glyph_bounds;
-  ASSERT_GT(shaper.Width(text_run, &glyph_bounds), 0);
+  ASSERT_GT(node->AccumulateInlineSize(&glyph_bounds), .0f);
 
-  TextRunPaintInfo run_info(text_run);
-  run_info.to = 8;
-
-  CachingWordShaper word_shaper(*font);
-  ShapeResultBuffer buffer;
-  word_shaper.FillResultBuffer(text_run, &buffer);
   ShapeResultBloberizer::FillGlyphs bloberizer(
-      font->GetFontDescription(), run_info, buffer,
+      font->GetFontDescription(), *node,
       ShapeResultBloberizer::Type::kEmitText);
 
-  shaper.GetCharacterRange(text_run, 0, 8);
+  node->ComputeCharacterRange(0, 8);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc
index b297e53f..5a732f2 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc
@@ -102,7 +102,7 @@
                                 IsRtl(direction) ? total_width : 0};
   for (unsigned j = 0; j < results_.size(); j++) {
     const ShapeResult* result = results_[j];
-    ComputeRangeIn(*result, result->GetDeprecatedInkBounds(), context);
+    ComputeRangeIn(*result, result->ComputeInkBounds(), context);
   }
 
   // The position in question might be just after the text.
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 8f05068..2586e845 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -3367,6 +3367,10 @@
       status: "stable",
     },
     {
+      name: "NonEmptyVisibleTextSelectionForTextFragment",
+      status: "stable",
+    },
+    {
       // TODO(crbug.com/1426629): This feature enables the deprecated value
       // slider-vertical. Disable this feature to stop parsing or allowing these
       // values.
diff --git a/third_party/blink/renderer/platform/text/locale_mac_test.mm b/third_party/blink/renderer/platform/text/locale_mac_test.mm
index 5a51842..b74f0ca 100644
--- a/third_party/blink/renderer/platform/text/locale_mac_test.mm
+++ b/third_party/blink/renderer/platform/text/locale_mac_test.mm
@@ -82,15 +82,16 @@
                                    int minute,
                                    int second,
                                    int millisecond) {
+    base::TimeDelta time = base::Hours(hour) + base::Minutes(minute) +
+                           base::Seconds(second) +
+                           base::Milliseconds(millisecond);
     DateComponents date;
-    date.SetMillisecondsSinceMidnight(hour * kMsPerHour +
-                                      minute * kMsPerMinute +
-                                      second * kMsPerSecond + millisecond);
+    date.SetMillisecondsSinceMidnight(time.InMillisecondsF());
     return date;
   }
 
   double MsForDate(int year, int month, int day) {
-    return DateToDaysFrom1970(year, month, day) * kMsPerDay;
+    return base::Days(DateToDaysFrom1970(year, month, day)).InMillisecondsF();
   }
 
   String FormatWeek(const String& locale_string, const String& iso_string) {
diff --git a/third_party/blink/renderer/platform/text/locale_win_test.cc b/third_party/blink/renderer/platform/text/locale_win_test.cc
index 18f47f7..dab88de1 100644
--- a/third_party/blink/renderer/platform/text/locale_win_test.cc
+++ b/third_party/blink/renderer/platform/text/locale_win_test.cc
@@ -89,7 +89,7 @@
   }
 
   double MsForDate(int year, int month, int day) {
-    return DateToDaysFrom1970(year, month, day) * kMsPerDay;
+    return base::Days(DateToDaysFrom1970(year, month, day)).InMillisecondsF();
   }
 
   String FormatDate(LCID lcid, int year, int month, int day) {
diff --git a/third_party/blink/renderer/platform/wtf/date_math.cc b/third_party/blink/renderer/platform/wtf/date_math.cc
index aba5b27..6d18f54 100644
--- a/third_party/blink/renderer/platform/wtf/date_math.cc
+++ b/third_party/blink/renderer/platform/wtf/date_math.cc
@@ -140,13 +140,14 @@
 }
 
 static double MsToDays(double ms) {
-  return floor(ms / kMsPerDay);
+  return base::Milliseconds(ms).InDaysFloored();
 }
 
 int MsToYear(double ms) {
   DCHECK(std::isfinite(ms));
   DCHECK_GE(ms, kMinimumECMADateInMs);
   DCHECK_LE(ms, kMaximumECMADateInMs);
+  static constexpr double kMsPerDay = base::Time::kMillisecondsPerDay;
   int approx_year = static_cast<int>(floor(ms / (kMsPerDay * 365.2425)) + 1970);
   double ms_from_approx_year_to1970 =
       kMsPerDay * DaysFrom1970ToYear(approx_year);
diff --git a/third_party/blink/renderer/platform/wtf/date_math.h b/third_party/blink/renderer/platform/wtf/date_math.h
index 9b75e35..47518d3 100644
--- a/third_party/blink/renderer/platform/wtf/date_math.h
+++ b/third_party/blink/renderer/platform/wtf/date_math.h
@@ -48,13 +48,6 @@
 
 namespace blink {
 
-const double kMinutesPerHour = 60.0;
-const double kSecondsPerMinute = 60.0;
-const double kMsPerSecond = 1000.0;
-const double kMsPerMinute = 60.0 * 1000.0;
-const double kMsPerHour = 60.0 * 60.0 * 1000.0;
-const double kMsPerDay = 24.0 * 60.0 * 60.0 * 1000.0;
-
 WTF_EXPORT bool IsLeapYear(int year);
 
 // Returns the number of days from 1970-01-01 to the specified date.
diff --git a/third_party/blink/renderer/platform/wtf/shared_buffer.h b/third_party/blink/renderer/platform/wtf/shared_buffer.h
index d183174..585a8e408 100644
--- a/third_party/blink/renderer/platform/wtf/shared_buffer.h
+++ b/third_party/blink/renderer/platform/wtf/shared_buffer.h
@@ -24,11 +24,6 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_SHARED_BUFFER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_SHARED_BUFFER_H_
 
@@ -229,9 +224,10 @@
   std::vector<char> buffer;
   buffer.reserve(size_);
 
-  for (const auto& span : *this)
-    buffer.insert(buffer.end(), span.data(), span.data() + span.size());
-
+  for (const auto& span : *this) {
+    buffer.insert(buffer.end(), span.data(),
+                  UNSAFE_TODO(span.data() + span.size()));
+  }
   DCHECK_EQ(buffer.size(), size_);
   return buffer;
 }
@@ -243,7 +239,8 @@
 
   for (const auto& span : *this) {
     buffer.insert(buffer.end(), reinterpret_cast<const uint8_t*>(span.data()),
-                  reinterpret_cast<const uint8_t*>(span.data() + span.size()));
+                  reinterpret_cast<const uint8_t*>(
+                      UNSAFE_TODO(span.data() + span.size())));
   }
   DCHECK_EQ(buffer.size(), size_);
   return buffer;
diff --git a/third_party/blink/renderer/platform/wtf/stack_util.cc b/third_party/blink/renderer/platform/wtf/stack_util.cc
index 2d7d412..91d15dc 100644
--- a/third_party/blink/renderer/platform/wtf/stack_util.cc
+++ b/third_party/blink/renderer/platform/wtf/stack_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/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "third_party/blink/renderer/platform/wtf/stack_util.h"
 
 #include "build/build_config.h"
@@ -127,7 +122,7 @@
     error = pthread_attr_getstack(&attr, &base, &size);
     CHECK(!error);
     pthread_attr_destroy(&attr);
-    return reinterpret_cast<uint8_t*>(base) + size;
+    return UNSAFE_TODO(reinterpret_cast<uint8_t*>(base) + size);
   }
 #if BUILDFLAG(IS_FREEBSD)
   pthread_attr_destroy(&attr);
@@ -228,7 +223,7 @@
   // tracks the end of the committed range. We're after the end of the reserved
   // stack area (most of which will be uncommitted, most times.)
   MEMORY_BASIC_INFORMATION stack_info;
-  memset(&stack_info, 0, sizeof(MEMORY_BASIC_INFORMATION));
+  UNSAFE_TODO(memset(&stack_info, 0, sizeof(MEMORY_BASIC_INFORMATION)));
   size_t result_size =
       VirtualQuery(&stack_info, &stack_info, sizeof(MEMORY_BASIC_INFORMATION));
   DCHECK_GE(result_size, sizeof(MEMORY_BASIC_INFORMATION));
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-animation.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-animation.html
index c2e0c629..1495318b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-animation.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-animation.html
@@ -31,7 +31,6 @@
   }
 
   #anchored {
-    align-self: self-end;
     position-anchor: --a;
     position-try-fallbacks: flip-block;
     position: absolute;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-basic.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-basic.html
index a26e402..175e39e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-basic.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-basic.html
@@ -21,7 +21,6 @@
     anchor-name: --a;
   }
   #anchored {
-    align-self: self-end;
     position-anchor: --a;
     position-try-fallbacks: flip-block;
     position: absolute;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-change-fallbacks.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-change-fallbacks.html
index 9f33cee8..4ff0e46b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-change-fallbacks.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-change-fallbacks.html
@@ -21,7 +21,6 @@
     anchor-name: --a;
   }
   #anchored {
-    align-self: self-end;
     position-anchor: --a;
     position-try-fallbacks: flip-block;
     position: absolute;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-change-try-rule.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-change-try-rule.html
index c9be2c6..98ae375 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-change-try-rule.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-change-try-rule.html
@@ -26,12 +26,10 @@
     position: absolute;
     width: 100px;
     height: 200px;
-    align-self: self-end;
     position-area: top center;
     background: lime;
   }
   @position-try --try {
-    align-self: self-start;
     position-area: bottom center;
   }
 </style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-iframe.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-iframe.html
index 282a557..e9b389f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-iframe.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-iframe.html
@@ -29,7 +29,6 @@
     width: 100px;
     height: 200px;
     position-area: top center;
-    align-self: self-end;
     background: lime;
   }
 </style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-intermediate-ignored.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-intermediate-ignored.html
index fd60b44..7ccf08c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-intermediate-ignored.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/last-successful-intermediate-ignored.html
@@ -27,7 +27,6 @@
     width: 100px;
     height: 200px;
     position-area: top center;
-    align-self: self-end;
     background: lime;
   }
 </style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/registered-custom-property-anchor.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/registered-custom-property-anchor.html
new file mode 100644
index 0000000..7ea5912e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/registered-custom-property-anchor.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<title>CSS Anchor Positioning: anchor() and anchor-size() not valid in registered custom properties</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#anchor-pos">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  @property --length {
+    syntax: "<length>";
+    inherits: false;
+    initial-value: 0px;
+  }
+  @property --length-percentage {
+    syntax: "<length-percentage>";
+    inherits: false;
+    initial-value: 0px;
+  }
+  @property --number {
+    syntax: "<number>";
+    inherits: false;
+    initial-value: 0;
+  }
+  #anchor {
+    --length: anchor(--foo bottom, 5px);
+    --length-percentage: anchor(--foo bottom, 10%);
+    --number: sign(anchor(--foo bottom, 100px));
+  }
+  #anchor-size {
+    --length: anchor-size(--foo block, 7px);
+    --length-percentage: anchor-size(--foo block, 20%);
+    --number: sign(anchor-size(--foo block, 100px));
+  }
+</style>
+<div id="anchor"></div>
+<div id="anchor_size"></div>
+<script>
+  test(() => {
+    const style = getComputedStyle(anchor);
+    assert_equals(style.getPropertyValue("--length"), "0px");
+    assert_equals(style.getPropertyValue("--length-percentage"), "0px");
+    assert_equals(style.getPropertyValue("--number"), "0");
+  }, "anchor() functions are not allowed in registered custom properties accepting <length> or <length-percentage>");
+
+  test(() => {
+    const style = getComputedStyle(anchor_size);
+    assert_equals(style.getPropertyValue("--length"), "0px");
+    assert_equals(style.getPropertyValue("--length-percentage"), "0px");
+    assert_equals(style.getPropertyValue("--number"), "0");
+  }, "anchor-size() using fallback value for registered custom properties accepting <length> or <length-percentage>");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/fragmentation/grid-gap-decorations-fragmentation-018-crash.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/fragmentation/grid-gap-decorations-fragmentation-018-crash.html
new file mode 100644
index 0000000..680a7b8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/fragmentation/grid-gap-decorations-fragmentation-018-crash.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>
+  Avoid crash when we have collapsed tracks due to auto-fit.
+</title>
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/11520">
+<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com">
+<style>
+  body {
+    margin: 0px;
+  }
+  .multi-col {
+    columns: 3;
+    column-fill: auto;
+    height: 100px;
+  }
+  .grid-container {
+    display: grid;
+    height: 300px;
+    grid-template-rows: repeat(auto-fit, 20px);
+    align-content: space-around;
+  }
+</style>
+<div class="multi-col">
+  <div class="grid-container">
+    <div style="width: 10px; height: 15px;"> </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/http/tests/devtools/network/network-disable-cache-memory.js b/third_party/blink/web_tests/http/tests/devtools/network/network-disable-cache-memory.js
index 0645e87..d050299d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/network/network-disable-cache-memory.js
+++ b/third_party/blink/web_tests/http/tests/devtools/network/network-disable-cache-memory.js
@@ -13,34 +13,42 @@
   await TestRunner.showPanel('network');
   await TestRunner.navigatePromise('resources/random-script-page.html');
 
-  var content1;
-  var content2;
-  var content3;
-
-  function loadScriptAndGetContent(callback) {
+  let status1;
+  let content1;
+  let status2;
+  let content2;
+  let status3;
+  let content3;
+  function loadScriptAndGetStatusAndContent(callback) {
     NetworkTestRunner.recordNetwork();
     ConsoleTestRunner.addConsoleSniffer(scriptLoaded);
     TestRunner.evaluateInPage('scheduleScriptLoad()');
 
     function scriptLoaded() {
-      var request = NetworkTestRunner.networkRequests().pop();
-      request.requestContentData().then(TextUtils.ContentData.ContentData.asDeferredContent).then(callback);
+      const request = NetworkTestRunner.networkRequests().pop();
+      request.requestContentData().then(TextUtils.ContentData.ContentData.asDeferredContent).then(
+        ({content, error, isEncoded}) => {
+          callback({status: request?.statusCode, content, error, isEncoded});
+        }
+      );
     }
   }
 
-  loadScriptAndGetContent(step1);
+  loadScriptAndGetStatusAndContent(step1);
 
-  function step1({ content, error, isEncoded }) {
+  function step1({ status, content, error, isEncoded }) {
     content1 = content;
+    status1 = status;
     TestRunner.reloadPage(step2);
   }
 
   function step2(msg) {
-    loadScriptAndGetContent(step3);
+    loadScriptAndGetStatusAndContent(step3);
   }
 
-  function step3({ content, error, isEncoded }) {
+  function step3({ status, content, error, isEncoded }) {
     content2 = content;
+    status2 = status;
     TestRunner.NetworkAgent.setCacheDisabled(true).then(step4);
   }
 
@@ -49,14 +57,17 @@
   }
 
   function step5() {
-    loadScriptAndGetContent(step6);
+    loadScriptAndGetStatusAndContent(step6);
   }
 
-  function step6({ content, error, isEncoded }) {
+  function step6({ status, content, error, isEncoded }) {
     content3 = content;
+    status3 = status;
 
-    TestRunner.assertTrue(content1 === content2, 'First and second scripts should be equal.');
-    TestRunner.assertTrue(content2 !== content3, 'Second and third scripts should differ.');
+    TestRunner.assertEquals(status1, 200, 'Second script load should be from cache');
+    TestRunner.assertEquals(status2, 304, 'Second script load should be from cache');
+    TestRunner.assertTrue(content1 !== content3, 'First and third scripts should differ.');
+    TestRunner.assertEquals(status3, 200, 'Third script load should be from network');
     TestRunner.NetworkAgent.setCacheDisabled(false).then(step7);
   }
 
diff --git a/third_party/crossbench b/third_party/crossbench
index 4dbf27c..7fad92a 160000
--- a/third_party/crossbench
+++ b/third_party/crossbench
@@ -1 +1 @@
-Subproject commit 4dbf27cac51cdece9e1e2915dfad799f7a16e839
+Subproject commit 7fad92a8c43e08847134eef473d56fa7044fc989
diff --git a/third_party/dawn b/third_party/dawn
index da556b4..d7279f3 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit da556b4eb39e603729869c3eedbedd8643e1518e
+Subproject commit d7279f397e6c79fd4b1c1c3fdf5b524991dd7a71
diff --git a/third_party/depot_tools b/third_party/depot_tools
index 9fd9d31f..e4185d0 160000
--- a/third_party/depot_tools
+++ b/third_party/depot_tools
@@ -1 +1 @@
-Subproject commit 9fd9d31f9441c754dd8860bfea7ca1be7833eaae
+Subproject commit e4185d003f9c08cb49edcb593212481db59d9a54
diff --git a/third_party/jetstream/main b/third_party/jetstream/main
index c432b1a..a26d33b 160000
--- a/third_party/jetstream/main
+++ b/third_party/jetstream/main
@@ -1 +1 @@
-Subproject commit c432b1a49a597356e2bbe93e63de7a25db01cc7a
+Subproject commit a26d33b5df562cbab0887e1ec5d05950aeb3e76a
diff --git a/third_party/perfetto b/third_party/perfetto
index 04a02eb..69bd8a4 160000
--- a/third_party/perfetto
+++ b/third_party/perfetto
@@ -1 +1 @@
-Subproject commit 04a02eb5f60c25daf3a07fbfa3aefeef366760d3
+Subproject commit 69bd8a4b80aca14a9f07b5443572bb34150e496c
diff --git a/third_party/rust/chromium_crates_io/Cargo.lock b/third_party/rust/chromium_crates_io/Cargo.lock
index 4ce34db..a2bc760f 100644
--- a/third_party/rust/chromium_crates_io/Cargo.lock
+++ b/third_party/rust/chromium_crates_io/Cargo.lock
@@ -824,7 +824,7 @@
 
 [[package]]
 name = "quote"
-version = "1.0.40"
+version = "1.0.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "proc-macro2",
diff --git a/third_party/rust/chromium_crates_io/supply-chain/config.toml b/third_party/rust/chromium_crates_io/supply-chain/config.toml
index 3e651c9c..6b40fb82 100644
--- a/third_party/rust/chromium_crates_io/supply-chain/config.toml
+++ b/third_party/rust/chromium_crates_io/supply-chain/config.toml
@@ -311,7 +311,7 @@
 [policy."qr_code:2.0.0"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
-[policy."quote:1.0.40"]
+[policy."quote:1.0.41"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
 [policy."read-fonts:0.35.0"]
diff --git a/third_party/rust/chromium_crates_io/vendor/quote-v1/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/quote-v1/.cargo_vcs_info.json
index 90ccbb86..410d546 100644
--- a/third_party/rust/chromium_crates_io/vendor/quote-v1/.cargo_vcs_info.json
+++ b/third_party/rust/chromium_crates_io/vendor/quote-v1/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "ab1e92c27a492e6077e203a6f85496bb4b1522e8"
+    "sha1": "594c865ce817b4adb5863713e4fa3749fbf47f0a"
   },
   "path_in_vcs": ""
 }
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/quote-v1/.github/workflows/ci.yml b/third_party/rust/chromium_crates_io/vendor/quote-v1/.github/workflows/ci.yml
index 189f230..19ca4c8 100644
--- a/third_party/rust/chromium_crates_io/vendor/quote-v1/.github/workflows/ci.yml
+++ b/third_party/rust/chromium_crates_io/vendor/quote-v1/.github/workflows/ci.yml
@@ -24,10 +24,10 @@
     strategy:
       fail-fast: false
       matrix:
-        rust: [nightly, stable, beta, 1.56.0]
+        rust: [nightly, stable, beta, 1.76.0, 1.60.0]
     timeout-minutes: 45
     steps:
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@v5
       - uses: dtolnay/rust-toolchain@master
         with:
           toolchain: ${{matrix.rust}}
@@ -35,7 +35,9 @@
       - name: Enable type layout randomization
         run: echo RUSTFLAGS=${RUSTFLAGS}\ -Zrandomize-layout >> $GITHUB_ENV
         if: matrix.rust == 'nightly'
+      - run: cargo check
       - run: cargo test
+        if: matrix.rust != '1.60.0'
       - run: cargo run --manifest-path benches/Cargo.toml
       - uses: actions/upload-artifact@v4
         if: matrix.rust == 'nightly' && always()
@@ -51,7 +53,7 @@
     runs-on: ubuntu-latest
     timeout-minutes: 45
     steps:
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@v5
       - uses: dtolnay/rust-toolchain@nightly
       - run: cargo generate-lockfile -Z minimal-versions
       - run: cargo check --locked
@@ -65,7 +67,7 @@
     env:
       RUSTDOCFLAGS: -Dwarnings
     steps:
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@v5
       - uses: dtolnay/rust-toolchain@nightly
         with:
           components: rust-src
@@ -78,7 +80,7 @@
     if: github.event_name != 'pull_request'
     timeout-minutes: 45
     steps:
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@v5
       - uses: dtolnay/rust-toolchain@nightly
         with:
           components: clippy, rust-src
@@ -91,7 +93,7 @@
     runs-on: ubuntu-latest
     timeout-minutes: 45
     steps:
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@v5
       - uses: dtolnay/rust-toolchain@miri
       - run: cargo miri setup
       - run: cargo miri test
@@ -104,7 +106,7 @@
     if: github.event_name != 'pull_request'
     timeout-minutes: 45
     steps:
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@v5
       - uses: dtolnay/rust-toolchain@stable
       - uses: dtolnay/install@cargo-outdated
       - run: cargo outdated --workspace --exit-code 1
diff --git a/third_party/rust/chromium_crates_io/vendor/quote-v1/Cargo.lock b/third_party/rust/chromium_crates_io/vendor/quote-v1/Cargo.lock
index 1c772afd..646d9ef 100644
--- a/third_party/rust/chromium_crates_io/vendor/quote-v1/Cargo.lock
+++ b/third_party/rust/chromium_crates_io/vendor/quote-v1/Cargo.lock
@@ -16,21 +16,21 @@
 
 [[package]]
 name = "glob"
-version = "0.3.2"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
+checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
 
 [[package]]
 name = "hashbrown"
-version = "0.15.2"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
 
 [[package]]
 name = "indexmap"
-version = "2.8.0"
+version = "2.11.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
+checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
 dependencies = [
  "equivalent",
  "hashbrown",
@@ -44,31 +44,31 @@
 
 [[package]]
 name = "memchr"
-version = "2.7.4"
+version = "2.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.94"
+version = "1.0.101"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
+checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.39"
+version = "1.0.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.40"
+version = "1.0.41"
 dependencies = [
  "proc-macro2",
  "rustversion",
@@ -77,9 +77,9 @@
 
 [[package]]
 name = "rustversion"
-version = "1.0.20"
+version = "1.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
 
 [[package]]
 name = "ryu"
@@ -89,53 +89,63 @@
 
 [[package]]
 name = "serde"
-version = "1.0.219"
+version = "1.0.228"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.219"
+version = "1.0.228"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
 dependencies = [
  "proc-macro2",
- "quote 1.0.39",
+ "quote 1.0.40",
  "syn",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.140"
+version = "1.0.145"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
 dependencies = [
  "itoa",
  "memchr",
  "ryu",
  "serde",
+ "serde_core",
 ]
 
 [[package]]
 name = "serde_spanned"
-version = "0.6.8"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
+checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee"
 dependencies = [
- "serde",
+ "serde_core",
 ]
 
 [[package]]
 name = "syn"
-version = "2.0.100"
+version = "2.0.106"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
+checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
 dependencies = [
  "proc-macro2",
- "quote 1.0.39",
+ "quote 1.0.40",
  "unicode-ident",
 ]
 
@@ -156,43 +166,48 @@
 
 [[package]]
 name = "toml"
-version = "0.8.20"
+version = "0.9.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
-dependencies = [
- "serde",
- "serde_spanned",
- "toml_datetime",
- "toml_edit",
-]
-
-[[package]]
-name = "toml_datetime"
-version = "0.6.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "toml_edit"
-version = "0.22.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
+checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0"
 dependencies = [
  "indexmap",
- "serde",
+ "serde_core",
  "serde_spanned",
  "toml_datetime",
+ "toml_parser",
+ "toml_writer",
  "winnow",
 ]
 
 [[package]]
-name = "trybuild"
-version = "1.0.104"
+name = "toml_datetime"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ae08be68c056db96f0e6c6dd820727cca756ced9e1f4cc7fdd20e2a55e23898"
+checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "toml_parser"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627"
+dependencies = [
+ "winnow",
+]
+
+[[package]]
+name = "toml_writer"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d163a63c116ce562a22cda521fcc4d79152e7aba014456fb5eb442f6d6a10109"
+
+[[package]]
+name = "trybuild"
+version = "1.0.111"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ded9fdb81f30a5708920310bfcd9ea7482ff9cba5f54601f7a19a877d5c2392"
 dependencies = [
  "dissimilar",
  "glob",
@@ -206,97 +221,36 @@
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.18"
+version = "1.0.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
 
 [[package]]
 name = "winapi-util"
-version = "0.1.9"
+version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
 dependencies = [
  "windows-sys",
 ]
 
 [[package]]
+name = "windows-link"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65"
+
+[[package]]
 name = "windows-sys"
-version = "0.59.0"
+version = "0.61.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f"
 dependencies = [
- "windows-targets",
+ "windows-link",
 ]
 
 [[package]]
-name = "windows-targets"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
-dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
-]
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-
-[[package]]
 name = "winnow"
-version = "0.7.3"
+version = "0.7.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1"
-dependencies = [
- "memchr",
-]
+checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
diff --git a/third_party/rust/chromium_crates_io/vendor/quote-v1/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/quote-v1/Cargo.toml
index f370f35..3b64326 100644
--- a/third_party/rust/chromium_crates_io/vendor/quote-v1/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/vendor/quote-v1/Cargo.toml
@@ -11,11 +11,11 @@
 
 [package]
 edition = "2018"
-rust-version = "1.56"
+rust-version = "1.60"
 name = "quote"
-version = "1.0.40"
+version = "1.0.41"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
-build = false
+build = "build.rs"
 autolib = false
 autobins = false
 autoexamples = false
@@ -33,13 +33,14 @@
 repository = "https://github.com/dtolnay/quote"
 
 [package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
 rustdoc-args = [
     "--generate-link-to-definition",
+    "--generate-macro-expansion",
     "--extern-html-root-url=core=https://doc.rust-lang.org",
     "--extern-html-root-url=alloc=https://doc.rust-lang.org",
     "--extern-html-root-url=std=https://doc.rust-lang.org",
 ]
-targets = ["x86_64-unknown-linux-gnu"]
 
 [features]
 default = ["proc-macro"]
@@ -65,5 +66,5 @@
 version = "1.0"
 
 [dev-dependencies.trybuild]
-version = "1.0.66"
+version = "1.0.108"
 features = ["diff"]
diff --git a/third_party/rust/chromium_crates_io/vendor/quote-v1/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/quote-v1/Cargo.toml.orig
index 0459f52..fb427a9 100644
--- a/third_party/rust/chromium_crates_io/vendor/quote-v1/Cargo.toml.orig
+++ b/third_party/rust/chromium_crates_io/vendor/quote-v1/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "quote"
-version = "1.0.40"
+version = "1.0.41"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 autobenches = false
 categories = ["development-tools::procedural-macro-helpers"]
@@ -10,14 +10,14 @@
 keywords = ["macros", "syn"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/dtolnay/quote"
-rust-version = "1.56"
+rust-version = "1.60"
 
 [dependencies]
 proc-macro2 = { version = "1.0.80", default-features = false }
 
 [dev-dependencies]
 rustversion = "1.0"
-trybuild = { version = "1.0.66", features = ["diff"] }
+trybuild = { version = "1.0.108", features = ["diff"] }
 
 [features]
 default = ["proc-macro"]
@@ -32,6 +32,7 @@
 targets = ["x86_64-unknown-linux-gnu"]
 rustdoc-args = [
     "--generate-link-to-definition",
+    "--generate-macro-expansion",
     "--extern-html-root-url=core=https://doc.rust-lang.org",
     "--extern-html-root-url=alloc=https://doc.rust-lang.org",
     "--extern-html-root-url=std=https://doc.rust-lang.org",
diff --git a/third_party/rust/chromium_crates_io/vendor/quote-v1/README.md b/third_party/rust/chromium_crates_io/vendor/quote-v1/README.md
index 58bbf21..83a500b8 100644
--- a/third_party/rust/chromium_crates_io/vendor/quote-v1/README.md
+++ b/third_party/rust/chromium_crates_io/vendor/quote-v1/README.md
@@ -34,7 +34,7 @@
 quote = "1.0"
 ```
 
-*Version requirement: Quote supports rustc 1.56 and up.*<br>
+*Version requirement: Quote supports rustc 1.60 and up.*<br>
 [*Release notes*](https://github.com/dtolnay/quote/releases)
 
 <br>
diff --git a/third_party/rust/chromium_crates_io/vendor/quote-v1/build.rs b/third_party/rust/chromium_crates_io/vendor/quote-v1/build.rs
new file mode 100644
index 0000000..c079367
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/quote-v1/build.rs
@@ -0,0 +1,33 @@
+use std::env;
+use std::process::Command;
+use std::str;
+
+fn main() {
+    println!("cargo:rerun-if-changed=build.rs");
+
+    let minor = match rustc_minor_version() {
+        Some(minor) => minor,
+        None => return,
+    };
+
+    if minor >= 77 {
+        println!("cargo:rustc-check-cfg=cfg(no_diagnostic_namespace)");
+    }
+
+    // Support for the `#[diagnostic]` tool attribute namespace
+    // https://blog.rust-lang.org/2024/05/02/Rust-1.78.0.html#diagnostic-attributes
+    if minor < 78 {
+        println!("cargo:rustc-cfg=no_diagnostic_namespace");
+    }
+}
+
+fn rustc_minor_version() -> Option<u32> {
+    let rustc = env::var_os("RUSTC")?;
+    let output = Command::new(rustc).arg("--version").output().ok()?;
+    let version = str::from_utf8(&output.stdout).ok()?;
+    let mut pieces = version.split('.');
+    if pieces.next() != Some("rustc 1") {
+        return None;
+    }
+    pieces.next()?.parse().ok()
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/quote-v1/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/quote-v1/src/lib.rs
index 0a12d60..1a939a9 100644
--- a/third_party/rust/chromium_crates_io/vendor/quote-v1/src/lib.rs
+++ b/third_party/rust/chromium_crates_io/vendor/quote-v1/src/lib.rs
@@ -89,7 +89,7 @@
 //! [prettyplease]: https://github.com/dtolnay/prettyplease
 
 // Quote types in rustdoc of other crates get linked to here.
-#![doc(html_root_url = "https://docs.rs/quote/1.0.40")]
+#![doc(html_root_url = "https://docs.rs/quote/1.0.41")]
 #![allow(
     clippy::doc_markdown,
     clippy::elidable_lifetime_names,
@@ -888,9 +888,9 @@
     // A repetition with no separator.
     ($tokens:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) * $a3:tt) => {{
         use $crate::__private::ext::*;
-        let has_iter = $crate::__private::ThereIsNoIteratorInRepetition;
+        let has_iter = $crate::__private::HasIterator::<false>;
         $crate::pounded_var_names!{quote_bind_into_iter!(has_iter) () $($inner)*}
-        let _: $crate::__private::HasIterator = has_iter;
+        <_ as $crate::__private::CheckHasIterator<true>>::check(has_iter);
         // This is `while true` instead of `loop` because if there are no
         // iterators used inside of this repetition then the body would not
         // contain any `break`, so the compiler would emit unreachable code
@@ -911,9 +911,9 @@
     ($tokens:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) $sep:tt *) => {{
         use $crate::__private::ext::*;
         let mut _i = 0usize;
-        let has_iter = $crate::__private::ThereIsNoIteratorInRepetition;
+        let has_iter = $crate::__private::HasIterator::<false>;
         $crate::pounded_var_names!{quote_bind_into_iter!(has_iter) () $($inner)*}
-        let _: $crate::__private::HasIterator = has_iter;
+        <_ as $crate::__private::CheckHasIterator<true>>::check(has_iter);
         while true {
             $crate::pounded_var_names!{quote_bind_next_or_break!() () $($inner)*}
             if _i > 0 {
@@ -958,9 +958,9 @@
 
     ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) * $a3:tt) => {{
         use $crate::__private::ext::*;
-        let has_iter = $crate::__private::ThereIsNoIteratorInRepetition;
+        let has_iter = $crate::__private::HasIterator::<false>;
         $crate::pounded_var_names!{quote_bind_into_iter!(has_iter) () $($inner)*}
-        let _: $crate::__private::HasIterator = has_iter;
+        <_ as $crate::__private::CheckHasIterator<true>>::check(has_iter);
         while true {
             $crate::pounded_var_names!{quote_bind_next_or_break!() () $($inner)*}
             $crate::quote_each_token_spanned!{$tokens $span $($inner)*}
@@ -972,9 +972,9 @@
     ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) $sep:tt *) => {{
         use $crate::__private::ext::*;
         let mut _i = 0usize;
-        let has_iter = $crate::__private::ThereIsNoIteratorInRepetition;
+        let has_iter = $crate::__private::HasIterator::<false>;
         $crate::pounded_var_names!{quote_bind_into_iter!(has_iter) () $($inner)*}
-        let _: $crate::__private::HasIterator = has_iter;
+        <_ as $crate::__private::CheckHasIterator<true>>::check(has_iter);
         while true {
             $crate::pounded_var_names!{quote_bind_next_or_break!() () $($inner)*}
             if _i > 0 {
diff --git a/third_party/rust/chromium_crates_io/vendor/quote-v1/src/runtime.rs b/third_party/rust/chromium_crates_io/vendor/quote-v1/src/runtime.rs
index c704ca8..0c5053e 100644
--- a/third_party/rust/chromium_crates_io/vendor/quote-v1/src/runtime.rs
+++ b/third_party/rust/chromium_crates_io/vendor/quote-v1/src/runtime.rs
@@ -18,37 +18,49 @@
 pub type TokenStream = proc_macro2::TokenStream;
 
 #[doc(hidden)]
-pub struct HasIterator; // True
+pub struct HasIterator<const B: bool>;
+
+impl BitOr<HasIterator<false>> for HasIterator<false> {
+    type Output = HasIterator<false>;
+    fn bitor(self, _rhs: HasIterator<false>) -> HasIterator<false> {
+        HasIterator::<false>
+    }
+}
+
+impl BitOr<HasIterator<false>> for HasIterator<true> {
+    type Output = HasIterator<true>;
+    fn bitor(self, _rhs: HasIterator<false>) -> HasIterator<true> {
+        HasIterator::<true>
+    }
+}
+
+impl BitOr<HasIterator<true>> for HasIterator<false> {
+    type Output = HasIterator<true>;
+    fn bitor(self, _rhs: HasIterator<true>) -> HasIterator<true> {
+        HasIterator::<true>
+    }
+}
+
+impl BitOr<HasIterator<true>> for HasIterator<true> {
+    type Output = HasIterator<true>;
+    fn bitor(self, _rhs: HasIterator<true>) -> HasIterator<true> {
+        HasIterator::<true>
+    }
+}
+
 #[doc(hidden)]
-pub struct ThereIsNoIteratorInRepetition; // False
-
-impl BitOr<ThereIsNoIteratorInRepetition> for ThereIsNoIteratorInRepetition {
-    type Output = ThereIsNoIteratorInRepetition;
-    fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition {
-        ThereIsNoIteratorInRepetition
-    }
+#[cfg_attr(
+    not(no_diagnostic_namespace),
+    diagnostic::on_unimplemented(
+        message = "repetition contains no interpolated value that is an iterator",
+        label = "none of the values interpolated inside this repetition are iterable"
+    )
+)]
+pub trait CheckHasIterator<const B: bool>: Sized {
+    fn check(self) {}
 }
 
-impl BitOr<ThereIsNoIteratorInRepetition> for HasIterator {
-    type Output = HasIterator;
-    fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator {
-        HasIterator
-    }
-}
-
-impl BitOr<HasIterator> for ThereIsNoIteratorInRepetition {
-    type Output = HasIterator;
-    fn bitor(self, _rhs: HasIterator) -> HasIterator {
-        HasIterator
-    }
-}
-
-impl BitOr<HasIterator> for HasIterator {
-    type Output = HasIterator;
-    fn bitor(self, _rhs: HasIterator) -> HasIterator {
-        HasIterator
-    }
-}
+impl CheckHasIterator<true> for HasIterator<true> {}
 
 /// Extension traits used by the implementation of `quote!`. These are defined
 /// in separate traits, rather than as a single trait due to ambiguity issues.
@@ -58,8 +70,7 @@
 /// the returned value should be idempotent.
 #[doc(hidden)]
 pub mod ext {
-    use super::RepInterp;
-    use super::{HasIterator as HasIter, ThereIsNoIteratorInRepetition as DoesNotHaveIter};
+    use super::{HasIterator, RepInterp};
     use crate::ToTokens;
     use alloc::collections::btree_set::{self, BTreeSet};
     use core::slice;
@@ -67,8 +78,8 @@
     /// Extension trait providing the `quote_into_iter` method on iterators.
     #[doc(hidden)]
     pub trait RepIteratorExt: Iterator + Sized {
-        fn quote_into_iter(self) -> (Self, HasIter) {
-            (self, HasIter)
+        fn quote_into_iter(self) -> (Self, HasIterator<true>) {
+            (self, HasIterator::<true>)
         }
     }
 
@@ -81,13 +92,13 @@
     pub trait RepToTokensExt {
         /// Pretend to be an iterator for the purposes of `quote_into_iter`.
         /// This allows repeated calls to `quote_into_iter` to continue
-        /// correctly returning DoesNotHaveIter.
+        /// correctly returning HasIterator<false>.
         fn next(&self) -> Option<&Self> {
             Some(self)
         }
 
-        fn quote_into_iter(&self) -> (&Self, DoesNotHaveIter) {
-            (self, DoesNotHaveIter)
+        fn quote_into_iter(&self) -> (&Self, HasIterator<false>) {
+            (self, HasIterator::<false>)
         }
     }
 
@@ -99,13 +110,13 @@
     pub trait RepAsIteratorExt<'q> {
         type Iter: Iterator;
 
-        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter);
+        fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator<true>);
     }
 
     impl<'q, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &T {
         type Iter = T::Iter;
 
-        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+        fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator<true>) {
             <T as RepAsIteratorExt>::quote_into_iter(*self)
         }
     }
@@ -113,7 +124,7 @@
     impl<'q, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &mut T {
         type Iter = T::Iter;
 
-        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+        fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator<true>) {
             <T as RepAsIteratorExt>::quote_into_iter(*self)
         }
     }
@@ -121,39 +132,39 @@
     impl<'q, T: 'q> RepAsIteratorExt<'q> for [T] {
         type Iter = slice::Iter<'q, T>;
 
-        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
-            (self.iter(), HasIter)
+        fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator<true>) {
+            (self.iter(), HasIterator::<true>)
         }
     }
 
     impl<'q, T: 'q, const N: usize> RepAsIteratorExt<'q> for [T; N] {
         type Iter = slice::Iter<'q, T>;
 
-        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
-            (self.iter(), HasIter)
+        fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator<true>) {
+            (self.iter(), HasIterator::<true>)
         }
     }
 
     impl<'q, T: 'q> RepAsIteratorExt<'q> for Vec<T> {
         type Iter = slice::Iter<'q, T>;
 
-        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
-            (self.iter(), HasIter)
+        fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator<true>) {
+            (self.iter(), HasIterator::<true>)
         }
     }
 
     impl<'q, T: 'q> RepAsIteratorExt<'q> for BTreeSet<T> {
         type Iter = btree_set::Iter<'q, T>;
 
-        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
-            (self.iter(), HasIter)
+        fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator<true>) {
+            (self.iter(), HasIterator::<true>)
         }
     }
 
     impl<'q, T: RepAsIteratorExt<'q>> RepAsIteratorExt<'q> for RepInterp<T> {
         type Iter = T::Iter;
 
-        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+        fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator<true>) {
             self.0.quote_into_iter()
         }
     }
diff --git a/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/test.rs b/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/test.rs
index bf4fb88..e096780 100644
--- a/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/test.rs
+++ b/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/test.rs
@@ -200,7 +200,7 @@
         #e32
         #e64
     };
-    let expected = concat!("2.345f32 2.345f64");
+    let expected = "2.345f32 2.345f64";
     assert_eq!(expected, tokens.to_string());
 }
 
diff --git a/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/does-not-have-iter-interpolated-dup.stderr b/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/does-not-have-iter-interpolated-dup.stderr
index 99c20a56..c8d6626 100644
--- a/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/does-not-have-iter-interpolated-dup.stderr
+++ b/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/does-not-have-iter-interpolated-dup.stderr
@@ -1,11 +1,9 @@
-error[E0308]: mismatched types
+error[E0277]: repetition contains no interpolated value that is an iterator
  --> tests/ui/does-not-have-iter-interpolated-dup.rs:8:5
   |
 8 |     quote!(#(#nonrep #nonrep)*);
-  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-  |     |
-  |     expected `HasIterator`, found `ThereIsNoIteratorInRepetition`
-  |     expected due to this
-  |     here the type of `has_iter` is inferred to be `ThereIsNoIteratorInRepetition`
+  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ none of the values interpolated inside this repetition are iterable
   |
+  = help: the trait `CheckHasIterator<true>` is not implemented for `HasIterator<false>`
+          but it is implemented for `HasIterator<true>`
   = note: this error originates in the macro `$crate::quote_token_with_context` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/does-not-have-iter-interpolated.stderr b/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/does-not-have-iter-interpolated.stderr
index ef90813..e9dec69 100644
--- a/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/does-not-have-iter-interpolated.stderr
+++ b/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/does-not-have-iter-interpolated.stderr
@@ -1,11 +1,9 @@
-error[E0308]: mismatched types
+error[E0277]: repetition contains no interpolated value that is an iterator
  --> tests/ui/does-not-have-iter-interpolated.rs:8:5
   |
 8 |     quote!(#(#nonrep)*);
-  |     ^^^^^^^^^^^^^^^^^^^
-  |     |
-  |     expected `HasIterator`, found `ThereIsNoIteratorInRepetition`
-  |     expected due to this
-  |     here the type of `has_iter` is inferred to be `ThereIsNoIteratorInRepetition`
+  |     ^^^^^^^^^^^^^^^^^^^ none of the values interpolated inside this repetition are iterable
   |
+  = help: the trait `CheckHasIterator<true>` is not implemented for `HasIterator<false>`
+          but it is implemented for `HasIterator<true>`
   = note: this error originates in the macro `$crate::quote_token_with_context` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/does-not-have-iter-separated.stderr b/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/does-not-have-iter-separated.stderr
index 7c6e30f2..60d237b 100644
--- a/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/does-not-have-iter-separated.stderr
+++ b/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/does-not-have-iter-separated.stderr
@@ -1,10 +1,9 @@
-error[E0308]: mismatched types
+error[E0277]: repetition contains no interpolated value that is an iterator
  --> tests/ui/does-not-have-iter-separated.rs:4:5
   |
 4 |     quote!(#(a b),*);
-  |     ^^^^^^^^^^^^^^^^
-  |     |
-  |     expected `HasIterator`, found `ThereIsNoIteratorInRepetition`
-  |     expected due to this
+  |     ^^^^^^^^^^^^^^^^ none of the values interpolated inside this repetition are iterable
   |
+  = help: the trait `CheckHasIterator<true>` is not implemented for `HasIterator<false>`
+          but it is implemented for `HasIterator<true>`
   = note: this error originates in the macro `$crate::quote_token_with_context` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/does-not-have-iter.stderr b/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/does-not-have-iter.stderr
index 0b13e5c..51f303367 100644
--- a/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/does-not-have-iter.stderr
+++ b/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/does-not-have-iter.stderr
@@ -1,10 +1,9 @@
-error[E0308]: mismatched types
+error[E0277]: repetition contains no interpolated value that is an iterator
  --> tests/ui/does-not-have-iter.rs:4:5
   |
 4 |     quote!(#(a b)*);
-  |     ^^^^^^^^^^^^^^^
-  |     |
-  |     expected `HasIterator`, found `ThereIsNoIteratorInRepetition`
-  |     expected due to this
+  |     ^^^^^^^^^^^^^^^ none of the values interpolated inside this repetition are iterable
   |
+  = help: the trait `CheckHasIterator<true>` is not implemented for `HasIterator<false>`
+          but it is implemented for `HasIterator<true>`
   = note: this error originates in the macro `$crate::quote_token_with_context` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/not-repeatable.stderr b/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/not-repeatable.stderr
index 26932bbf..d5e13b04 100644
--- a/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/not-repeatable.stderr
+++ b/third_party/rust/chromium_crates_io/vendor/quote-v1/tests/ui/not-repeatable.stderr
@@ -17,18 +17,26 @@
           `&mut Ipv4Addr: Iterator`
           which is required by `&mut Ipv4Addr: ext::RepIteratorExt`
 note: the traits `Iterator` and `ToTokens` must be implemented
- --> src/to_tokens.rs
-  |
-  | pub trait ToTokens {
-  | ^^^^^^^^^^^^^^^^^^
-  |
- ::: $RUST/core/src/iter/traits/iterator.rs
+ --> $RUST/core/src/iter/traits/iterator.rs
   |
   | pub trait Iterator {
   | ^^^^^^^^^^^^^^^^^^
+  |
+ ::: src/to_tokens.rs
+  |
+  | pub trait ToTokens {
+  | ^^^^^^^^^^^^^^^^^^
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following traits define an item `quote_into_iter`, perhaps you need to implement one of them:
           candidate #1: `ext::RepAsIteratorExt`
           candidate #2: `ext::RepIteratorExt`
           candidate #3: `ext::RepToTokensExt`
   = note: this error originates in the macro `$crate::quote_bind_into_iter` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0282]: type annotations needed
+ --> tests/ui/not-repeatable.rs:7:13
+  |
+7 |     let _ = quote! { #(#ip)* };
+  |             ^^^^^^^^^^^^^^^^^^ cannot infer type
+  |
+  = note: this error originates in the macro `$crate::quote_bind_next_or_break` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/third_party/rust/quote/v1/BUILD.gn b/third_party/rust/quote/v1/BUILD.gn
index 9cf7854..303badca 100644
--- a/third_party/rust/quote/v1/BUILD.gn
+++ b/third_party/rust/quote/v1/BUILD.gn
@@ -31,7 +31,7 @@
   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"
+  cargo_pkg_version = "1.0.41"
 
   allow_unsafe = false
 
@@ -40,6 +40,9 @@
     "default",
     "proc-macro",
   ]
+  build_root = "//third_party/rust/chromium_crates_io/vendor/quote-v1/build.rs"
+  build_sources =
+      [ "//third_party/rust/chromium_crates_io/vendor/quote-v1/build.rs" ]
 
   #####################################################################
   # Tweaking which GN `config`s apply to this target.
diff --git a/third_party/rust/quote/v1/README.chromium b/third_party/rust/quote/v1/README.chromium
index b7c10bdd..a9ffe7f 100644
--- a/third_party/rust/quote/v1/README.chromium
+++ b/third_party/rust/quote/v1/README.chromium
@@ -1,7 +1,7 @@
 Name: quote
 URL: https://crates.io/crates/quote
-Version: 1.0.40
-Revision: ab1e92c27a492e6077e203a6f85496bb4b1522e8
+Version: 1.0.41
+Revision: 594c865ce817b4adb5863713e4fa3749fbf47f0a
 Update Mechanism: Manual
 License: Apache-2.0
 License File: //third_party/rust/chromium_crates_io/vendor/quote-v1/LICENSE-APACHE
diff --git a/third_party/skia b/third_party/skia
index 93e2cb6..b8420264 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 93e2cb6281cb04bcc3d30bdb36af9b259b322480
+Subproject commit b842026480e0d5e5547e5d6359a6a44e5692aff1
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps
index 7d9b006..edacf51 160000
--- a/third_party/vulkan-deps
+++ b/third_party/vulkan-deps
@@ -1 +1 @@
-Subproject commit 7d9b006a1969c0b9f713373084935addfdd8d994
+Subproject commit edacf5135c8db8f952c32279bc4a0afcb5bde5a7
diff --git a/third_party/vulkan-validation-layers/src b/third_party/vulkan-validation-layers/src
index dc5dea7..cc388e8 160000
--- a/third_party/vulkan-validation-layers/src
+++ b/third_party/vulkan-validation-layers/src
@@ -1 +1 @@
-Subproject commit dc5dea72aba1c3d1e27a4db2bb68acb0f62d336a
+Subproject commit cc388e801f874ed61e6c78bb1403d24e011255ab
diff --git a/third_party/webrtc b/third_party/webrtc
index 49ed555..39e1a7c 160000
--- a/third_party/webrtc
+++ b/third_party/webrtc
@@ -1 +1 @@
-Subproject commit 49ed5557b49af2b6d7729b8cbfab1900384abf1e
+Subproject commit 39e1a7ca166e88e458205d295b52e2360e86d400
diff --git a/tools/clang/spanify/evaluate_patches.py b/tools/clang/spanify/evaluate_patches.py
index d376651f..3862729 100755
--- a/tools/clang/spanify/evaluate_patches.py
+++ b/tools/clang/spanify/evaluate_patches.py
@@ -252,7 +252,7 @@
 
 # Produce a full rewrite, and store individual patches below ~/scratch/patch_*
 rewrite_script = "./tools/clang/spanify/rewrite-multiple-platforms.sh"
-print(f"${rewrite_script} --platform=${platform}")
+print(f"{rewrite_script} --platform={platform}")
 run(f"{rewrite_script} --platform={platform}")
 
 run("git reset --hard origin/main")  # Restore source code.
diff --git a/tools/clang/spanify/rewrite-multiple-platforms.sh b/tools/clang/spanify/rewrite-multiple-platforms.sh
index d9db59a3..77b8ea0a 100755
--- a/tools/clang/spanify/rewrite-multiple-platforms.sh
+++ b/tools/clang/spanify/rewrite-multiple-platforms.sh
@@ -108,6 +108,7 @@
     mv third_party/llvm-build third_party/llvm-build-upstream
   else
     echo "*** Build is already saved ***"
+    echo "*** If you don't expect this you might need to delete and resync ***"
   fi
   if [ $INCREMENTAL_CLANG_BUILD = true ]
   then
@@ -236,6 +237,21 @@
     mkdir -p "$OUT_DIR"
     args_for_platform "$PLATFORM" > "$OUT_DIR/args.gn"
 
+    if [ $PLATFORM = "mac" ]; then
+      # You can not build libclang_re.osx.a without mac, luckily we don't need
+      # to change it for the rewrite so just "restore" the version from the
+      # saved build regardless of platform.
+      LIBCLANG="Release+Asserts/lib/clang"
+      DARWIN_RT="lib/darwin"
+      for path in $(ls -d third_party/llvm-build-upstream/${LIBCLANG}/*); do
+        # the basename is the clang version (like "22")
+        DIR=`basename ${path}`
+        mkdir -p "third_party/llvm-build/${LIBCLANG}/${DIR}/${DARWIN_RT}"
+        cp third_party/llvm-build-upstream/${LIBCLANG}/${DIR}/${DARWIN_RT}/* \
+           third_party/llvm-build/${LIBCLANG}/${DIR}/${DARWIN_RT}/
+      done
+    fi
+
     # Build generated files that a successful compilation depends on.
     echo "*** Preparing targets for $PLATFORM ***"
     gn gen $OUT_DIR
diff --git a/tools/jj/bug.py b/tools/jj/bug.py
new file mode 100755
index 0000000..0bb79a8
--- /dev/null
+++ b/tools/jj/bug.py
@@ -0,0 +1,214 @@
+#!/usr/bin/env python3
+
+# Copyright 2025 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import logging
+import re
+import shutil
+import subprocess
+import sys
+import util
+
+_FIND_TRAILER = '''self.trailers()
+.filter(|trailer| trailer.key().lower() == "{}")
+.map(|trailer| trailer.value())
+.join(",")'''
+
+_BUGGED_MISSING_ERR = '''\
+Searching for bugs requires the CLI tool "bugged" to be installed.
+This tool is only available to Googlers (see go/bugged for install instructions)
+'''
+
+
+def _calculate_bugs(bugs: str) -> set[str]:
+  bugs = set(bugs.split(','))
+  # The template produces ,, if some parents don't have bugs.
+  bugs.discard('')
+  return bugs
+
+
+def _search_bugs(query: str | None):
+  args = [
+      'bugged', 'search', '--error-if-not-found=true',
+      '--columns=issue,reporter,assignee,status,summary'
+  ]
+  if query:
+    args.append(query)
+  ps = util.run_command(
+      args,
+      stdout=subprocess.PIPE,
+      check=False,
+      text=True,
+  )
+  if ps.returncode == 5:  # No results found
+    print('No results found. Try another query?')
+    return _search_bugs(input('>>> '))
+  elif ps.returncode != 0:
+    print('Issue tracker search failed', file=sys.stderr)
+    exit(1)
+
+  # The first column is the bug number. We need this internally, but don't want
+  # to show it to the user.
+  lines = [
+      re.split(r'\s+', line, maxsplit=1)
+      for line in ps.stdout.rstrip().split('\n')
+  ]
+  print(f'#  {lines[0][1]}')
+  issues = {}
+  # Reverse it because we want the important information to be at the bottom.
+  # We do this since the prompt is at the bottom.
+  for i, (issue, line) in reversed(list(enumerate(lines))[1:]):
+    issues[str(i)] = issue
+    fmt = f'{i:>2} {line}'
+    # Print every second line in cyan so you can easily line up the numbers
+    # with the summary
+    print(f'\033[36m{fmt}\033[0m' if i % 2 else fmt)
+
+  # Maybe someone with experience with TUIs could improve on the UX, but this
+  # works pretty well and is much easier to code.
+  print('Type the number in the left column to select an issue')
+  print('Type "q [query]" to search for something different')
+  while True:
+    answer = input('>>> ')
+    if answer.startswith('q '):
+      return _search_bugs(answer.removeprefix('q '))
+    elif answer == '':
+      # Run the default query
+      return _search_bugs(None)
+    elif answer in issues:
+      return issues[answer]
+    print('Invalid response')
+
+
+def _add_handler(args, revs: str):
+  direct = {
+      x['change_id']
+      for x in util.jj_log(
+          revisions=f'{revs}',
+          templates={
+              'change_id': 'change_id',
+          },
+          ignore_working_copy=True,
+      )
+  }
+
+  ancestors = util.jj_log(
+      revisions=f'mutable()::({revs})',
+      templates={
+          'change_id': 'change_id',
+          'parents': util.MUTABLE_PARENTS,
+          'trailers': 'trailers',
+          'desc': 'description',
+          'bugs': _FIND_TRAILER.format('bug'),
+          'fixed': _FIND_TRAILER.format('fixed'),
+      },
+      ignore_working_copy=True,
+  )
+
+  revs = {rev['change_id']: rev for rev in ancestors}
+
+  for rev in ancestors:
+    rev['fixed'] = _calculate_bugs(rev['fixed'])
+    rev['bugs'] = _calculate_bugs(rev['bugs'])
+
+  bugs = set(args.bug)
+
+  if args.query or (not bugs and not args.inherit):
+    if args.query:
+      print('Searching for bugs on issue tracker...')
+    else:
+      print('No bugs provided. Searching for bugs on issue tracker...')
+    bugged = shutil.which('bugged')
+    if bugged is None:
+      print(_BUGGED_MISSING_ERR, file=sys.stderr)
+      exit(1)
+    bugs.add(_search_bugs(args.query))
+
+  for rev in reversed(ancestors):
+    if rev['change_id'] not in direct:
+      # Suppose you have A <- B <- C:
+      # When running `jj bug add --inherit -r C`, C should inherit from B
+      # When running `jj bug add --inherit -r B|C`, C should inherit from B,
+      # which should have already inherited from A.
+      continue
+    bugs_to_add = set(bugs)
+    if args.inherit:
+      # This doesn't need to be done recursively because of the toposort
+      # guaruntee of `jj log`
+      if rev['parents']:
+        for change_id in rev['parents'].split(','):
+          bugs_to_add.update(revs[change_id]['bugs'])
+
+    bugs_to_add -= rev['bugs']
+    bugs_to_add -= rev['fixed']
+    (rev['fixed'] if args.fixed else rev['bugs']).update(bugs_to_add)
+
+    # Skip the ones we already have
+    tag = 'Fixed' if args.fixed else 'Bug'
+    # We may not need to add bugs, especially in the case of inherit.
+    if bugs_to_add:
+      util.add_trailers(
+          rev=rev,
+          trailers={tag: [','.join(bugs_to_add)]},
+          commit=True,
+      )
+
+
+def main(args):
+  logging.basicConfig(level=logging.getLevelNamesMapping()[args.verbosity])
+
+  revs = util.join_revsets(args.revision)
+  args.func(args, revs)
+
+
+if __name__ == '__main__':
+  parser = argparse.ArgumentParser()
+  parser.add_argument(
+      '--verbosity',
+      help='Verbosity of logging',
+      default='INFO',
+      choices=logging.getLevelNamesMapping().keys(),
+      type=lambda x: x.upper(),
+  )
+
+  subparsers = parser.add_subparsers()
+
+  parser_add = subparsers.add_parser('add')
+  parser_add.set_defaults(func=_add_handler)
+  parser_add.add_argument(
+      '-r',
+      '--revision',
+      help='The revisions to add the bug to',
+      nargs='+',
+  )
+  parser_add.add_argument(
+      '-f',
+      '--fixed',
+      help='Mark the revision as fixing the bug',
+      action='store_true',
+  )
+  parser_add.add_argument(
+      '-i',
+      '--inherit',
+      help='Inherit the bug from parent commits. Bugs are not transitively ' +
+      'inherited unless the parent is also part of -r',
+      action='store_true',
+  )
+  parser_add.add_argument(
+      '-b',
+      '--bug',
+      help='The bug to add to the revisions',
+      nargs='*',
+      default=[],
+  )
+  parser_add.add_argument(
+      '-q',
+      '--query',
+      help='Query to use when searching for a bug in issue tracker',
+      default=None,
+  )
+
+  main(parser.parse_args())
diff --git a/tools/jj/config.toml b/tools/jj/config.toml
index 4452601..e5d9bf6d 100644
--- a/tools/jj/config.toml
+++ b/tools/jj/config.toml
@@ -11,6 +11,9 @@
 "cr-upload" = ["util", "exec", "tools/jj/upload.py", "--"]
 "upload" = ["cr-upload"]
 
+"cr-bug" = ["util", "exec", "tools/jj/bug.py", "--"]
+"bug" = ["cr-bug"]
+
 [revset-aliases]
 "trunk()" = "main@origin"
 "immutable_heads()" = "remote_bookmarks() | tags()"
diff --git a/tools/jj/upload.py b/tools/jj/upload.py
index 926b598..ea0438b5 100755
--- a/tools/jj/upload.py
+++ b/tools/jj/upload.py
@@ -12,15 +12,11 @@
 from util import jj_log
 from util import run_command
 from util import run_jj
+from util import join_revsets
 from util import split_description
 
 _IMMUTABLE_PARENTS = 'parents.filter(|p| p.immutable()).map(|p| p.commit_id())'
 _MUTABLE_PARENTS = 'parents.filter(|p| !p.immutable()).map(|p| p.commit_id())'
-_NAME = '''change_id.short() ++
-if(current_working_copy, " (@)") ++
-" " ++
-description.first_line()
-'''
 
 
 def fatal(*args, **kwargs):
@@ -76,10 +72,8 @@
   if len(revs) == 0:
     rev = '@'
     implicit_revs = True
-  elif len(revs) == 1:
-    rev = revs[0]
   else:
-    rev = '|'.join(f'({r})' for r in revs)
+    rev = join_revsets(revs)
 
   snapshot_taken = False
 
@@ -91,7 +85,6 @@
   to_upload = jj_log(
       revisions=f'mutable()::({rev})',
       templates={
-          'name': _NAME,
           'commit_id': 'commit_id',
           'empty': 'empty',
           'desc': 'description',
@@ -124,14 +117,13 @@
     if 'Bug' not in trailers and 'Fixed' not in trailers:
       logging.warning(
           'Change %s has no associated Bug. If this change has an associated ' +
-          'bug, add Bug: [bug number] or Fixed: [bug number].', name)
+          'bug, run `jj bug add [--inherit]`', name)
 
   if not args.bypass_hooks:
     # Find the commits that `git cl presubmit` will actually run on
     got_presubmits = jj_log(
         revisions=f'mutable()::@',
         templates={
-            'name': _NAME,
             'empty': 'empty',
             'immutable_parents': _IMMUTABLE_PARENTS
         },
diff --git a/tools/jj/util.py b/tools/jj/util.py
index 556a995..792ee21 100644
--- a/tools/jj/util.py
+++ b/tools/jj/util.py
@@ -14,6 +14,16 @@
 _COMMA = '\x1f'
 
 _TRAILER = re.compile(r'([a-zA-Z0-9\-_]+): (.*)')
+_CHANGE_PRETTY = '''change_id.short() ++
+if(current_working_copy, " (@)") ++
+" " ++
+description.first_line()
+'''
+
+MUTABLE_PARENTS = '''parents
+.filter(|c| !c.immutable())
+.map(|p| p.change_id())
+.join(",")'''
 
 
 def run_command(args: list[str],
@@ -52,6 +62,7 @@
      {'change_id': 'b', 'parents': '<parent of b's id>'}
   ]
   """
+  templates.setdefault('name', _CHANGE_PRETTY)
   # Start by assigning indexes based on the field name.
   fields, templates = zip(*sorted(templates.items()))
   # We're just creating a jj template that outputs CSV files.
@@ -96,3 +107,37 @@
   if not trailers:
     return description, {}
   return user_desc, trailers
+
+
+def join_revsets(revs: list[str]):
+  if len(revs) == 1:
+    return revs[0]
+  else:
+    return ' | '.join(f'({r})' for r in revs)
+
+
+def add_trailers(rev: dict[str, str], trailers: dict[str, list[str]],
+                 commit: bool) -> str:
+  old_desc = rev['desc'].rstrip()
+  old_trailers = rev['trailers'].rstrip()
+  assert old_desc.endswith(old_trailers)
+  old_desc = old_desc.removesuffix(old_trailers).rstrip()
+  if not old_desc:
+    # We need a non-empty first line in order for it to be treated as a trailer.
+    old_desc = 'TODO: add description'
+
+  if old_trailers:
+    lines = [old_desc, '', old_trailers]
+  else:
+    lines = [old_desc, '']
+  for k, vs in trailers.items():
+    for v in vs:
+      lines.append(f'{k}: {v}')
+  new_desc = '\n'.join(lines)
+
+  if commit:
+    run_jj(
+        ['describe', '-m', new_desc, '-r', rev['change_id']],
+        ignore_working_copy=True,
+    )
+  return new_desc
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index dd2b319..f01ac99 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -9077,7 +9077,6 @@
   <int value="-1827599944" label="QueryTilesLocalOrdering:enabled"/>
   <int value="-1827136280" label="AndroidComposeplate:disabled"/>
   <int value="-1826649921" label="ContextualSuggestionsButton:disabled"/>
-  <int value="-1826309726" label="ArcCustomTabsExperiment:disabled"/>
   <int value="-1825184776" label="TangibleSync:disabled"/>
   <int value="-1824647193" label="HelpAppOnboardingRevamp:disabled"/>
   <int value="-1824540307" label="NotificationWidthIncrease:enabled"/>
@@ -9858,6 +9857,8 @@
   <int value="-1538752676" label="IncognitoBrandConsistencyForAndroid:enabled"/>
   <int value="-1538734579"
       label="AutofillEnableSendingBcnInGetUploadDetails:disabled"/>
+  <int value="-1538553397"
+      label="AutofillEnabledKeyboardAccessoryChipRedesign:disabled"/>
   <int value="-1538492024" label="OmniboxReverseAnswers:enabled"/>
   <int value="-1538476948"
       label="VisitedURLRankingHistoryVisibilityScoreFilter:disabled"/>
@@ -12240,6 +12241,8 @@
   <int value="-695687521" label="double-buffer-compositing"/>
   <int value="-694943768" label="ContextualSearchSuppressShortView:disabled"/>
   <int value="-694783082" label="MostVisitedTilesSelectExistingTab:enabled"/>
+  <int value="-694727287"
+      label="AutofillEnabledKeyboardAccessoryChipRedesign:enabled"/>
   <int value="-694622753" label="VizHitTest:disabled"/>
   <int value="-694601891" label="ToastRefinements:enabled"/>
   <int value="-694187898" label="MashOopViz:disabled"/>
@@ -13618,7 +13621,6 @@
   <int value="-189740492"
       label="PolicyIndicationForManagedDefaultSearch:disabled"/>
   <int value="-189543840" label="PageActionsMigration:disabled"/>
-  <int value="-189478545" label="ArcCustomTabsExperiment:enabled"/>
   <int value="-188439713" label="disable-video-capture-use-gpu-memory-buffer"/>
   <int value="-187536302" label="TabstripComboButton:enabled"/>
   <int value="-187506528" label="(Obsolete) CrOSSuspendToDisk:enabled"/>
@@ -14756,6 +14758,8 @@
   <int value="218317796" label="CastStreamingVp9:enabled"/>
   <int value="218890378" label="ManualSaving:disabled"/>
   <int value="219117936" label="AllowReaderForAccessibility:enabled"/>
+  <int value="219129954"
+      label="AutofillEnableKeyboardAccessoryChipRedesign:disabled"/>
   <int value="219162425" label="TabClosureMethodRefactor:disabled"/>
   <int value="219384037" label="ESimPolicy:disabled"/>
   <int value="220654375" label="SearchResultInlineIcon:disabled"/>
@@ -19650,6 +19654,8 @@
   <int value="1936810062" label="WebVrVsyncAlign:enabled"/>
   <int value="1937435913"
       label="CryptAuthV2DedupDeviceLastActivityTime:disabled"/>
+  <int value="1937531194"
+      label="AutofillEnableKeyboardAccessoryChipRedesign:enabled"/>
   <int value="1937660673" label="PrivacySandboxEqualizedPromptButtons:enabled"/>
   <int value="1937905990" label="AutofillCenterAlignedSuggestions:enabled"/>
   <int value="1938279796" label="PromosOnLocalNtp:disabled"/>
diff --git a/tools/metrics/histograms/metadata/accessibility/enums.xml b/tools/metrics/histograms/metadata/accessibility/enums.xml
index 505821f..8f8fd38 100644
--- a/tools/metrics/histograms/metadata/accessibility/enums.xml
+++ b/tools/metrics/histograms/metadata/accessibility/enums.xml
@@ -1727,7 +1727,7 @@
   <int value="39"
       label="Open developer tools element inspection (not implemented)"/>
   <int value="40" label="Toggle showing developer tools (not implemented)"/>
-  <int value="41" label="View page source (not implemented)"/>
+  <int value="41" label="View page source"/>
   <int value="42" label="Open task manager"/>
   <int value="43" label="Save page"/>
   <int value="44" label="Show downloads"/>
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index fb68689..13ccc38c 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -1224,6 +1224,19 @@
   </summary>
 </histogram>
 
+<histogram name="Android.BrowserControls.RenderDrivenShowConstraint"
+    enum="Boolean" expires_after="2026-04-01">
+  <owner>wenyufu@chromium.org</owner>
+  <owner>clank-app-team@google.com</owner>
+  <summary>
+    Records when browser controls constraint is set to &quot;SHOWN&quot;,
+    whether the render is capable to drive the browser controls show animation.
+    The record is used for crbug.com/449011189. Recorded after native is fully
+    initialized and when feature BrowserControlsRenderDrivenShowConstraint is
+    enabled.
+  </summary>
+</histogram>
+
 <histogram name="Android.BrowsingDataModel.ModelDestructionTime" units="ms"
     expires_after="2025-12-14">
   <owner>alimariam@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/ash/enums.xml b/tools/metrics/histograms/metadata/ash/enums.xml
index 43270ec6..c32f9541 100644
--- a/tools/metrics/histograms/metadata/ash/enums.xml
+++ b/tools/metrics/histograms/metadata/ash/enums.xml
@@ -2152,6 +2152,7 @@
   <int value="10" label="Failed in guest or public user session"/>
   <int value="11" label="Failed as another user is active in MUSI scenario"/>
   <int value="12" label="Failed as windows moved from other users are visible"/>
+  <int value="13" label="Failed as user session is not active"/>
 </enum>
 
 <enum name="SeaPenActionMenuItem">
diff --git a/tools/metrics/histograms/metadata/net/enums.xml b/tools/metrics/histograms/metadata/net/enums.xml
index 8812aa0..27defeb 100644
--- a/tools/metrics/histograms/metadata/net/enums.xml
+++ b/tools/metrics/histograms/metadata/net/enums.xml
@@ -3036,6 +3036,7 @@
   <int value="14" label="InvalidArgument"/>
   <int value="15" label="BodyEndMismatch"/>
   <int value="16" label="FailedForTesting"/>
+  <int value="17" label="Aborted"/>
 </enum>
 
 <!-- LINT.ThenChange(//net/disk_cache/sql/sql_persistent_store.h:SqlDiskCacheStoreError) -->
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index 59ceadf..881dd8a 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -7615,6 +7615,20 @@
   </token>
 </histogram>
 
+<histogram name="Net.SqlDiskCache.Backend.{MethodName}.PostingDelay"
+    units="microseconds" expires_after="2026-03-08">
+  <owner>horo@chromium.org</owner>
+  <owner>src/net/OWNERS</owner>
+  <summary>
+    Measures the time delay from posting a task to its execution for the method
+    of the SQL-based disk cache backend. This metric is recorded immediately
+    before the logic for the method is executed. It helps diagnose potential
+    delays caused by task queueing. The histogram is not reported on Windows
+    machines without high resolution clocks.
+  </summary>
+  <token key="MethodName" variants="SqlPersistentStoreMethodName"/>
+</histogram>
+
 <histogram name="Net.SqlDiskCache.Backend.{MethodName}.Result"
     enum="SqlDiskCacheStoreError" expires_after="2026-02-22">
   <owner>horo@chromium.org</owner>
@@ -7711,6 +7725,30 @@
   </summary>
 </histogram>
 
+<histogram name="Net.SqlDiskCache.OptimisticWrite.Result"
+    enum="SqlDiskCacheStoreError" expires_after="2026-03-08">
+  <owner>horo@chromium.org</owner>
+  <owner>src/net/OWNERS</owner>
+  <summary>
+    Records the result of an optimistic write operation to the SQL disk cache.
+    This is recorded when the optimistic write completes on the background
+    thread, indicating whether the underlying persistent store operation
+    succeeded or failed.
+  </summary>
+</histogram>
+
+<histogram name="Net.SqlDiskCache.Write.IsOptimistic" enum="Boolean"
+    expires_after="2026-03-22">
+  <owner>horo@chromium.org</owner>
+  <owner>src/net/OWNERS</owner>
+  <summary>
+    Records whether a disk cache write operation was performed optimistically
+    (synchronously) or not. True indicates the write was optimistic, false
+    indicates it was queued for asynchronous processing. This metric will be
+    emitted every time a cache entry write happens.
+  </summary>
+</histogram>
+
 <histogram name="Net.SSL.ECHResult" enum="SSLECHResult"
     expires_after="2026-03-01">
   <owner>davidben@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml
index 8d40cf3..5c15e28 100644
--- a/tools/metrics/histograms/metadata/signin/histograms.xml
+++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -1777,6 +1777,9 @@
     <variant name="Declined"
         summary="the user declined the flow to enable history sync by tapping
                  on the decline button in the history sync screen"/>
+    <variant name="Offered"
+        summary="the user was shown a button that would start the flow to
+                 enable history sync (only recorded on Desktop)"/>
     <variant name="Skipped"
         summary="the history sync screen has been skipped (due to enterprise
                  policies disabling sync, history sync, or tabs sync; or if
diff --git a/tools/metrics/histograms/metadata/stability/enums.xml b/tools/metrics/histograms/metadata/stability/enums.xml
index 3aefaf49..5e5c61f6e 100644
--- a/tools/metrics/histograms/metadata/stability/enums.xml
+++ b/tools/metrics/histograms/metadata/stability/enums.xml
@@ -497,6 +497,7 @@
   <int value="329" label="RFH_ORIGIN_TO_COMMIT_MISMATCH"/>
   <int value="330" label="RFH_CRASH_REPORT_STORAGE_SIZE_TOO_LARGE"/>
   <int value="331" label="RFH_CRASH_REPORT_STORAGE_ALREADY_INITIALIZED"/>
+  <int value="332" label="RFH_INVALID_DOCUMENT_SEQUENCE_NUMBER"/>
 </enum>
 
 <enum name="BadMessageReasonExtensions">
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index fb4e6a23..5072668 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/v52.0/linux-arm64/trace_processor_shell"
         },
         "win": {
-            "hash": "e6a95281ff2ab517cc2d0070f16b7058d51d15da",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/7d2ae96575efa97ddab72f0b962d22660c00a567/trace_processor_shell.exe"
+            "hash": "f9280d326b5a0388d14ff2e4946624b7b3d07c74",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/69bd8a4b80aca14a9f07b5443572bb34150e496c/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "46d798c1864490cbb2ee053d6eda436184470e69",
@@ -21,8 +21,8 @@
             "full_remote_path": "perfetto-luci-artifacts/ebf44e57a3b734c5281bdff53d9945805486004e/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "e9844b4b1cb3bdc35095f6767aabef68069fa386",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/b4696ebad1f8d9ed72e8e42df48474bde0551f29/trace_processor_shell"
+            "hash": "3fffdfdf6ff00dc2983c6a3c707e68ae276a3618",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/69bd8a4b80aca14a9f07b5443572bb34150e496c/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/aura/test/test_screen.cc b/ui/aura/test/test_screen.cc
index be47300..2af49ca 100644
--- a/ui/aura/test/test_screen.cc
+++ b/ui/aura/test/test_screen.cc
@@ -73,8 +73,8 @@
 void TestScreen::SetColorSpace(const gfx::ColorSpace& color_space,
                                float sdr_white_level) {
   display::Display display(GetPrimaryDisplay());
-  gfx::DisplayColorSpaces display_color_spaces(color_space,
-                                               gfx::BufferFormat::RGBA_8888);
+  gfx::DisplayColorSpaces display_color_spaces(
+      color_space, viz::SinglePlaneFormat::kRGBA_8888);
   display_color_spaces.SetSDRMaxLuminanceNits(sdr_white_level);
   display.SetColorSpaces(display_color_spaces);
   display_list().UpdateDisplay(display);
diff --git a/ui/base/x/x11_display_util.cc b/ui/base/x/x11_display_util.cc
index c8eff585..9af47cd 100644
--- a/ui/base/x/x11_display_util.cc
+++ b/ui/base/x/x11_display_util.cc
@@ -487,8 +487,8 @@
         color_space = display::GetColorSpaceFromEdid(edid_parser);
       }
 
-      display.SetColorSpaces(
-          gfx::DisplayColorSpaces(color_space, gfx::BufferFormat::BGRA_8888));
+      display.SetColorSpaces(gfx::DisplayColorSpaces(
+          color_space, viz::SinglePlaneFormat::kBGRA_8888));
     }
 
     display.set_color_depth(depth);
diff --git a/ui/display/mac/screen_mac.mm b/ui/display/mac/screen_mac.mm
index a76d09d..4be0d350 100644
--- a/ui/display/mac/screen_mac.mm
+++ b/ui/display/mac/screen_mac.mm
@@ -150,8 +150,8 @@
       }
     }
   }
-  gfx::DisplayColorSpaces display_color_spaces(icc_profile.GetColorSpace(),
-                                               gfx::BufferFormat::BGRA_8888);
+  gfx::DisplayColorSpaces display_color_spaces(
+      icc_profile.GetColorSpace(), viz::SinglePlaneFormat::kBGRA_8888);
   if (HasForceDisplayColorProfile()) {
     if (Display::HasEnsureForcedColorProfile()) {
       if (display_color_spaces != display.GetColorSpaces()) {
diff --git a/ui/display/manager/display_manager.cc b/ui/display/manager/display_manager.cc
index 241fa65..8f1e21e 100644
--- a/ui/display/manager/display_manager.cc
+++ b/ui/display/manager/display_manager.cc
@@ -1481,12 +1481,13 @@
   static Display* fake_display = nullptr;
   if (!fake_display) {
     fake_display = new Display(Display::GetDefaultDisplay());
-    // Note that if an inappropriate gfx::BufferFormat is specified in the
+    // Note that if an inappropriate format is specified in the
     // gfx::DisplayColorSpaces of the fake display, this can sometimes
     // propagate to allocation code and cause errors.
     // https://crbug.com/1057501
     gfx::DisplayColorSpaces display_color_spaces(
-        gfx::ColorSpace::CreateSRGB(), DisplaySnapshot::PrimaryFormat());
+        gfx::ColorSpace::CreateSRGB(),
+        DisplaySnapshot::PrimarySharedImageFormat());
     fake_display->SetColorSpaces(display_color_spaces);
   }
   return *fake_display;
diff --git a/ui/display/types/BUILD.gn b/ui/display/types/BUILD.gn
index 3ca5f98..4e36a910 100644
--- a/ui/display/types/BUILD.gn
+++ b/ui/display/types/BUILD.gn
@@ -32,6 +32,7 @@
 
   deps = [
     "//base",
+    "//components/viz/common/resources:shared_image_format",
     "//skia",
     "//skia:skcms",
     "//ui/gfx:buffer_types",
diff --git a/ui/display/types/DEPS b/ui/display/types/DEPS
index d58763e..ca85a2f 100644
--- a/ui/display/types/DEPS
+++ b/ui/display/types/DEPS
@@ -1,5 +1,7 @@
 include_rules = [
   "-ui",
+  "+components/viz/common/resources/shared_image_format.h",
+  "+components/viz/common/resources/shared_image_format_utils.h",
   "+ui/display/types",
   "+ui/gfx/buffer_types.h",
   "+ui/gfx/color_space.h",
diff --git a/ui/display/types/display_snapshot.cc b/ui/display/types/display_snapshot.cc
index 52a1ade..269564b 100644
--- a/ui/display/types/display_snapshot.cc
+++ b/ui/display/types/display_snapshot.cc
@@ -10,6 +10,7 @@
 
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
+#include "components/viz/common/resources/shared_image_format_utils.h"
 
 namespace display {
 
@@ -156,7 +157,13 @@
 
 // static
 gfx::BufferFormat DisplaySnapshot::PrimaryFormat() {
-  return gfx::BufferFormat::BGRA_8888;
+  return viz::SinglePlaneSharedImageFormatToBufferFormat(
+      PrimarySharedImageFormat());
+}
+
+// static
+viz::SharedImageFormat DisplaySnapshot::PrimarySharedImageFormat() {
+  return viz::SinglePlaneFormat::kBGRA_8888;
 }
 
 void DisplaySnapshot::AddIndexToDisplayId() {
diff --git a/ui/display/types/display_snapshot.h b/ui/display/types/display_snapshot.h
index 7290789..599b376f 100644
--- a/ui/display/types/display_snapshot.h
+++ b/ui/display/types/display_snapshot.h
@@ -14,6 +14,7 @@
 
 #include "base/files/file_path.h"
 #include "base/memory/raw_ptr.h"
+#include "components/viz/common/resources/shared_image_format.h"
 #include "skia/ext/skcolorspace_primaries.h"
 #include "ui/display/types/display_constants.h"
 #include "ui/display/types/display_mode.h"
@@ -154,6 +155,9 @@
   // Returns the buffer format to be used for the primary plane buffer.
   static gfx::BufferFormat PrimaryFormat();
 
+  // Returns the SharedImageFormat to be used for the primary plane buffer.
+  static viz::SharedImageFormat PrimarySharedImageFormat();
+
   // Adds |connector_index_| to bits 33-48 of |edid_display_id_|. This function
   // is not plumbed via mojom to limit and control usage across processes.
   void AddIndexToDisplayId();
diff --git a/ui/display/util/display_util.cc b/ui/display/util/display_util.cc
index 1e00a0e3..0029ef43 100644
--- a/ui/display/util/display_util.cc
+++ b/ui/display/util/display_util.cc
@@ -314,14 +314,14 @@
     const std::optional<gfx::HDRStaticMetadata>& hdr_static_metadata) {
   if (HasForceDisplayColorProfile()) {
     return gfx::DisplayColorSpaces(GetForcedDisplayColorProfile(),
-                                   DisplaySnapshot::PrimaryFormat());
+                                   DisplaySnapshot::PrimarySharedImageFormat());
   }
 
   // ChromeOS VMs (e.g. amd64-generic or betty) have INVALID Primaries; just
   // pass the color space along.
   if (!snapshot_color_space.IsValid()) {
     return gfx::DisplayColorSpaces(snapshot_color_space,
-                                   DisplaySnapshot::PrimaryFormat());
+                                   DisplaySnapshot::PrimarySharedImageFormat());
   }
 
   // Make all displays report that they have sRGB primaries. Hardware color
@@ -335,7 +335,7 @@
 
   // Use that color space for all content.
   gfx::DisplayColorSpaces display_color_spaces = gfx::DisplayColorSpaces(
-      sdr_color_space, DisplaySnapshot::PrimaryFormat());
+      sdr_color_space, DisplaySnapshot::PrimarySharedImageFormat());
 
   // Claim 10% HDR headroom if HDR is available.
   if (allow_high_bit_depth && snapshot_color_space.IsHDR()) {
diff --git a/ui/ozone/platform/wayland/host/wayland_pointer.cc b/ui/ozone/platform/wayland/host/wayland_pointer.cc
index 2b7e785..4d20b546 100644
--- a/ui/ozone/platform/wayland/host/wayland_pointer.cc
+++ b/ui/ozone/platform/wayland/host/wayland_pointer.cc
@@ -169,14 +169,7 @@
                             uint32_t time,
                             uint32_t axis,
                             wl_fixed_t value) {
-  // Wayland compositors send axis events with values in the surface coordinate
-  // space. They send a value of 10 per mouse wheel click by convention, so
-  // clients (e.g. GTK+) typically scale down by this amount to convert to
-  // discrete step coordinates. wl_pointer version 5 improves the situation by
-  // adding axis sources and discrete axis events.
-  const double kAxisValueScale = 10.0;
-  const double delta = -wl_fixed_to_double(value) / kAxisValueScale *
-                       MouseWheelEvent::kWheelDelta;
+  const double delta = -wl_fixed_to_double(value);
   const auto timestamp = wl::EventMillisecondsToTimeTicks(time);
   auto* self = static_cast<WaylandPointer*>(data);
   self->OnAxisImpl(delta, axis, timestamp, /*is_high_resolution=*/false);
diff --git a/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc b/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
index 7e2cd4a7..6b11c6c 100644
--- a/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
@@ -334,8 +334,45 @@
       ASSERT_TRUE(event->IsMouseWheelEvent());
       auto* mouse_wheel_event = event->AsMouseWheelEvent();
       EXPECT_EQ(axis == WL_POINTER_AXIS_VERTICAL_SCROLL
-                    ? gfx::Vector2d(0, -MouseWheelEvent::kWheelDelta)
-                    : gfx::Vector2d(-MouseWheelEvent::kWheelDelta, 0),
+                    ? gfx::Vector2d(0, -10) : gfx::Vector2d(-10, 0),
+                mouse_wheel_event->offset());
+      EXPECT_EQ(gfx::PointF(), mouse_wheel_event->location_f());
+      EXPECT_EQ(gfx::PointF(), mouse_wheel_event->root_location_f());
+    }
+  }
+}
+
+TEST_F(WaylandPointerTest, Axis120) {
+  SendEnter();
+
+  for (uint32_t axis :
+       {WL_POINTER_AXIS_VERTICAL_SCROLL, WL_POINTER_AXIS_HORIZONTAL_SCROLL}) {
+    for (bool send_axis_source : {false, true}) {
+      std::unique_ptr<Event> event;
+      EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+
+      PostToServerAndWait([axis, send_axis_source](
+                              wl::TestWaylandServerThread* server) {
+        auto* const pointer = server->seat()->pointer()->resource();
+
+        if (send_axis_source) {
+          // The axis source event is optional.  When it is not set within the
+          // event frame, we assume the mouse wheel.
+          wl_pointer_send_axis_source(pointer, WL_POINTER_AXIS_SOURCE_WHEEL);
+        }
+
+        // Mouse wheels generate both axis and axis_value120 events.  The value
+        // of the axis event is ignored.
+        wl_pointer_send_axis(pointer, 1003, axis, 10);
+        wl_pointer_send_axis_value120(pointer, axis, 120);
+        wl_pointer_send_frame(pointer);
+      });
+
+      ASSERT_TRUE(event);
+      ASSERT_TRUE(event->IsMouseWheelEvent());
+      auto* mouse_wheel_event = event->AsMouseWheelEvent();
+      EXPECT_EQ(axis == WL_POINTER_AXIS_VERTICAL_SCROLL
+                    ? gfx::Vector2d(0, -120) : gfx::Vector2d(-120, 0),
                 mouse_wheel_event->offset());
       EXPECT_EQ(gfx::PointF(), mouse_wheel_event->location_f());
       EXPECT_EQ(gfx::PointF(), mouse_wheel_event->root_location_f());
diff --git a/ui/webui/resources/cr_components/searchbox/searchbox_dropdown.ts b/ui/webui/resources/cr_components/searchbox/searchbox_dropdown.ts
index 993978e..dfcc007 100644
--- a/ui/webui/resources/cr_components/searchbox/searchbox_dropdown.ts
+++ b/ui/webui/resources/cr_components/searchbox/searchbox_dropdown.ts
@@ -176,12 +176,16 @@
     // If the updated selection is a new match, remove any remaining selection
     // on the previously selected match.
     if (oldSelection.line !== selection.line) {
-      this.selectableMatchElements[this.selectedMatchIndex]?.updateSelection(
-          selection);
+      const oldMatch = this.selectableMatchElements[this.selectedMatchIndex];
+      if (oldMatch) {
+        oldMatch.selection = selection;
+      }
     }
     this.selectIndex(selection.line);
-    this.selectableMatchElements[this.selectedMatchIndex]?.updateSelection(
-        selection);
+    const newMatch = this.selectableMatchElements[this.selectedMatchIndex];
+    if (newMatch) {
+      newMatch.selection = selection;
+    }
   }
 
   /**
diff --git a/ui/webui/resources/cr_components/searchbox/searchbox_match.html.ts b/ui/webui/resources/cr_components/searchbox/searchbox_match.html.ts
index 2bf560d..61146a2 100644
--- a/ui/webui/resources/cr_components/searchbox/searchbox_match.html.ts
+++ b/ui/webui/resources/cr_components/searchbox/searchbox_match.html.ts
@@ -10,7 +10,7 @@
   // clang-format off
   return html`<!--_html_template_start_-->
 <div class="container" aria-hidden="true">
-  <div id="focus-indicator"></div>
+  <div id="focus-indicator" class="${this.getFocusIndicatorCssClass_()}"></div>
   <cr-searchbox-icon id="icon" .match="${this.match}"></cr-searchbox-icon>
   <div id="text-container">
     <span id="tail-suggest-prefix" ?hidden="${!this.tailSuggestPrefix_}">
@@ -30,6 +30,7 @@
     ${this.match.keywordChipHint ? html`
       <div id="actions-focus-border">
         <cr-searchbox-action id="keyword"
+            class="${this.getKeywordCssClass_()}"
             hint="${this.match.keywordChipHint}"
             icon-path="//resources/images/icon_search.svg"
             aria-label="${this.match.keywordChipA11y}"
@@ -42,6 +43,7 @@
     ${this.match.actions.map((item, index) => html`
       <div id="actions-focus-border">
         <cr-searchbox-action id="action"
+            class="${this.getActionCssClass_(index)}"
             hint="${item.hint}"
             suggestion-contents="${item.suggestionContents}"
             icon-path="${item.iconPath}"
@@ -52,7 +54,9 @@
       </div>
     `)}
   </div>
-  <cr-icon-button id="remove" class="action-icon icon-clear" tabindex="3"
+  <cr-icon-button id="remove"
+      class="action-icon icon-clear ${this.getRemoveCssClass_()}"
+      tabindex="3"
       aria-label="${this.removeButtonAriaLabel_}"
       title="${this.removeButtonTitle_}"
       ?hidden="${!this.match.supportsDeletion}"
diff --git a/ui/webui/resources/cr_components/searchbox/searchbox_match.ts b/ui/webui/resources/cr_components/searchbox/searchbox_match.ts
index 3054ff6..1f99a0e 100644
--- a/ui/webui/resources/cr_components/searchbox/searchbox_match.ts
+++ b/ui/webui/resources/cr_components/searchbox/searchbox_match.ts
@@ -109,6 +109,8 @@
 
       match: {type: Object},
 
+      selection: {type: Object},
+
       /**
        * Index of the match in the autocomplete result. Used to inform embedder
        * of events such as deletion, click, etc.
@@ -169,6 +171,11 @@
   accessor isEntitySuggestion: boolean = false;
   accessor isRichSuggestion: boolean = false;
   accessor match: AutocompleteMatch = createAutocompleteMatch();
+  accessor selection: OmniboxPopupSelection = {
+    line: -1,
+    state: SelectionLineState.kNormal,
+    actionIndex: 0,
+  };
   accessor matchIndex: number = -1;
   accessor sideType: SideType = SideType.kDefaultPrimary;
   accessor showThumbnail: boolean = false;
@@ -390,7 +397,7 @@
   }
 
   /**
-   * Decodes the AcMatchClassificationStyle enteries encoded in the given
+   * Decodes the AcMatchClassificationStyle entries encoded in the given
    * ACMatchClassification style field, maps each entry to a CSS
    * class and returns them.
    */
@@ -438,34 +445,6 @@
         }, document.createElement('span'));
   }
 
-  updateSelection(selection: OmniboxPopupSelection) {
-    this.$['focus-indicator'].classList.toggle(
-        'selected-within',
-        selection.state !== SelectionLineState.kNormal &&
-            selection.line === this.matchIndex);
-
-    this.shadowRoot.querySelector('#keyword')
-        ?.classList.toggle(
-            'selected',
-            selection.state === SelectionLineState.kKeywordMode &&
-                selection.line === this.matchIndex);
-
-    [...this.shadowRoot.querySelectorAll(
-         '#actions-container cr-searchbox-action')]
-        .forEach((action, index) => {
-          action.classList.toggle(
-              'selected',
-              selection.state === SelectionLineState.kFocusedButtonAction &&
-                  selection.actionIndex === index &&
-                  selection.line === this.matchIndex);
-        });
-
-    this.$.remove.classList.toggle(
-        'selected',
-        selection.state === SelectionLineState.kFocusedButtonRemoveSuggestion &&
-            selection.line === this.matchIndex);
-  }
-
   private getMatchContents_(): string {
     if (!this.match) {
       return '';
@@ -513,6 +492,36 @@
     return match.swapContentsAndDescription ? match.contentsClass :
                                               match.descriptionClass;
   }
+
+  protected getFocusIndicatorCssClass_(): string {
+    return this.selection.line === this.matchIndex &&
+            this.selection.state !== SelectionLineState.kNormal ?
+        'selected-within' :
+        '';
+  }
+
+  protected getKeywordCssClass_(): string {
+    return this.selection.line === this.matchIndex &&
+            this.selection.state === SelectionLineState.kKeywordMode ?
+        'selected' :
+        '';
+  }
+
+  protected getActionCssClass_(actionIndex: number): string {
+    return this.selection.line === this.matchIndex &&
+            this.selection.state === SelectionLineState.kFocusedButtonAction &&
+            this.selection.actionIndex === actionIndex ?
+        'selected' :
+        '';
+  }
+
+  protected getRemoveCssClass_(): string {
+    return this.selection.line === this.matchIndex &&
+            this.selection.state ===
+                SelectionLineState.kFocusedButtonRemoveSuggestion ?
+        'selected' :
+        '';
+  }
 }
 
 declare global {