diff --git a/DEPS b/DEPS
index b169b18e..2d2941ee 100644
--- a/DEPS
+++ b/DEPS
@@ -269,7 +269,7 @@
   'screen_ai_windows_386': 'version:140.02',
 
   # siso CIPD package version.
-  'siso_version': 'git_revision:e5fa67c5a456c1ab932f440ddfb195a8a33c235b',
+  'siso_version': 'git_revision:887a10bc8a038d8e330d06d1ad5ae6ec646f3040',
 
   # download libaom test data
   'download_libaom_testdata': False,
@@ -291,11 +291,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': 'ac3566084be15e2d1322eeb396e76469b50d19b0',
+  'src_internal_revision': 'efb4f0a19e8ccb65722c1639bb21e0572fe9a249',
   # 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': '64e37e1ad12643dac64278b85b18d67ecb80642f',
+  'skia_revision': '39c70f883c0eb62a51a0747d3dd0df4666014ea2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -383,7 +383,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '138048fff68bb9b2f9cf114c3f3b282b789d46f1',
+  'devtools_frontend_revision': '41b0772c9f6c8fa7a57badb667e49126925806df',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -407,7 +407,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '3de4294640795796e47ab8e90dcb2c43dde62273',
+  'dawn_revision': '0b095928b31253ffc9684e460e08cc5710c2c21c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1182,7 +1182,7 @@
       'packages': [
           {
               'package': 'chromium/chrome/android/orderfiles/arm',
-              'version': '57wpPndpH3Aaj9NcaXeu2-K5lFsDQNFPP_8mvOElROIC',
+              'version': 'RgywX1RV6ppjnoTp4RN_ujmN7ZkqqDA8ZvReuHMz9Z0C',
           },
       ],
       'condition': 'checkout_android',
@@ -1193,7 +1193,7 @@
       'packages': [
           {
               'package': 'chromium/chrome/android/orderfiles/arm64',
-              'version': 'yGEa5_xOMGJpG-FeajVtT_FY7_H1Ltklc3UGktO6B4YC',
+              'version': 'cmrQHrqMtuCTO6gv3EJntbK6HMRTmu4mkyvQ8EJ11U8C',
           },
       ],
       'condition': 'checkout_android',
@@ -1370,7 +1370,7 @@
       'packages': [
         {
           'package': 'chromium/third_party/updater/chromium_linux64',
-          'version': 'version:2@1495011',
+          'version': 'version:2@1496001',
         },
       ],
   },
@@ -1416,7 +1416,7 @@
       'packages': [
         {
           'package': 'chromium/third_party/updater/chromium_win_x86',
-          'version': 'version:2@1495030',
+          'version': 'version:2@1496001',
         },
       ],
   },
@@ -1427,7 +1427,7 @@
       'packages': [
         {
           'package': 'chromium/third_party/updater/chromium_win_x86_64',
-          'version': 'version:2@1495038',
+          'version': 'version:2@1496004',
         },
       ],
   },
@@ -1585,7 +1585,7 @@
     'packages': [
       {
         'package': 'chromium/chrome/test/data/variations/cipd',
-        'version': 'WMn_HojtRUS2pNICebTkZUE9NLCRiKg8t9gamhkWFGgC',
+        'version': 'yhI7eHneNGlKiKz275h1v1zhxYfRiuY6mejAvYaxZ58C',
       },
     ],
     'dep_type': 'cipd',
@@ -1596,7 +1596,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    'bdf12c2772f61caaa6fe2ba099b9b6f81b8accd0',
+    '45c2f62260d04feed5cd4f2c0a44ed4c7fc77985',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -2937,7 +2937,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@ce23c0071ce2cbf33c8eb1a4bcaebb548d6ecc3b',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@3678a87313f1434831df0ba2867c060388c2fbe2',
   'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@38f6708b6b6f213010c51ffa8f577a7751e12ce7',
   '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@97e96f9e9defeb4bba3cfbd034dec516671dd7a3',
@@ -2946,7 +2946,7 @@
   'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@f2389e27734347c1d9f40e03be53f69f969976b1',
   'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@f766b30b2de3ffe2cf6b656d943720882617ec58',
   'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@b0a40d2e50310e9f84327061290a390a061125a3',
-  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@3493fc8be4f99acf3b685bc2b9733b95d8f51a7b',
+  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@a11139aca558fdb4fe6332ffd4ba213d48317db6',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'cb0597213b0fcb999caa9ed08c2f88dc45eb7d50',
@@ -2989,7 +2989,7 @@
     Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'),
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '2fcc3b79ac702738ba22441d4a55c2e8f90c787c',
+    Var('webrtc_git') + '/src.git' + '@' + '9bd64751d9b3b35a820cb72c9029993e218146a1',
 
   # 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.
@@ -3122,7 +3122,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'SO-vrb5Rw1__P74Q9nTCUMhS5-Gfa777zOwnar1YhD8C',
+        'version': 'wDanLhusSutIIW147uQXYpg4dRoqrI-LKRyz9YhPsc8C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3133,7 +3133,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'WdYYVdyVaUWm1K0SA3v0eH51Sz8WS8Z_1Cfxf-lf_N4C',
+        'version': 'g1u6v41bR5X4O-T_YcpAN3WH6ham-TXSRmwqqkZKopsC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3758,7 +3758,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        '2895e17b8cb4e8f1c26617d9f104be21967694ab',
+        'aa425b74d980d8414aa5b414fe70e1e68a2265ff',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/ash/webui/recorder_app_ui/resources/images/genai_error_general.svg b/ash/webui/recorder_app_ui/resources/images/genai_error_general.svg
index b99ede13..761da87 100644
--- a/ash/webui/recorder_app_ui/resources/images/genai_error_general.svg
+++ b/ash/webui/recorder_app_ui/resources/images/genai_error_general.svg
@@ -1 +1,16 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="201" height="100" fill="none"><path fill="#E2E1EC" d="m159.57 41.48-21.13-16.6a12.67 12.67 0 0 1-4.82-8.35c-.46-3.33.4-6.72 2.4-9.42a12.63 12.63 0 0 1 8.2-4.98 12.17 12.17 0 0 1 9.2 2.4l21.14 16.59a12.67 12.67 0 0 1 4.82 8.35c.46 3.33-.4 6.72-2.39 9.42a12.48 12.48 0 0 1-8.2 4.98 12.2 12.2 0 0 1-9.22-2.39Z"/><path fill="#FF5167" d="m39.25 23.14-9 10.72a3.2 3.2 0 0 0 .4 4.5l10.6 8.9a3.2 3.2 0 0 0 4.5-.4l9-10.72a3.2 3.2 0 0 0-.4-4.5l-10.6-8.9a3.2 3.2 0 0 0-4.5.4Z"/><path fill="#DBE1FF" d="M58.4 92.1c3.06-.67 6.1-1.52 9.08-2.52 4.14-1.25 8.6-.82 12.39 1.17 2.07 1.2 4.2 2.28 6.4 3.24 7.79 3.06 16.83-1.09 18.86-9.37 1.79-7.28-3.1-15.16-10.7-16.29-3.52-.54-7.09.13-10.62-.1a16.16 16.16 0 0 1-10.07-4.2c-2.34-2.17-4.49-4.56-7.13-6.44a19.2 19.2 0 0 0-8.72-3.43 20.02 20.02 0 0 0-14.16 3.57 19.61 19.61 0 0 0-7.88 12.18c-.95 4.88.04 9.92 2.76 14.06a19.29 19.29 0 0 0 11.87 8.18c2.6.53 5.3.51 7.91-.05Z"/><path stroke="#E2E1EC" stroke-dasharray="4 6" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="3" d="M146.52 95.12a2.77 2.77 0 0 1-3.32.23c-.34-.21-.63-.5-.85-.83a28.71 28.71 0 0 1-4.66-19.8 27.97 27.97 0 0 1 28.67-24.4c6.96.22 13.62 3 18.7 7.83a2.88 2.88 0 0 1 .64 3.3c-.17.36-.41.68-.71.94l-38.47 32.73Z"/><path stroke="#C6A0BF" stroke-miterlimit="10" stroke-width="3" d="M122.5 82a9 9 0 1 0 0-18 9 9 0 0 0 0 18Z"/><path fill="#B5C4FF" d="M97.5 65a32 32 0 1 0 0-64 32 32 0 0 0 0 64Z"/><path fill="#fff" fill-rule="evenodd" d="M88.64 40.8a2 2 0 1 0 2.95 2.7l6.44-7.05 6.91 6.59a2 2 0 0 0 2.76-2.9l-6.97-6.64 6.5-7.1a2 2 0 1 0-2.95-2.7l-6.44 7.04-6.9-6.59a2 2 0 1 0-2.77 2.9l6.97 6.64-6.5 7.1Z" clip-rule="evenodd"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100" viewBox="0 0 200 100" fill="none">
+<g clip-path="url(#clip0_2195_26319)">
+<path d="M159.075 41.481L137.937 24.8853C135.307 22.8697 133.574 19.8651 133.119 16.5318C132.664 13.1985 133.525 9.80944 135.511 7.10954C136.495 5.77196 137.725 4.64398 139.133 3.78998C140.541 2.93607 142.098 2.37281 143.715 2.13248C145.332 1.89214 146.978 1.97943 148.559 2.38933C150.14 2.79931 151.624 3.52384 152.927 4.52159L174.058 21.1163C176.69 23.131 178.424 26.1354 178.88 29.4689C179.337 32.8024 178.477 36.1922 176.49 38.893C174.503 41.5929 171.552 43.3821 168.286 43.8674C165.02 44.3527 161.707 43.4943 159.075 41.481Z" fill="var(--cros-sys-illo-secondary)" />
+<path d="M38.7502 23.1417L29.7484 33.8612C28.6129 35.2134 28.7894 37.2292 30.1426 38.3635L40.7437 47.2518C42.0969 48.3868 44.1144 48.2105 45.2498 46.8584L54.2515 36.1386C55.3874 34.7866 55.2103 32.7707 53.8571 31.6362L43.2563 22.7478C41.9032 21.6132 39.8857 21.7895 38.7502 23.1417Z" fill="var(--cros-sys-illo-color4)" />
+<path d="M57.8929 92.104C60.9634 91.4255 63.9958 90.5816 66.9762 89.5758C71.1224 88.3328 75.5794 88.7553 79.3682 90.7498C81.4382 91.9432 83.5718 93.026 85.7611 93.9942C93.5586 97.0549 102.599 92.9034 104.631 84.6198C106.417 77.3437 101.536 69.4587 93.928 68.332C90.413 67.7949 86.8396 68.4626 83.3059 68.2362C79.5443 68.0349 75.9874 66.5496 73.2446 64.0357C70.9002 61.8616 68.7508 59.4748 66.107 57.5949C63.5447 55.7538 60.5505 54.574 57.3929 54.1612C52.4041 53.5215 47.3326 54.8004 43.2294 57.7323C39.1263 60.6642 36.3062 65.0244 35.3537 69.9091C34.4012 74.7944 35.3893 79.8291 38.1133 83.9704C40.8373 88.1122 45.0881 91.0423 49.9848 92.1542C52.5885 92.6816 55.2824 92.6645 57.8929 92.104Z" fill="var(--cros-sys-illo-color1-2)" />
+<path d="M146.019 95.1237C145.717 95.3808 145.365 95.5701 144.983 95.6795C144.602 95.7891 144.201 95.8165 143.808 95.7597C143.414 95.7027 143.035 95.5624 142.698 95.3485C142.361 95.1349 142.071 94.8525 141.849 94.519C137.93 88.697 136.272 81.6476 137.192 74.7205C138.112 67.7925 141.545 61.473 146.833 56.9712C152.122 52.4687 158.896 50.1001 165.858 50.3184C172.821 50.5365 179.483 53.3259 184.57 58.1531C184.861 58.4285 185.091 58.7618 185.246 59.1312C185.401 59.5008 185.477 59.898 185.469 60.2974C185.462 60.697 185.37 61.0896 185.202 61.4494C185.032 61.8095 184.789 62.1293 184.489 62.3875L146.019 95.1237Z" stroke="var(--cros-sys-illo-secondary)" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="4 6" />
+<path d="M122 82C126.97 82 131 77.9704 131 73C131 68.0292 126.97 64 122 64C117.029 64 113 68.0292 113 73C113 77.9704 117.029 82 122 82Z" stroke="var(--cros-sys-illo-color5)" stroke-width="3" stroke-miterlimit="10" />
+<path d="M97 65C114.673 65 129 50.6731 129 33C129 15.3269 114.673 1 97 1C79.3269 1 65 15.3269 65 33C65 50.6731 79.3269 65 97 65Z" fill="var(--cros-sys-illo-color1-1)" />
+<path fill-rule="evenodd" clip-rule="evenodd" d="M88.1366 40.7918C87.3907 41.6065 87.4464 42.8716 88.2611 43.6175C89.0758 44.3634 90.3409 44.3076 91.0868 43.4929L97.5324 36.453L104.44 43.0403C105.239 43.8026 106.505 43.7726 107.268 42.9732C108.03 42.1738 108 40.9079 107.201 40.1456L100.234 33.5021L106.735 26.402C107.481 25.5873 107.425 24.3222 106.61 23.5763C105.795 22.8304 104.53 22.8862 103.784 23.7009L97.3387 30.7411L90.4311 24.1538C89.6317 23.3915 88.3657 23.4215 87.6034 24.2209C86.8411 25.0203 86.8712 26.2862 87.6706 27.0485L94.637 33.6919L88.1366 40.7918Z" fill="var(--cros-sys-base_elevated)" />
+</g>
+<defs>
+<clipPath id="clip0_2195_26319">
+<rect width="200" height="100" fill="var(--cros-sys-base_elevated)" />
+</clipPath>
+</defs>
+</svg>
\ No newline at end of file
diff --git a/ash/webui/recorder_app_ui/resources/images/genai_error_unsafe.svg b/ash/webui/recorder_app_ui/resources/images/genai_error_unsafe.svg
index 4f938c7..da3d467 100644
--- a/ash/webui/recorder_app_ui/resources/images/genai_error_unsafe.svg
+++ b/ash/webui/recorder_app_ui/resources/images/genai_error_unsafe.svg
@@ -1 +1,15 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="201" height="100" fill="none"><path stroke="#C6A0BF" stroke-miterlimit="10" stroke-width="3" d="M40.458 69.35c8.03-.7 13.974-7.778 13.273-15.808-.7-8.032-7.778-13.974-15.809-13.274-8.031.7-13.974 7.778-13.273 15.81.7 8.03 7.777 13.973 15.809 13.273Z"/><path fill="#E2E1EC" d="M156.993 71.305c-2.221-.627-2.933-3.422-1.282-5.034l19.568-19.11c1.651-1.613 4.428-.836 5.002 1.399l6.822 26.558c.575 2.24-1.494 4.262-3.721 3.634l-26.389-7.447Z"/><rect width="29.518" height="29.518" x="6" y="53.2" stroke="#3F5AA9" stroke-dasharray="3 6" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" rx="14.759" transform="rotate(-21 6 53.2)"/><path stroke="#E89C00" stroke-width="3" d="M151.185 38.389a.5.5 0 0 1 .841-.251l22.637 22.436a.5.5 0 0 1-.214.835l-29.188 8.429a.5.5 0 0 1-.628-.584l6.552-30.865Z"/><path fill="#DBE1FF" d="M106.332 10.267c2.38-2.355 6.493-1.268 7.369 1.948l1.731 6.353c.583 2.142 2.733 3.51 4.964 3.158l6.618-1.042c3.349-.527 6.04 2.713 4.82 5.806l-2.41 6.11c-.812 2.059.114 4.396 2.138 5.396l6.007 2.966c3.04 1.501 3.28 5.657.43 7.445l-5.631 3.533a4.223 4.223 0 0 0-1.505 5.575l3.102 5.84c1.569 2.958-.733 6.441-4.125 6.242l-6.7-.395c-2.259-.132-4.24 1.437-4.573 3.624l-.989 6.484c-.5 3.284-4.465 4.764-7.103 2.654l-5.211-4.17c-1.757-1.406-4.31-1.281-5.895.287l-4.7 4.652c-2.38 2.355-6.493 1.268-7.37-1.948l-1.73-6.353c-.584-2.142-2.734-3.51-4.965-3.158l-6.618 1.042c-3.35.528-6.04-2.712-4.82-5.806l2.41-6.11c.813-2.06-.113-4.396-2.138-5.395l-6.007-2.967c-3.04-1.501-3.28-5.657-.43-7.445l5.631-3.533a4.22 4.22 0 0 0 1.504-5.574l-3.1-5.841c-1.57-2.957.732-6.44 4.123-6.241l6.701.393c2.26.133 4.24-1.436 4.573-3.622l.989-6.485c.5-3.283 4.466-4.764 7.103-2.653l5.212 4.17c1.756 1.405 4.308 1.28 5.893-.288l4.702-4.652Z"/><path fill="#3F5AA9" d="m98.418 51.32-.018-1.198c-.012-.848.074-1.576.26-2.185a5.18 5.18 0 0 1 .955-1.794c.476-.589 1.121-1.216 1.935-1.882.527-.444.957-.85 1.291-1.218.357-.393.618-.809.781-1.247.187-.463.277-.986.268-1.567-.014-.969-.352-1.74-1.015-2.311-.638-.597-1.551-.886-2.738-.87-.703.011-1.33.154-1.884.428-.529.274-.96.668-1.291 1.182-.332.49-.554 1.074-.665 1.754l-3.604-.42c.103-1.237.462-2.345 1.078-3.323.615-1.002 1.464-1.802 2.546-2.4 1.081-.597 2.349-.906 3.802-.927 1.575-.023 2.924.236 4.046.777 1.146.517 2.03 1.28 2.65 2.288.62.984.94 2.155.96 3.511.014 1.018-.13 1.916-.434 2.696a7.88 7.88 0 0 1-1.206 2.053c-.5.613-1.037 1.154-1.612 1.622-.551.445-.993.875-1.326 1.292a3.924 3.924 0 0 0-.672 1.245c-.115.438-.168.96-.159 1.565l.012.872-3.96.058Zm2.091 8.839c-.776.01-1.433-.246-1.974-.771a2.69 2.69 0 0 1-.791-1.915 2.69 2.69 0 0 1 .735-1.937c.525-.54 1.175-.817 1.951-.828.75-.01 1.384.247 1.901.772.54.525.816 1.163.827 1.914a2.625 2.625 0 0 1-.771 1.938c-.501.54-1.127.816-1.878.827Z"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100" viewBox="0 0 200 100" fill="none">
+<g clip-path="url(#clip0_2195_26312)">
+<path d="M40.4587 69.3503C48.4895 68.6502 54.4326 61.5719 53.7325 53.5412C53.0323 45.5097 45.954 39.5673 37.9233 40.2674C29.8918 40.9676 23.9494 48.0451 24.6496 56.0766C25.3497 64.1073 32.4273 70.0505 40.4587 69.3503Z" stroke="var(--cros-sys-illo-color5)" stroke-width="3" stroke-miterlimit="10" />
+<path d="M156.993 71.3054C154.772 70.6787 154.06 67.8842 155.711 66.272L175.279 47.1611C176.93 45.5489 179.707 46.3261 180.281 48.561L187.103 75.1194C187.678 77.3599 185.609 79.3812 183.382 78.7529L156.993 71.3054Z" fill="var(--cros-sys-illo-secondary)" />
+<rect x="6" y="53.2012" width="29.5179" height="29.5179" rx="14.759" transform="rotate(-20.9825 6 53.2012)" stroke="var(--cros-sys-illo-color1)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="3 6" />
+<path d="M152.026 38.1377L174.663 60.5736C174.934 60.8423 174.817 61.3033 174.45 61.4091L145.261 69.8377C144.899 69.9425 144.555 69.6228 144.634 69.2535L151.185 38.389C151.267 38.0019 151.745 37.8592 152.026 38.1377Z" stroke="var(--cros-sys-illo-color3)" stroke-width="3" />
+<path d="M106.332 10.2669C108.712 7.91182 112.825 8.99923 113.701 12.2153L115.432 18.5682C116.015 20.71 118.165 22.0775 120.396 21.7262L127.014 20.684C130.363 20.1565 133.054 23.3967 131.834 26.4896L129.424 32.5992C128.612 34.659 129.538 36.9961 131.562 37.996L137.569 40.962C140.609 42.4634 140.849 46.6189 137.999 48.4072L132.368 51.9399C130.47 53.1308 129.819 55.545 130.863 57.5145L133.965 63.3553C135.534 66.3126 133.232 69.796 129.84 69.5966L123.14 69.2023C120.881 69.0697 118.9 70.6386 118.567 72.8255L117.578 79.3104C117.078 82.5935 113.113 84.074 110.475 81.9637L105.264 77.7938C103.508 76.3882 100.954 76.5127 99.3694 78.0807L94.6686 82.7333C92.2886 85.088 88.1757 84.0009 87.2998 80.7846L85.5686 74.4323C84.9852 72.2905 82.835 70.9228 80.604 71.2737L73.9863 72.3158C70.6361 72.8435 67.9456 69.6038 69.1661 66.5102L71.5766 60.4006C72.3888 58.3409 71.4626 56.0042 69.438 55.0046L63.4315 52.0382C60.3909 50.5367 60.1504 46.3813 63.0016 44.593L68.6321 41.0603C70.5302 39.8693 71.1818 37.4555 70.1362 35.4861L67.0356 29.6449C65.466 26.6879 67.7679 23.2045 71.1593 23.4038L77.8605 23.7974C80.1193 23.9301 82.0991 22.3614 82.4329 20.175L83.4219 13.6896C83.9227 10.4066 87.8876 8.92588 90.5251 11.0365L95.7366 15.2062C97.4929 16.612 100.045 16.4876 101.63 14.9192L106.332 10.2669Z" fill="var(--cros-sys-illo-color1-2)" />
+<path d="M98.4177 51.3209L98.4003 50.1218C98.388 49.2739 98.4744 48.5458 98.6594 47.9374C98.844 47.3047 99.1625 46.7065 99.6146 46.1426C100.091 45.5542 100.736 44.927 101.55 44.261C102.077 43.8172 102.507 43.4111 102.841 43.0429C103.198 42.65 103.459 42.2343 103.622 41.7958C103.809 41.3327 103.899 40.8105 103.89 40.2291C103.876 39.2601 103.538 38.4897 102.875 37.9178C102.237 37.3213 101.324 37.0317 100.137 37.0489C99.4343 37.0591 98.8064 37.2015 98.2531 37.476C97.7241 37.7502 97.2936 38.1442 96.9619 38.6578C96.6298 39.1472 96.4081 39.7319 96.2968 40.412L92.6926 39.9918C92.7958 38.7546 93.1553 37.6469 93.771 36.6688C94.3865 35.6665 95.235 34.8667 96.3167 34.2695C97.3983 33.6723 98.6659 33.3631 100.119 33.342C101.694 33.3191 103.043 33.5782 104.165 34.1192C105.311 34.6356 106.195 35.3982 106.815 36.4068C107.435 37.3912 107.755 38.5617 107.775 39.9183C107.789 40.9357 107.645 41.8343 107.341 42.6141C107.037 43.3696 106.635 44.0539 106.135 44.6669C105.635 45.2799 105.098 45.8207 104.523 46.2894C103.972 46.7336 103.53 47.164 103.197 47.5808C102.888 47.9729 102.664 48.3881 102.525 48.8262C102.41 49.264 102.357 49.7857 102.366 50.3914L102.378 51.2634L98.4177 51.3209ZM100.509 60.1587C99.7334 60.1699 99.0755 59.9129 98.5348 59.3877C98.0184 58.8622 97.7547 58.2239 97.7438 57.4729C97.7329 56.722 97.9779 56.0763 98.4789 55.536C99.0041 54.9953 99.6543 54.7194 100.43 54.7081C101.18 54.6972 101.814 54.9545 102.331 55.4801C102.871 56.0053 103.147 56.6434 103.158 57.3944C103.169 58.1453 102.912 58.7911 102.387 59.3318C101.886 59.8721 101.26 60.1478 100.509 60.1587Z" fill="var(--cros-sys-illo-color1)" />
+</g>
+<defs>
+<clipPath id="clip0_2195_26312">
+<rect width="200" height="100" fill="var(--cros-sys-base_elevated)" />
+</clipPath>
+</defs>
+</svg>
\ No newline at end of file
diff --git a/ash/wm/switchable_windows.cc b/ash/wm/switchable_windows.cc
index c938676..b9e32a4a 100644
--- a/ash/wm/switchable_windows.cc
+++ b/ash/wm/switchable_windows.cc
@@ -15,10 +15,11 @@
 
 namespace {
 
-constexpr std::array<int, 3> kSwitchableContainers = {
+constexpr std::array<int, 4> kSwitchableContainers = {
     kShellWindowId_AlwaysOnTopContainer,
     kShellWindowId_FloatContainer,
     kShellWindowId_PipContainer,
+    kShellWindowId_LiveCaptionContainer,
 };
 
 std::vector<int> GetSwitchableContainerIds() {
diff --git a/base/allocator/partition_alloc_support.h b/base/allocator/partition_alloc_support.h
index a70c2db4..3099f98 100644
--- a/base/allocator/partition_alloc_support.h
+++ b/base/allocator/partition_alloc_support.h
@@ -184,6 +184,7 @@
 // to the function, and it may use that for debugging purpose.
 BASE_EXPORT void SetDoubleFreeOrCorruptionDetectedFn(void (*fn)(uintptr_t));
 
+using partition_alloc::SchedulerLoopQuarantineScanPolicyUpdater;
 using partition_alloc::ScopedSchedulerLoopQuarantineExclusion;
 
 }  // namespace base::allocator
diff --git a/base/allocator/partition_allocator/src/partition_alloc/scheduler_loop_quarantine.cc b/base/allocator/partition_allocator/src/partition_alloc/scheduler_loop_quarantine.cc
index 32aaef24..d7fb206 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/scheduler_loop_quarantine.cc
+++ b/base/allocator/partition_allocator/src/partition_alloc/scheduler_loop_quarantine.cc
@@ -241,7 +241,7 @@
       }
     }
 
-    freed_count++;
+    ++freed_count;
     PA_DCHECK(slot_size > 0);
     freed_size_in_bytes += slot_size;
     branch_size_in_bytes_ -= slot_size;
@@ -255,6 +255,31 @@
 }
 
 template <bool thread_bound>
+void SchedulerLoopQuarantineBranch<thread_bound>::AllowScanlessPurge() {
+  PA_DCHECK(kThreadBound);
+  // Always thread-bound; no need to lock.
+  FakeScopedGuard guard(lock_);
+
+  PA_CHECK(disallow_scanless_purge_ > 0);
+  --disallow_scanless_purge_;
+  if (disallow_scanless_purge_ == 0) {
+    // Now scanless purge is allowed. Purging at this timing is more performance
+    // efficient.
+    PurgeInternal(0);
+  }
+}
+
+template <bool thread_bound>
+void SchedulerLoopQuarantineBranch<thread_bound>::DisallowScanlessPurge() {
+  PA_DCHECK(kThreadBound);
+  // Always thread-bound; no need to lock.
+  FakeScopedGuard guard(lock_);
+
+  ++disallow_scanless_purge_;
+  PA_CHECK(disallow_scanless_purge_ > 0);  // Overflow check.
+}
+
+template <bool thread_bound>
 const SchedulerLoopQuarantineConfig&
 SchedulerLoopQuarantineBranch<thread_bound>::GetConfigurationForTesting() {
   return config_for_testing_;
diff --git a/base/allocator/partition_allocator/src/partition_alloc/scheduler_loop_quarantine.h b/base/allocator/partition_allocator/src/partition_alloc/scheduler_loop_quarantine.h
index 7d2465e..293d8c9e 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/scheduler_loop_quarantine.h
+++ b/base/allocator/partition_allocator/src/partition_alloc/scheduler_loop_quarantine.h
@@ -156,6 +156,9 @@
                   SlotSpanMetadata* slot_span,
                   uintptr_t slot_start) PA_LOCKS_EXCLUDED(lock_);
 
+  void AllowScanlessPurge();
+  void DisallowScanlessPurge();
+
   const SchedulerLoopQuarantineConfig& GetConfigurationForTesting();
 
   class ScopedQuarantineExclusion {
@@ -223,6 +226,15 @@
   // Using `std::atomic` here so that other threads can update this value.
   std::atomic_size_t branch_capacity_in_bytes_ = 0;
 
+  // TODO(http://crbug.com/329027914): Implement stack scanning, to be performed
+  // when this value is non-zero.
+  //
+  // Currently, a scanless purge is always performed. However, this value is
+  // still used as a hint to determine safer purge timings for memory
+  // optimization.
+  uint32_t disallow_scanless_purge_ PA_GUARDED_BY(lock_) = 0;
+
+  // Debug and testing data.
 #if PA_BUILDFLAG(DCHECKS_ARE_ON)
   std::atomic_bool being_destructed_ = false;
 #endif  // PA_BUILDFLAG(DCHECKS_ARE_ON)
diff --git a/base/allocator/partition_allocator/src/partition_alloc/scheduler_loop_quarantine_support.cc b/base/allocator/partition_allocator/src/partition_alloc/scheduler_loop_quarantine_support.cc
index 4505a9d..3670be1 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/scheduler_loop_quarantine_support.cc
+++ b/base/allocator/partition_allocator/src/partition_alloc/scheduler_loop_quarantine_support.cc
@@ -21,6 +21,50 @@
 ScopedSchedulerLoopQuarantineExclusion::
     ~ScopedSchedulerLoopQuarantineExclusion() {}
 
+SchedulerLoopQuarantineScanPolicyUpdater::
+    SchedulerLoopQuarantineScanPolicyUpdater() = default;
+
+SchedulerLoopQuarantineScanPolicyUpdater::
+    ~SchedulerLoopQuarantineScanPolicyUpdater() {
+  // Ensure all `DisallowScanlessPurge()` calls were followed by
+  // `AllowScanlessPurge()`.
+  PA_CHECK(disallow_scanless_purge_calls_ == 0);
+}
+
+void SchedulerLoopQuarantineScanPolicyUpdater::DisallowScanlessPurge() {
+  disallow_scanless_purge_calls_++;
+  PA_CHECK(0 < disallow_scanless_purge_calls_);  // Overflow check.
+
+  auto* branch = GetQuarantineBranch();
+  PA_CHECK(branch);
+  branch->DisallowScanlessPurge();
+}
+
+void SchedulerLoopQuarantineScanPolicyUpdater::AllowScanlessPurge() {
+  PA_CHECK(0 < disallow_scanless_purge_calls_);
+  disallow_scanless_purge_calls_--;
+
+  auto* branch = GetQuarantineBranch();
+  PA_CHECK(branch);
+  branch->AllowScanlessPurge();
+}
+
+internal::ThreadBoundSchedulerLoopQuarantineBranch*
+SchedulerLoopQuarantineScanPolicyUpdater::GetQuarantineBranch() {
+  ThreadCache* tcache = ThreadCache::EnsureAndGet();
+  if (!ThreadCache::IsValid(tcache)) {
+    return nullptr;
+  }
+
+  uintptr_t current_tcache_addr = reinterpret_cast<uintptr_t>(tcache);
+  if (tcache_address_ == 0) {
+    tcache_address_ = current_tcache_addr;
+  } else {
+    PA_CHECK(tcache_address_ == current_tcache_addr);
+  }
+  return &tcache->GetSchedulerLoopQuarantineBranch();
+}
+
 namespace internal {
 ScopedSchedulerLoopQuarantineBranchAccessorForTesting::
     ScopedSchedulerLoopQuarantineBranchAccessorForTesting(
diff --git a/base/allocator/partition_allocator/src/partition_alloc/scheduler_loop_quarantine_support.h b/base/allocator/partition_allocator/src/partition_alloc/scheduler_loop_quarantine_support.h
index 4eac1a5..7784216 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/scheduler_loop_quarantine_support.h
+++ b/base/allocator/partition_allocator/src/partition_alloc/scheduler_loop_quarantine_support.h
@@ -10,11 +10,13 @@
 #ifndef PARTITION_ALLOC_SCHEDULER_LOOP_QUARANTINE_SUPPORT_H_
 #define PARTITION_ALLOC_SCHEDULER_LOOP_QUARANTINE_SUPPORT_H_
 
+#include <map>
 #include <optional>
 #include <variant>
 
 #include "partition_alloc/build_config.h"
 #include "partition_alloc/buildflags.h"
+#include "partition_alloc/partition_alloc_base/compiler_specific.h"
 #include "partition_alloc/partition_root.h"
 #include "partition_alloc/scheduler_loop_quarantine.h"
 #include "partition_alloc/thread_cache.h"
@@ -39,6 +41,49 @@
       instance_;
 };
 
+// An utility class to update Scheduler-Loop Quarantine's purging strategy for
+// the current thread. By default it uses "scanless" purge for best performance.
+// However, it also supports stack-scanning before purging to verify there is no
+// dangling pointer in stack memory. Stack-scanning comes with some performance
+// cost, but there is security benefit. This class can be used to switch between
+// these two strategies dynamically.
+// An example usage is to allow scanless purge only around "stack bottom".
+// We can safely assume there is no dangling pointer if stack memory is barely
+// used thus safe to purge quarantine.
+// At Chrome layer it is task execution and we expect
+// `DisallowScanlessPurge()` to be called before task execution and
+// `AllowScanlessPurge()` after. Since there is no unified way to hook
+// task execution in Chrome, we provide an abstract utility here.
+// This class is not thread-safe.
+//
+// TODO(http://crbug.com/329027914): stack-scanning is not implemented yet
+// and this class is effectively "disallow any purge unless really needed".
+// It still gives some hints on purging timing for memory efficiency.
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+    SchedulerLoopQuarantineScanPolicyUpdater {
+ public:
+  SchedulerLoopQuarantineScanPolicyUpdater();
+  ~SchedulerLoopQuarantineScanPolicyUpdater();
+
+  // Disallows scanless purge and performs stack-scanning when needed.
+  // Can be called multiple times, but each call to this function must be
+  // followed by `AllowScanlessPurge()`.
+  void DisallowScanlessPurge();
+
+  // Re-activate scanless purge. `DisallowScanlessPurge()` must be called prior
+  // to use of this function. This may trigger purge immediately.
+  void AllowScanlessPurge();
+
+ private:
+  PA_ALWAYS_INLINE internal::ThreadBoundSchedulerLoopQuarantineBranch*
+  GetQuarantineBranch();
+
+  uint32_t disallow_scanless_purge_calls_ = 0;
+
+  // An address of `ThreadCache` instance works as a thread ID.
+  uintptr_t tcache_address_ = 0;
+};
+
 namespace internal {
 
 class PA_COMPONENT_EXPORT(PARTITION_ALLOC)
diff --git a/base/memory/safety_checks.h b/base/memory/safety_checks.h
index fad0b5a..fd45631 100644
--- a/base/memory/safety_checks.h
+++ b/base/memory/safety_checks.h
@@ -339,6 +339,16 @@
 #endif  // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
 };
 
+#if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+using base::allocator::SchedulerLoopQuarantineScanPolicyUpdater;
+#else
+class SchedulerLoopQuarantineScanPolicyUpdater {
+ public:
+  ALWAYS_INLINE void DisallowScanlessPurge() {}
+  ALWAYS_INLINE void AllowScanlessPurge() {}
+};
+#endif  // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+
 }  // namespace base
 
 #endif  // BASE_MEMORY_SAFETY_CHECKS_H_
diff --git a/build/android/gyp/create_test_apk_wrapper_script.py b/build/android/gyp/create_test_apk_wrapper_script.py
index b4d18ec..8fb1187 100755
--- a/build/android/gyp/create_test_apk_wrapper_script.py
+++ b/build/android/gyp/create_test_apk_wrapper_script.py
@@ -12,7 +12,7 @@
 from util import build_utils
 
 SCRIPT_TEMPLATE = string.Template("""\
-#!/usr/bin/env python3
+#!/usr/bin/env vpython3
 #
 # This file was generated by build/android/gyp/create_test_apk_wrapper_script.py
 
diff --git a/build/modules/linux-x64/BUILD.gn b/build/modules/linux-x64/BUILD.gn
new file mode 100644
index 0000000..c96deb4
--- /dev/null
+++ b/build/modules/linux-x64/BUILD.gn
@@ -0,0 +1,240 @@
+# 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.
+
+# AUTOGENERATED FILE. DO NOT EDIT.
+# To regenerate, run build/modules/modularize/modularize.py
+
+import("//buildtools/third_party/libc++/modules.gni")
+
+builtin_module("_Builtin_float") {
+}
+
+builtin_module("_Builtin_intrinsics") {
+  public_deps = [
+    ":_Builtin_stddef",
+    ":_Builtin_stdint",
+    ":std_core",
+    ":sys_stage1",
+    ":sys_stage2",
+  ]
+}
+
+builtin_module("_Builtin_inttypes") {
+  public_deps = [
+    ":_Builtin_stdint",
+    ":sys_stage1",
+  ]
+}
+
+builtin_module("_Builtin_iso646") {
+}
+
+builtin_module("_Builtin_limits") {
+  public_deps = [ ":sys_stage1" ]
+}
+
+builtin_module("_Builtin_stdalign") {
+}
+
+builtin_module("_Builtin_stdarg") {
+}
+
+builtin_module("_Builtin_stdatomic") {
+  public_deps = [
+    ":_Builtin_stddef",
+    ":_Builtin_stdint",
+    ":sys_stage1",
+  ]
+}
+
+builtin_module("_Builtin_stdbool") {
+}
+
+builtin_module("_Builtin_stdcountof") {
+}
+
+builtin_module("_Builtin_stddef") {
+}
+
+builtin_module("_Builtin_stddef_wint_t") {
+}
+
+builtin_module("_Builtin_stdint") {
+  public_deps = [ ":sys_stage1" ]
+}
+
+builtin_module("_Builtin_stdnoreturn") {
+}
+
+builtin_module("_Builtin_tgmath") {
+  public_deps = [ ":std_math_h" ]
+}
+
+builtin_module("_Builtin_unwind") {
+  public_deps = [ ":_Builtin_stdint" ]
+}
+
+builtin_module("ptrauth") {
+}
+
+libcxx_module("std") {
+  public_deps = [
+    ":_Builtin_limits",
+    ":_Builtin_stdalign",
+    ":_Builtin_stdarg",
+    ":_Builtin_stddef",
+    ":std_core",
+    ":std_ctype_h",
+    ":std_errno_h",
+    ":std_fenv_h",
+    ":std_float_h",
+    ":std_inttypes_h",
+    ":std_math_h",
+    ":std_private_mbstate_t",
+    ":std_string_h",
+    ":std_uchar_h",
+    ":std_wctype_h",
+    ":sys_stage1",
+    ":sys_stage2",
+  ]
+}
+
+libcxx_module("std_complex_h") {
+  public_deps = [
+    ":std",
+    ":sys_stage1",
+  ]
+}
+
+libcxx_module("std_core") {
+  public_deps = [
+    ":_Builtin_stddef",
+    ":_Builtin_stdint",
+    ":sys_stage1",
+  ]
+}
+
+libcxx_module("std_ctype_h") {
+  public_deps = [ ":sys_stage1" ]
+}
+
+libcxx_module("std_errno_h") {
+  public_deps = [ ":sys_stage1" ]
+}
+
+libcxx_module("std_fenv_h") {
+  public_deps = [ ":sys_stage1" ]
+}
+
+libcxx_module("std_float_h") {
+  public_deps = [
+    ":_Builtin_float",
+    ":sys_stage1",
+  ]
+}
+
+libcxx_module("std_inttypes_h") {
+  public_deps = [
+    ":_Builtin_inttypes",
+    ":_Builtin_stdint",
+    ":sys_stage1",
+  ]
+}
+
+libcxx_module("std_math_h") {
+  public_deps = [
+    ":std_core",
+    ":sys_stage1",
+  ]
+}
+
+libcxx_module("std_private_mbstate_t") {
+  public_deps = [ ":sys_stage1" ]
+}
+
+libcxx_module("std_stdatomic_h") {
+  public_deps = [
+    ":_Builtin_stdatomic",
+    ":sys_stage1",
+  ]
+}
+
+libcxx_module("std_string_h") {
+  public_deps = [
+    ":_Builtin_stddef",
+    ":sys_stage1",
+  ]
+}
+
+libcxx_module("std_tgmath_h") {
+  public_deps = [
+    ":std",
+    ":sys_stage1",
+  ]
+}
+
+libcxx_module("std_uchar_h") {
+  public_deps = [
+    ":_Builtin_stddef",
+    ":sys_stage1",
+  ]
+}
+
+libcxx_module("std_wctype_h") {
+  public_deps = [ ":sys_stage1" ]
+}
+
+sysroot_module("sys_stage1") {
+  public_deps = [
+    ":_Builtin_stdarg",
+    ":_Builtin_stddef",
+  ]
+}
+
+sysroot_module("sys_stage2") {
+  public_deps = [
+    ":_Builtin_limits",
+    ":_Builtin_stddef",
+    ":sys_stage1",
+  ]
+}
+
+alias("all_modules") {
+  actual = [
+    ":_Builtin_float",
+    ":_Builtin_intrinsics",
+    ":_Builtin_inttypes",
+    ":_Builtin_iso646",
+    ":_Builtin_limits",
+    ":_Builtin_stdalign",
+    ":_Builtin_stdarg",
+    ":_Builtin_stdatomic",
+    ":_Builtin_stdbool",
+    ":_Builtin_stdcountof",
+    ":_Builtin_stddef",
+    ":_Builtin_stddef_wint_t",
+    ":_Builtin_stdint",
+    ":_Builtin_stdnoreturn",
+    ":_Builtin_tgmath",
+    ":_Builtin_unwind",
+    ":ptrauth",
+    ":std",
+    ":std_complex_h",
+    ":std_core",
+    ":std_ctype_h",
+    ":std_errno_h",
+    ":std_fenv_h",
+    ":std_float_h",
+    ":std_inttypes_h",
+    ":std_math_h",
+    ":std_private_mbstate_t",
+    ":std_stdatomic_h",
+    ":std_string_h",
+    ":std_tgmath_h",
+    ":std_uchar_h",
+    ":std_wctype_h",
+    ":sys_stage1",
+    ":sys_stage2",
+  ]
+}
diff --git a/build/modules/linux-x64/module.modulemap b/build/modules/linux-x64/module.modulemap
new file mode 100644
index 0000000..c0842e54
--- /dev/null
+++ b/build/modules/linux-x64/module.modulemap
@@ -0,0 +1,126 @@
+// 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.
+
+// AUTOGENERATED FILE. DO NOT EDIT.
+// To regenerate, run build/modules/modularize/modularize.py
+
+
+module sys_stage1 [system] [extern_c] {
+  module sysroot_alloca_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/alloca.h"
+    export *
+  }
+  module sysroot_asm_generic_errno_base_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/asm-generic/errno-base.h"
+    export *
+  }
+  module sysroot_asm_generic_errno_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/asm-generic/errno.h"
+    export *
+  }
+  module sysroot_asm_errno_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/x86_64-linux-gnu/asm/errno.h"
+    export *
+  }
+  module sysroot_endian_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/endian.h"
+    export *
+  }
+  module sysroot_fcntl_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/fcntl.h"
+    export *
+  }
+  module sysroot_features_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/features.h"
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/x86_64-linux-gnu/sys/cdefs.h"
+    export *
+  }
+  module sysroot_gnu_stubs_64_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/x86_64-linux-gnu/gnu/stubs-64.h"
+    export *
+  }
+  module sysroot_gnu_stubs_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/x86_64-linux-gnu/gnu/stubs.h"
+    export *
+  }
+  module sysroot_linux_errno_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/linux/errno.h"
+    export *
+  }
+  module sysroot_linux_falloc_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/linux/falloc.h"
+    export *
+  }
+  module sysroot_linux_limits_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/linux/limits.h"
+    export *
+  }
+  module sysroot_locale_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/locale.h"
+    export *
+  }
+  module sysroot_nl_types_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/nl_types.h"
+    export *
+  }
+  module sysroot_pthread_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/pthread.h"
+    export *
+  }
+  module sysroot_sched_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/sched.h"
+    export *
+  }
+  module sysroot_setjmp_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/setjmp.h"
+    export *
+  }
+  module sysroot_signal_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/signal.h"
+    export *
+  }
+  module sysroot_stdc_predef_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/stdc-predef.h"
+    export *
+  }
+  module sysroot_stdio_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/stdio.h"
+    export *
+  }
+  module sysroot_strings_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/strings.h"
+    export *
+  }
+  module sysroot_sys_select_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/x86_64-linux-gnu/sys/select.h"
+    export *
+  }
+  module sysroot_sys_types_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/x86_64-linux-gnu/sys/types.h"
+    export *
+  }
+  module sysroot_sys_ucontext_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/x86_64-linux-gnu/sys/ucontext.h"
+    export *
+  }
+  module sysroot_threads_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/threads.h"
+    export *
+  }
+  module sysroot_time_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/time.h"
+    export *
+  }
+  module sysroot_unistd_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/unistd.h"
+    export *
+  }
+}
+
+module sys_stage2 [system] [extern_c] {
+  module sysroot_stdlib_h {
+    header "../../linux/debian_bullseye_amd64-sysroot/usr/include/stdlib.h"
+    export *
+  }
+}
diff --git a/build/modules/modularize/compiler.py b/build/modules/modularize/compiler.py
new file mode 100644
index 0000000..b9ba024
--- /dev/null
+++ b/build/modules/modularize/compiler.py
@@ -0,0 +1,390 @@
+# 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 collections
+import functools
+import hashlib
+import itertools
+import logging
+import pathlib
+import pickle
+import re
+import shutil
+import subprocess
+import sys
+import tempfile
+
+from graph import IncludeDir
+from graph import Header
+from graph import HeaderRef
+
+_MODULE_START = re.compile('^module ([a-z0-9_]+) ', flags=re.I)
+_HEADER = re.compile('( textual)? header "([^"]*)"')
+
+# It doesn't matter if these don't work on all platforms.
+# It'll just print a warning saying it failed to compile.
+# This contains a list of files that aren't depended on by libc++, but we still
+# want to precompile.
+_SYSROOT_PRECOMPILED_HEADERS = ['fcntl.h']
+
+
+# Some of these steps are quite slow (O(minutes)).
+# To allow for fast iteration of config, cache them.
+def _maybe_cache(fn):
+
+  @functools.wraps(fn)
+  def new_fn(self, *args, **kwargs):
+    # The results should be solely dependent on the GN out dir (assuming the
+    # user doesn't change args.gn)
+    gn_rel = str(self.gn_out.resolve()).lstrip('/')
+    cache_path = pathlib.Path(f'/tmp/modularize_cache', gn_rel, fn.__name__)
+    cache_path.parent.mkdir(exist_ok=True, parents=True)
+    if self._use_cache and cache_path.is_file():
+      return pickle.loads(cache_path.read_bytes())
+    result = fn(self, *args, **kwargs)
+    cache_path.write_bytes(pickle.dumps(result))
+    return result
+
+  return new_fn
+
+
+# We don't need a true parse, just want to determine which modules correspond
+# to which files.
+def _parse_modulemap(path: pathlib.Path) -> dict[str, list[tuple[str, bool]]]:
+  """Parses a modulemap into name -> [(header, textual)]"""
+  modules = collections.defaultdict(list)
+  with path.open() as f:
+    for line in f:
+      mod = _MODULE_START.match(line)
+      if mod is not None:
+        current_module = mod.group(1)
+      header = _HEADER.search(line)
+      if header is not None:
+        modules[current_module].append((header.group(2), bool(header.group(1))))
+  # This is a builtin module with feature requirements.
+  modules.pop('opencl_c', None)
+  return modules
+
+
+class Compiler:
+
+  def __init__(self, *, source_root: pathlib.Path, gn_out: pathlib.Path,
+               error_dir: pathlib.Path | None, use_cache: bool):
+    self._error_dir = error_dir
+    self._use_cache = use_cache
+    self.gn_out = gn_out
+    self.source_root = source_root
+
+    self.os = self._get_os()
+    self.cpu = self._get_cpu()
+
+    if self.os == 'linux':
+      self.sysroot = self.source_root / 'build/linux/debian_bullseye_amd64-sysroot/usr/include'
+    elif self.os == 'android':
+      self.sysroot = self.source_root / 'third_party/android_toolchain/ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include'
+    else:
+      self.sysroot = list(
+          source_root.glob(
+              'third_party/depot_tools/win_toolchain/vs_files/*/Windows Kits/10/Include/*'
+          ))[0]
+      self.msvc_dir = list(
+          source_root.glob(
+              'third_party/depot_tools/win_toolchain/vs_files/*/VC/Tools/MSVC/*/include'
+          ))[0]
+
+  def _parse_depfile(self, content: str) -> list[pathlib.Path]:
+    files = []
+    # The file will look like:
+    # /dev/null: <blah>.cc \
+    # <main include> \
+    # <other includes> \
+    # So we need [1:] to ensure it doesn't have a dependency on itself.
+    for line in content.rstrip().split('\n')[1:]:
+      # Remove both the trailing newlines and any escapes in the file names.
+      files.append(
+          pathlib.Path(self.gn_out,
+                       line.replace('\\', '').strip(' ')).resolve())
+    return files
+
+  def _get_gn_arg(self, name: str) -> str:
+    content = (self.gn_out / 'args.gn').read_text()
+    ps = subprocess.run(
+        ['gn', 'args', '.', f'--list={name}', '--short'],
+        text=True,
+        check=False,
+        cwd=self.gn_out,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.DEVNULL,
+    )
+
+    # GN args outputs errors to stdout, so we can't use check=True.
+    if ps.returncode != 0:
+      print(ps.stdout, file=sys.stderr)
+      exit(1)
+
+    # output format: 'target_cpu = "x64"\n'
+    return ps.stdout.rstrip().split(' = ')[1].strip('"')
+
+  def _clang_arg(self, arg: str) -> str:
+    if self.os == 'win':
+      return f'/clang:{arg}'
+    else:
+      return arg
+
+  @_maybe_cache
+  def _get_cpu(self):
+    # If the target_cpu is not explicitly set, it returns the empty string and
+    # it uses the host_cpu instead.
+    return self._get_gn_arg('target_cpu') or self._get_gn_arg('host_cpu')
+
+  @_maybe_cache
+  def _get_os(self):
+    # If the target_os is not explicitly set, it returns the empty string and
+    # it uses the host_os instead.
+    return self._get_gn_arg('target_os') or self._get_gn_arg('host_os')
+
+  def _write_err(self, rel: str, content: bytes):
+    if self._error_dir is not None:
+      out = self._error_dir / rel
+      out.parent.mkdir(exist_ok=True, parents=True)
+      out.write_bytes(content)
+
+  def split_path(self, path: pathlib.Path) -> tuple[IncludeDir, str]:
+    """Splits a path into the include directory it's under, and the string
+    needed to include it from a header file."""
+    assert path.is_absolute()
+    for d, include_dir in self.include_dirs:
+      if path.is_relative_to(d):
+        return include_dir, str(path.relative_to(d))
+
+  # Apply two layers of cache here.
+  # The _maybe_cache layer caches between runs via a file.
+  # The functools.cache layer ensures you don't keep loading the pickle file.
+  @functools.cache
+  @_maybe_cache
+  def base_command(self) -> list[str]:
+    """Returns a command suitable for building for current platform"""
+    return subprocess.run(
+        [
+            'build/modules/modularize/no_modules_compile_command.sh',
+            str(self.gn_out),
+            self.os,
+        ],
+        check=True,
+        text=True,
+        cwd=self.source_root,
+        stdout=subprocess.PIPE,
+        # Strip the -o /dev/null with [:-2]
+        # Windows requires it to be at the end, otherwise it writes to {output}.obj.
+    ).stdout.rstrip().replace('\\', '').split(' ')[:-2]
+
+  # Again, two layers of cache here to cache between runs and within a run.
+  @functools.cached_property
+  @_maybe_cache
+  def include_dirs(self) -> list[tuple[pathlib.Path, IncludeDir]]:
+    cmd = self.base_command() + [
+        '-E',
+        '-v',
+        '-x',
+        'c++',
+        '-',
+        '-o',
+        '/dev/null',
+    ]
+    cmd.remove('-c')
+    # include dir lines both start and end with whitespace
+    lines = [
+        line.strip() for line in subprocess.run(
+            cmd,
+            cwd=self.gn_out,
+            text=True,
+            check=True,
+            stderr=subprocess.PIPE,
+            # We need to pass in a "file" so we pass in - and devnull so it's
+            # an empty file.
+            stdin=subprocess.DEVNULL,
+        ).stderr.replace('\\', '').split('\n')
+    ]
+
+    dirs = lines[lines.index('#include <...> search starts here:') +
+                 1:lines.index('End of search list.')]
+    # We don't care about these.
+    dirs.remove('../..')
+    dirs.remove('gen')
+    dirs.remove('../../third_party/libc++abi/src/include')
+
+    out = []
+    for d in dirs:
+      d = (self.gn_out / d).resolve()
+      if d.is_relative_to(self.sysroot):
+        out.append((d, IncludeDir.Sysroot))
+      elif 'libc++' in d.parts:
+        out.append((d, IncludeDir.LibCxx))
+      elif 'clang' in d.parts:
+        out.append((d, IncludeDir.Builtin))
+      else:
+        raise NotImplementedError(f'Unknown include directory {d}')
+
+    return out
+
+  def compile_one(
+      self, include: str
+  ) -> tuple[subprocess.CompletedProcess, None | list[pathlib.Path]]:
+    """Compiles a single source file including {include}.
+
+    Args:
+      include: The string to #include (eg. 'vector')
+
+    Returns:
+      The result of the compilation, and either:
+        None if no depfile was created,
+        A list of all files transitively required otherwise.
+    """
+    with tempfile.TemporaryDirectory() as td:
+      source = pathlib.Path(td, 'source.cc')
+      source.write_text(f'#include <{include}>')
+      depfile = pathlib.Path(td, 'source.o.d')
+      command = self.base_command() + [
+          # We write stderr to a file
+          '-fno-color-diagnostics',
+          '-x',
+          'c++-header',
+          str(source),
+          self._clang_arg('-MD'),
+          self._clang_arg('-MF'),
+          self._clang_arg(depfile),
+          '-o',
+          '/dev/null',
+      ]
+      if logging.getLogger().isEnabledFor(logging.DEBUG):
+        logging.debug('Running command: (cd %s && %s)', self.gn_out,
+                      ' '.join(command))
+      ps = subprocess.run(
+          command,
+          stderr=subprocess.PIPE,
+          cwd=self.gn_out,
+      )
+      # The depfile is generated even if it fails to compile.
+      try:
+        return ps, self._parse_depfile(depfile.read_text())
+      except FileNotFoundError:
+        return ps, None
+
+  @_maybe_cache
+  def compile_all(self) -> dict[HeaderRef, Header]:
+    """Generates a graph of headers by compiling all files in the sysroot."""
+    if self._error_dir is not None:
+      shutil.rmtree(self._error_dir, ignore_errors=True)
+
+    graph: dict[HeaderRef, Header] = {}
+    uncompiled = []
+    seen = set()
+
+    def visit(include: str):
+      if include not in seen:
+        uncompiled.append(include)
+        seen.add(include)
+
+    # Use a list as a set because it's tiny.
+    seen_dirs = [IncludeDir.Sysroot]
+
+    def add_to_dfs(kind: IncludeDir, modulemap: pathlib.Path):
+      if kind in seen_dirs:
+        return
+      seen_dirs.append(kind)
+      for mod, files in _parse_modulemap(modulemap).items():
+        for path, textual in files:
+          graph[(kind, path)] = Header(include_dir=kind,
+                                       rel=path,
+                                       root_module=mod,
+                                       textual=textual)
+          visit(path)
+
+    # Populate a list of initial headers to compile.
+    add_to_dfs(
+        IncludeDir.LibCxx,
+        self.source_root / 'third_party/libc++/src/include/module.modulemap.in')
+    for header in _SYSROOT_PRECOMPILED_HEADERS:
+      visit(header)
+
+    # Could consider making the DFS parallel to improve performance.
+    # But it's a lot of effort for a script that's rarely run.
+    while uncompiled:
+      rel = uncompiled.pop()
+
+      ps, files = self.compile_one(rel)
+      if files is None:
+        logging.warning("Failed to generate depfile while compiling %s", rel)
+        self._write_err(rel, ps.stderr)
+        continue
+
+      abs_path = files[0]
+      kind, _ = self.split_path(abs_path)
+
+      # The first time we come across a builtin header, we use that to find
+      # the builtin modulemap to ensure we compile every module in it.
+      add_to_dfs(
+          kind,
+          abs_path.parents[rel.count('/')] / 'module.modulemap',
+      )
+
+      if (kind, rel) not in graph:
+        # If we're seeing it for the first time here, but it's from another
+        # include dir, it must not be in the module map, so it should be treated as textual.
+        graph[(kind, rel)] = Header(include_dir=kind,
+                                    rel=rel,
+                                    textual=kind != IncludeDir.Sysroot)
+      state = graph[(kind, rel)]
+      state.abs = abs_path
+
+      for to_abs in files[1:]:
+        to_kind, to_rel = self.split_path(to_abs)
+        assert (kind, rel) != (to_kind, to_rel)
+        if (to_kind, to_rel) not in graph:
+          graph[(to_kind, to_rel)] = Header(
+              include_dir=to_kind,
+              rel=to_rel,
+              abs=to_abs,
+              textual=to_kind != IncludeDir.Sysroot,
+          )
+        state.deps.append((to_kind, to_rel))
+        visit(to_rel)
+
+      if ps.returncode == 0:
+        logging.debug('Compiled %s', state.pretty_name)
+      elif any([
+          state.textual,
+          rel.startswith('bits/'), '/bits/' in rel,
+          rel.endswith('intrin.h')
+      ]):
+        # These things are generally expected to not compile standalone.
+        logging.debug('Probably fine: Failed to compile %s', state.pretty_name)
+      else:
+        if state.root_module != None:
+          logging.warning('%s was not textual but failed to compile',
+                          state.pretty_name)
+        else:
+          # Since this isn't part of a modulemap we can choose to mark it as
+          # textual.
+          logging.warning('Failed to compile %s', state.pretty_name)
+        self._write_err(rel, ps.stderr)
+
+      # If you can't compile it, assume it's textual
+      if state.root_module is None and ps.returncode != 0:
+        state.textual = True
+
+    assert IncludeDir.Builtin in seen_dirs
+
+    for header in graph.values():
+      if header.abs is None:
+        for d, kind in self.include_dirs:
+          if header.include_dir == kind and (d / header.rel).is_file():
+            header.abs = d / header.rel
+            break
+      assert header.abs is not None
+
+      for dep in header.deps:
+        assert dep in graph
+
+    return graph
diff --git a/build/modules/modularize/compiler_test.py b/build/modules/modularize/compiler_test.py
new file mode 100644
index 0000000..7f72837
--- /dev/null
+++ b/build/modules/modularize/compiler_test.py
@@ -0,0 +1,104 @@
+# 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 pathlib
+import unittest
+import tempfile
+import textwrap
+
+from compiler import _maybe_cache
+from compiler import _parse_modulemap
+from compiler import Compiler
+from modularize import SOURCE_ROOT
+
+
+class TestableCompiler(Compiler):
+  n = 1
+
+  @_maybe_cache
+  def cached_n(self):
+    return self.n
+
+  # Override these to prevent it from invoking GN
+  def _get_os(self):
+    return 'linux'
+
+  def _get_cpu(self):
+    return 'x64'
+
+
+class CompilerTest(unittest.TestCase):
+
+  def setUp(self):
+    super().setUp()
+    self.compiler1 = TestableCompiler(
+        gn_out=pathlib.Path('/tmp/compiler1'),
+        source_root=SOURCE_ROOT,
+        error_dir=None,
+        use_cache=True,
+    )
+    self.compiler1_uncached = TestableCompiler(
+        gn_out=pathlib.Path('/tmp/compiler1'),
+        source_root=SOURCE_ROOT,
+        error_dir=None,
+        use_cache=False,
+    )
+    self.compiler2 = TestableCompiler(
+        gn_out=pathlib.Path('/tmp/compiler2'),
+        source_root=SOURCE_ROOT,
+        error_dir=None,
+        use_cache=True,
+    )
+
+  def test_maybe_cache(self):
+    # Uncached compilers should write to the cache, but not read from it.
+    self.compiler1.n = 2
+    self.assertEqual(self.compiler1_uncached.cached_n(), 1)
+    self.assertEqual(self.compiler1.cached_n(), 1)
+    self.compiler1_uncached.n = 3
+    self.assertEqual(self.compiler1_uncached.cached_n(), 3)
+    self.assertEqual(self.compiler1.cached_n(), 3)
+
+    # This one should be unrelated since it has a different gn_out dir.
+    self.compiler2.n = 4
+    self.assertEqual(self.compiler2.cached_n(), 4)
+
+  def test_parse_modulemap(self):
+    self.assertDictEqual(
+        # It's a defaultdict
+        _parse_modulemap(SOURCE_ROOT /
+                         'build/modules/modularize/testdata/module.modulemap'),
+        {
+            'first': [
+                ('first.h', False),
+                ('../first_textual.h', True),
+            ],
+            'second': [
+                ('second.h', False),
+                ('../second_textual.h', True),
+            ]
+        },
+    )
+
+  def test_parse_depfile(self):
+    self.assertListEqual(
+        self.compiler1._parse_depfile(
+            textwrap.dedent("""\
+          /dev/null: /tmp/main.cc \\
+            ../up.cc \\
+            path/to/relative.cc \\
+            /path/to/absolute.cc \\
+            path\\ with\\ spaces.cc \\
+          """)),
+        [
+            pathlib.Path('/tmp/up.cc'),
+            pathlib.Path('/tmp/compiler1/path/to/relative.cc'),
+            pathlib.Path('/path/to/absolute.cc'),
+            pathlib.Path('/tmp/compiler1/path with spaces.cc'),
+        ],
+    )
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/modules/modularize/config.py b/build/modules/modularize/config.py
new file mode 100644
index 0000000..f93c6d0
--- /dev/null
+++ b/build/modules/modularize/config.py
@@ -0,0 +1,86 @@
+# Copyright 2025 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import collections
+import pathlib
+
+from graph import IncludeDir
+from graph import Header
+from graph import HeaderRef
+
+
+def fix_graph(graph: dict[HeaderRef, Header], os: str, cpu: str):
+  """Applies manual augmentation of the header graph."""
+  is_apple = os in ['mac', 'ios']
+
+  # Deal with include_next for modules with modulemaps.
+  # We were only able to compile the one in the first include dir.
+  # To solve this, we copy all dependencies except the shadow to the shadowed
+  # header file.
+  # eg. If libcxx/stddef.h has deps [builtin/stddef.h, sysroot/stdint.h], we
+  # set the deps of builtin/stddef.h to [sysroot/stdint.h]
+  includes = {}
+  for rel in {header.rel for header in graph.values()}:
+    order = []
+    for d in IncludeDir:
+      header = graph.get((d, rel), None)
+      if header is not None:
+        order.append(header)
+    for prev, header in zip(order, order[1:]):
+      header.deps = [(to_kind, to_rel) for (to_kind, to_rel) in order[0].deps
+                     if to_rel != header.rel or to_kind > header.include_dir]
+      header.prev = prev
+      prev.next = header
+    includes[rel] = order
+
+  for header in graph.values():
+    header.direct_deps = header.calculate_direct_deps(includes)
+
+  if is_apple:
+    # From here on out we're modifying which headers are textual.
+    # This isn't relevant to apple since it has a modulemap.
+    return
+
+  # Calculate a reverse dependency graph
+  rdeps = collections.defaultdict(list)
+  for header in graph.values():
+    for dep in header.deps:
+      rdeps[graph[dep]].append(header)
+
+  sysroot = lambda rel, kind=IncludeDir.Sysroot: graph[(kind, rel)]
+
+  for header in graph.values():
+    if header.include_dir != IncludeDir.Sysroot:
+      continue
+
+    parts = set(pathlib.Path(header.rel).parts)
+    # We want non-textual, but we don't need to do so if the header including
+    # you via include_next is non-textual.
+    if header.prev is not None:
+      header.textual = not header.prev.textual
+    # Anything not to be included by the user directly that was only included
+    # once can be marked as textual. Unfortunately since .d files calculate
+    # *transitive* dependencies this is not particularly effective.
+    elif (len(rdeps[header]) < 2
+          and parts.intersection(['asm', 'asm-generic', 'bits'])):
+      header.textual = True
+    elif '#pragma once' in (header.content or ''):
+      header.textual = False
+    elif 'bits' in parts:
+      header.textual = True
+
+  # Assert is inherently textual.
+  sysroot('assert.h').textual = True
+
+  # This is included from the std_wchar_h module, but that module is marked as
+  # textual. Normally that would mean we would mark this as non-textual, but
+  # wchar.h doesn't play nice being non-textual.
+  sysroot('wchar.h').textual = True
+
+  if os == 'android':
+    graph[(IncludeDir.LibCxx, 'wchar.h')].public_configs.append(
+        '//buildtools/third_party/libc++:wchar_android_fix')
+
+    sysroot('android/legacy_threads_inlines.h').textual = True
+    sysroot('bits/threads_inlines.h').textual = True
diff --git a/build/modules/modularize/graph.py b/build/modules/modularize/graph.py
new file mode 100644
index 0000000..6e18bfc
--- /dev/null
+++ b/build/modules/modularize/graph.py
@@ -0,0 +1,224 @@
+# 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.
+
+from __future__ import annotations
+
+import collections
+import dataclasses
+import enum
+import functools
+import itertools
+import pathlib
+import re
+
+_INCLUDES = re.compile(r'#\s*include(_next)?\s*<([^>]+)>')
+
+
+class IncludeDir(enum.Enum):
+  # Ordered by include order for clang
+  LibCxx = 1
+  Builtin = 2
+  DarwinBasic = 3
+  DarwinFoundation = 4
+  CStandardLibrary = 5
+  Sysroot = 6
+
+  def __lt__(self, other):
+    return self.value < other.value
+
+
+HeaderRef = tuple[IncludeDir, str]
+
+
+@dataclasses.dataclass
+class Header:
+  include_dir: IncludeDir
+  # The string to use in your #include statement to get this file.
+  rel: str
+  # The absolute path to the file
+  # This should be filled by the time the compiler finishes.
+  abs: pathlib.Path = None
+  # Prev and next come from include_next / include_prev
+  prev: None | Header = None
+  next: None | Header = None
+  root_module: None | str = None
+  textual: bool = False
+  deps: list[HeaderRef] = dataclasses.field(default_factory=list)
+  direct_deps: set[Header] = dataclasses.field(default_factory=set)
+  # Here, None means no exports, and the empty list means 'export *'
+  # We default to exporting all to preserve the behaviour of includes.
+  exports: None | list[HeaderRef] = dataclasses.field(default_factory=list)
+
+  # Any configs required to build this file.
+  public_configs: list[str] = dataclasses.field(default_factory=list)
+
+  def __hash__(self):
+    return hash((self.include_dir, self.rel))
+
+  def __eq__(self, other):
+    return (self.include_dir, self.rel) == (other.include_dir, other.rel)
+
+  def __lt__(self, other):
+    return (self.include_dir, self.rel) < (other.include_dir, other.rel)
+
+  @property
+  def pretty_name(self):
+    return f'{self.include_dir.name}/{self.rel}'
+
+  def __repr__(self):
+    return self.pretty_name
+
+  @property
+  def submodule_name(self):
+    normalized = self.rel.replace('.', '_').replace('/', '_').replace('-', '_')
+    return 'sysroot_' + normalized
+
+  @functools.cached_property
+  def content(self) -> None | str:
+    return self.abs.read_text()
+
+  def calculate_direct_deps(self, includes: dict[str,
+                                                 list[Header]]) -> set[Header]:
+    direct = set()
+    for is_next, include in _INCLUDES.findall(self.content):
+      header = None
+      order = includes.get(include, [])
+      if is_next and self in order[:-1]:
+        header = order[order.index(self) + 1]
+      if not is_next and order:
+        header = order[0]
+
+      # It might have been conditionally included.
+      if header is not None and (header.include_dir, header.rel) in self.deps:
+        direct.add(header)
+    return direct
+
+  def direct_deps_closure(self) -> set[Header]:
+    closure = set(self.direct_deps)
+    for dep in self.direct_deps:
+      if dep.textual:
+        closure.remove(dep)
+        closure.update(dep.direct_deps_closure())
+    return closure
+
+
+@dataclasses.dataclass
+class Target:
+  """Represents a single clang module / gn target."""
+  include_dir: IncludeDir
+  name: str
+  headers: list[Header] = dataclasses.field(default_factory=list)
+
+  def __lt__(self, other):
+    return self.name < other.name
+
+
+def run_build(graph: dict[HeaderRef, Header]) -> list[Target]:
+  """Calculates the correct way to run a build."""
+  unbuilt_modules: dict[str, list[Header]] = collections.defaultdict(list)
+  unbuilt_headers: set[Header] = set()
+
+  for header in graph.values():
+    if not header.textual:
+      if header.root_module is None:
+        unbuilt_headers.add(header)
+      else:
+        unbuilt_modules[header.root_module].append(header)
+    header.rdeps = set()
+    # A group is a set of headers that must be compiled together, because they
+    # form a dependency loop.
+    header.group = [header]
+    header.mod_deps = set()
+    header.unbuilt_deps = set([
+        graph[dep] for dep in header.deps
+        # Textual headers don't need to be built.
+        # Also, you don't need to wait for a dependency within the same module.
+        if not graph[dep].textual and \
+          (header.root_module is None or \
+           header.root_module != graph[dep].root_module)
+    ])
+
+  for header in graph.values():
+    for dep in header.unbuilt_deps:
+      dep.rdeps.add(header)
+
+  # Break dependency loops.
+  for header in sorted(graph.values()):
+    for dep in list(header.unbuilt_deps):
+      # Mark all headers but one in the loop as already having been built.
+      if header in dep.unbuilt_deps and header.include_dir == IncludeDir.Sysroot and dep.include_dir == IncludeDir.Sysroot:
+        header.group.append(dep)
+        dep.group = header.group
+        for rdep in dep.rdeps:
+          assert header is rdep or header in rdep.unbuilt_deps
+          rdep.unbuilt_deps.remove(dep)
+        unbuilt_headers.remove(dep)
+
+  build_gn = []
+
+  for i in itertools.count():
+    # Try and build any buildable modules from modulemaps.
+    while True:
+      n_remaining = len(unbuilt_modules)
+      for mod, headers in list(unbuilt_modules.items()):
+        if not any(header.unbuilt_deps for header in headers):
+          build_gn.append(
+              Target(
+                  include_dir=headers[0].include_dir,
+                  name=mod,
+                  headers=sorted(headers),
+              ))
+          del unbuilt_modules[mod]
+          for header in headers:
+            for rdep in header.rdeps:
+              rdep.mod_deps.add(header.root_module)
+              rdep.unbuilt_deps.remove(header)
+
+      if n_remaining == len(unbuilt_modules):
+        break
+
+    # Try and build any builtable sysroot modules
+    sysroot_mod = f'sys_stage{i + 1}'
+    build_gn.append(Target(
+        include_dir=IncludeDir.Sysroot,
+        name=sysroot_mod,
+    ))
+    while True:
+      n_remaining = len(unbuilt_headers)
+      for header in list(unbuilt_headers):
+        if not header.unbuilt_deps:
+          header.root_module = sysroot_mod
+          build_gn[-1].headers.append(header)
+          unbuilt_headers.remove(header)
+          for rdep in header.rdeps:
+            rdep.mod_deps.add(header.root_module)
+            rdep.unbuilt_deps.remove(header)
+
+      if n_remaining == len(unbuilt_headers):
+        break
+
+    build_gn[-1].headers.sort()
+    if not build_gn[-1].headers:
+      break
+
+  build_gn.pop()
+
+  if not unbuilt_modules and not unbuilt_headers:
+    # Success. Everything is built
+    return build_gn
+  else:
+    print(
+        "Dependency loop in sysroot. You probably want to make one of them textual."
+    )
+    print("The following headers are in a dependency loop:")
+    pairs = set()
+    for header in unbuilt_headers:
+      for dep in header.unbuilt_deps:
+        if header in dep.unbuilt_deps:
+          print(f'{header.pretty_name} -> {dep.pretty_name}')
+
+    # If you get to this point, you probably want a debugger to help understand what the problem is.
+    sysroot = lambda rel: graph[(IncludeDir.Sysroot, rel)]
+    breakpoint()
+    exit(1)
diff --git a/build/modules/modularize/modularize.py b/build/modules/modularize/modularize.py
new file mode 100755
index 0000000..575ee91
--- /dev/null
+++ b/build/modules/modularize/modularize.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python
+
+# 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.
+"""Modularize modularizes a platform."""
+
+import argparse
+import logging
+import pathlib
+import shutil
+import sys
+import tempfile
+from config import fix_graph
+from graph import run_build
+from render import render_build_gn
+from render import render_modulemap
+from compiler import Compiler
+
+SOURCE_ROOT = pathlib.Path(__file__).parents[3].resolve()
+
+
+def main(args):
+  logging.basicConfig(level=logging.getLevelNamesMapping()[args.verbosity])
+
+  compiler = Compiler(
+      source_root=SOURCE_ROOT,
+      gn_out=args.C.resolve(),
+      error_dir=None if args.error_log is None else args.error_log.resolve(),
+      use_cache=args.cache,
+  )
+  platform = f'{compiler.os}-{compiler.cpu}'
+  logging.info('Detected platform %s', platform)
+
+  out_dir = SOURCE_ROOT / f'build/modules/{platform}'
+  # Otherwise gn will error out because it tries to import a file that doesn't exist.
+  if not out_dir.is_dir():
+    shutil.copytree(out_dir.parent / 'linux-x64', out_dir)
+
+  if args.compile:
+    with tempfile.TemporaryDirectory() as td:
+      ps, files = compiler.compile_one(args.compile, pathlib.Path(td, 'source'))
+      print('stderr:', ps.stderr.decode('utf-8'), file=sys.stderr)
+      print('Files used:')
+      print('\n'.join(sorted(map(str, files))))
+      print('Setting breakpoint to allow further debugging')
+      breakpoint()
+      return
+
+  graph = compiler.compile_all()
+  fix_graph(graph, compiler.os, compiler.cpu)
+  targets = run_build(graph)
+  out_dir.mkdir(exist_ok=True, parents=False)
+  # Since apple provides a modulemap, we only need to create a BUILD.gn file.
+  if compiler.os not in ['mac', 'ios']:
+    render_modulemap(out_dir=out_dir, sysroot=compiler.sysroot, targets=targets)
+  textual_headers = [hdr for hdr in graph.values() if hdr.textual]
+  render_build_gn(out_dir=out_dir,
+                  textual_headers=textual_headers,
+                  targets=targets)
+
+
+if __name__ == '__main__':
+  parser = argparse.ArgumentParser()
+  parser.add_argument('-C', type=pathlib.Path)
+
+  # Make it required so the user understands how compilation works.
+  cache = parser.add_mutually_exclusive_group(required=True)
+  cache.add_argument(
+      '--cache',
+      action='store_true',
+      help='Enable caching. Will attempt to reuse the compilation results.')
+  cache.add_argument(
+      '--no-cache',
+      action='store_false',
+      dest='cache',
+      help=
+      'Disable caching. Will attempt to recompile the whole libcxx, builtins, and sysroot on every invocation'
+  )
+
+  parser.add_argument(
+      '--compile',
+      help='Compile a single header file',
+  )
+
+  parser.add_argument('--error-log',
+                      type=lambda value: pathlib.Path(value) if value else None)
+
+  parser.add_argument(
+      '--verbosity',
+      help='Verbosity of logging',
+      default='INFO',
+      choices=logging.getLevelNamesMapping().keys(),
+      type=lambda x: x.upper(),
+  )
+
+  main(parser.parse_args())
diff --git a/build/modules/modularize/render.py b/build/modules/modularize/render.py
new file mode 100644
index 0000000..d74c11e
--- /dev/null
+++ b/build/modules/modularize/render.py
@@ -0,0 +1,134 @@
+# 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 contextlib
+import io
+import pathlib
+
+from graph import Header
+from graph import IncludeDir
+from graph import Target
+
+_HEADER = """# 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.
+
+# AUTOGENERATED FILE. DO NOT EDIT.
+# To regenerate, run build/modules/modularize/modularize.py
+
+"""
+
+
+def _update_content(path: pathlib.Path, content: str):
+  """Updates the content of a file if changed, thus preventing a siso reload."""
+  with contextlib.suppress(FileNotFoundError):
+    if path.read_text() == content:
+      return
+  path.write_text(content)
+
+
+def render_modulemap(out_dir: pathlib.Path, sysroot: pathlib.Path,
+                     targets: list[Target]):
+  """Writes a modulemap to {out_dir}"""
+  f = io.StringIO()
+  f.write(_HEADER.replace('#', '//'))
+  for target in targets:
+    if target.include_dir != IncludeDir.Sysroot:
+      continue
+    f.write(f'\nmodule {target.name} [system] [extern_c] {{\n')
+    for header in target.headers:
+      assert header.include_dir == IncludeDir.Sysroot
+      f.write(f'  module {header.submodule_name} {{\n')
+      for single in sorted(header.group):
+        assert single.abs is not None
+        f.write(
+            f'    header "{single.abs.relative_to(out_dir, walk_up=True)}"\n')
+      if not header.exports and header.exports is not None:
+        f.write('    export *\n')
+      for export in header.exports or []:
+        f.write(f'    export {export.submodule_name}\n')
+
+      f.write('  }\n')
+
+    f.write('}\n')
+  _update_content(out_dir / 'module.modulemap', f.getvalue())
+
+
+def _render_string_list(f,
+                        indent: int,
+                        key: str,
+                        values: list[str],
+                        add: str | None = None):
+  if not values and add is None:
+    return
+  indent = " " * indent
+  f.write(f'{indent}{key} = ')
+  if add is not None:
+    f.write(add)
+    if values:
+      f.write(' + ')
+
+  if len(values) == 1:
+    f.write(f'[ "{values[0]}" ]\n')
+  elif len(values) > 1:
+    f.write(f'[\n')
+    for value in values:
+      f.write(f'{indent}  "{value}",\n')
+    f.write(f'{indent}]\n')
+  else:
+    f.write('\n')
+
+
+def render_build_gn(out_dir: pathlib.Path, targets: list[Target],
+                    textual_headers: list[Header]):
+  """Renders a BUILD.gn file for a specific platform to {out_dir}"""
+  # textual configs are associated with textual headers, so we just apply them
+  # indiscriminately since they're not for compiling a specific target.
+  textual_configs = sorted(
+      {cfg
+       for hdr in textual_headers
+       for cfg in hdr.public_configs})
+
+  f = io.StringIO()
+  f.write(_HEADER)
+  f.write('import("//buildtools/third_party/libc++/modules.gni")\n\n')
+  if textual_configs:
+    _render_string_list(f, 0, 'textual_configs', textual_configs)
+    f.write('\n')
+  for target in sorted(targets):
+    direct_deps = set()
+    for hdr in target.headers:
+      direct_deps.update(hdr.direct_deps_closure())
+    public_deps = sorted({
+        f':{hdr.root_module}'
+        for hdr in direct_deps
+        if hdr.root_module is not None and hdr.root_module != target.name
+    })
+
+    rule = {
+        IncludeDir.LibCxx: 'libcxx_module',
+        IncludeDir.Sysroot: 'sysroot_module',
+        IncludeDir.Builtin: 'builtin_module',
+    }[target.include_dir]
+    f.write(f'{rule}("{target.name}") {{\n')
+    _render_string_list(f, 2, 'public_deps', public_deps)
+    configs = sorted([
+        c for header in target.headers for single in header.group
+        for c in single.public_configs
+    ])
+    _render_string_list(f,
+                        2,
+                        'public_configs',
+                        sorted(configs),
+                        add='textual_configs' if textual_configs else None)
+    f.write('}\n\n')
+
+  f.write('alias("all_modules") {\n')
+  f.write('  actual = [\n')
+  for target in sorted(targets):
+    f.write(f'    ":{target.name}",\n')
+  f.write('  ]\n')
+  f.write('}\n')
+
+  _update_content(out_dir / 'BUILD.gn', f.getvalue())
diff --git a/build/modules/modularize/testdata/module.modulemap b/build/modules/modularize/testdata/module.modulemap
new file mode 100644
index 0000000..c94b889
--- /dev/null
+++ b/build/modules/modularize/testdata/module.modulemap
@@ -0,0 +1,17 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module first [system] [extern_c] {
+  header "first.h"
+  module submod {
+    textual header "../first_textual.h"
+  }
+}
+
+module second [system] [extern_c] {
+  header "second.h"
+  module submod {
+    textual header "../second_textual.h"
+  }
+}
\ No newline at end of file
diff --git a/build/toolchain/apple/toolchain.gni b/build/toolchain/apple/toolchain.gni
index a83b703..6c86f73 100644
--- a/build/toolchain/apple/toolchain.gni
+++ b/build/toolchain/apple/toolchain.gni
@@ -188,6 +188,7 @@
       ld += " -B " + invoker.bin_path
     }
 
+    coverage_wrapper = ""
     if (defined(toolchain_args.coverage_instrumentation_input_file)) {
       toolchain_coverage_instrumentation_input_file =
           toolchain_args.coverage_instrumentation_input_file
@@ -203,8 +204,7 @@
                       root_build_dir) + " --files-to-instrument=" +
           rebase_path(toolchain_coverage_instrumentation_input_file,
                       root_build_dir) + " --target-os=" + target_os
-      cc = "\"$python_path\" $_coverage_wrapper ${cc}"
-      cxx = "\"$python_path\" $_coverage_wrapper ${cxx}"
+      coverage_wrapper = "\"$python_path\" ${_coverage_wrapper} "
     }
 
     linker_driver_env = "TOOL_VERSION=${tool_versions.linker_driver}"
@@ -398,7 +398,7 @@
     tool("cc") {
       depfile = "{{output}}.d"
       precompiled_header_type = "gcc"
-      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+      command = "$coverage_wrapper$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
       depsformat = "gcc"
       description = "CC {{output}}"
       outputs = [ "$object_subdir/{{source_name_part}}.o" ]
@@ -407,7 +407,7 @@
     tool("cxx") {
       depfile = "{{output}}.d"
       precompiled_header_type = "gcc"
-      command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} {{module_deps_no_self}} -c {{source}} -o {{output}}"
+      command = "$coverage_wrapper$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} {{module_deps_no_self}} -c {{source}} -o {{output}}"
       depsformat = "gcc"
       description = "CXX {{output}}"
       outputs = [ "$object_subdir/{{source_name_part}}.o" ]
@@ -416,6 +416,9 @@
     tool("cxx_module") {
       depfile = "{{output}}.d"
       precompiled_header_type = "gcc"
+
+      # Module file doesn't need coverage instrumentation because module files
+      # represent interfaces rather than implementations.
       command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} {{module_deps_no_self}} -fmodule-name={{label_name}} -c -x c++ -Xclang -emit-module {{source}} -o {{output}}"
       depsformat = "gcc"
       description = "CXX_MODULE {{output}}"
@@ -434,7 +437,7 @@
     tool("objc") {
       depfile = "{{output}}.d"
       precompiled_header_type = "gcc"
-      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objc}} -c {{source}} -o {{output}}"
+      command = "$coverage_wrapper$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objc}} -c {{source}} -o {{output}}"
       depsformat = "gcc"
       description = "OBJC {{output}}"
       outputs = [ "$object_subdir/{{source_name_part}}.o" ]
@@ -443,7 +446,7 @@
     tool("objcxx") {
       depfile = "{{output}}.d"
       precompiled_header_type = "gcc"
-      command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objcc}} -c {{source}} -o {{output}}"
+      command = "$coverage_wrapper$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objcc}} -c {{source}} -o {{output}}"
       depsformat = "gcc"
       description = "OBJCXX {{output}}"
       outputs = [ "$object_subdir/{{source_name_part}}.o" ]
diff --git a/chrome/VERSION b/chrome/VERSION
index f44f807d..93466e2 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=140
 MINOR=0
-BUILD=7336
+BUILD=7338
 PATCH=0
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 369d21280..1ffff5bc 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -19091,7 +19091,7 @@
         Got it
       </message>
       <message name="IDS_MULTI_CAPTURE_NOTIFICATION_BUTTON_TEXT" desc="Text for the notification button to reach the details view.">
-        View details
+        Details
       </message>
     </if>
 
diff --git a/chrome/app/generated_resources_grd/IDS_MULTI_CAPTURE_NOTIFICATION_BUTTON_TEXT.png.sha1 b/chrome/app/generated_resources_grd/IDS_MULTI_CAPTURE_NOTIFICATION_BUTTON_TEXT.png.sha1
index eadc30a..3f97fdeb0 100644
--- a/chrome/app/generated_resources_grd/IDS_MULTI_CAPTURE_NOTIFICATION_BUTTON_TEXT.png.sha1
+++ b/chrome/app/generated_resources_grd/IDS_MULTI_CAPTURE_NOTIFICATION_BUTTON_TEXT.png.sha1
@@ -1 +1 @@
-93809d069ae3c74e1d2be65b047141bb0a55e679
\ No newline at end of file
+5d72b293c3a6c67512e841e6dd6563ce5ee01f66
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 2770375..6f92f0ba 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1800,6 +1800,7 @@
     "//chrome/browser/ui/javascript_dialogs:impl",
     "//chrome/browser/ui/omnibox:impl",
     "//chrome/browser/ui/page_info:impl",
+    "//chrome/browser/ui/startup:impl",
     "//chrome/browser/ui/prefs:impl",
     "//chrome/browser/ui/safety_hub:impl",
     "//chrome/browser/ui/toolbar:impl",
@@ -2086,6 +2087,7 @@
     "//chrome/browser/ui/search_engines",
     "//chrome/browser/ui/side_search",
     "//chrome/browser/ui/startup",
+    "//chrome/browser/ui/startup:impl",
     "//chrome/browser/ui/sync",
     "//chrome/browser/ui/sync:impl",
     "//chrome/browser/ui/translate",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 24c5b97..0aa9636 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -4735,14 +4735,6 @@
 };
 #endif  // !BUILDFLAG(IS_ANDROID)
 
-const FeatureEntry::Choice kActFeaturesChoices[] = {
-    {"Default", "", ""},
-    {"Enabled", switches::kEnableFeatures,
-     "IpProtectionUx, FingerprintingProtectionUx, ActUserBypassUx"},
-    {"Disabled", switches::kDisableFeatures,
-     "IpProtectionUx, FingerprintingProtectionUx, ActUserBypassUx"},
-};
-
 // LINT.IfChange(DataSharingVersioningChoices)
 const FeatureEntry::Choice kDataSharingVersioningStateChoices[] = {
     {"Default", "", ""},
@@ -8999,10 +8991,6 @@
      flag_descriptions::kDoubleBufferCompositingDescription, kOsCrOS,
      SINGLE_VALUE_TYPE(switches::kDoubleBufferCompositing)},
 
-    {"act-features", flag_descriptions::kActFeaturesName,
-     flag_descriptions::kActFeaturesDescription, kOsDesktop | kOsAndroid,
-     MULTI_VALUE_TYPE(kActFeaturesChoices)},
-
     {"tracking-protection-3pcd", flag_descriptions::kTrackingProtection3pcdName,
      flag_descriptions::kTrackingProtection3pcdDescription,
      kOsDesktop | kOsAndroid,
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 81d5bdf..fc8ea76 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -49,13 +49,6 @@
     "expiry_milestone": 145
   },
   {
-    "name": "act-features",
-    "owners": [
-      "fmacintosh@google.com"
-    ],
-    "expiry_milestone": 140
-  },
-  {
     "name": "adaptive-button-in-top-toolbar-page-summary",
     "owners": [ "salg@google.com", "chrome-segmentation-platform@google.com" ],
     "expiry_milestone": 140
@@ -7951,7 +7944,7 @@
       "slutskii@google.com",
       "cros-3pidp@google.com"
     ],
-    "expiry_milestone": 140
+    "expiry_milestone": 143
   },
   {
     "name": "policy-promotion-banner-flag",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 9cdd6403..db33364 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -4230,9 +4230,6 @@
     "Provides a control for enabling/disabling Third-Party Cookie Deprecation "
     "Metadata Grants (WRT its default state) for testing.";
 
-const char kActFeaturesName[] = "ACT Features";
-const char kActFeaturesDescription[] = "Enable ACT features";
-
 const char kTrackingProtection3pcdName[] = "Tracking Protection for 3PCD";
 const char kTrackingProtection3pcdDescription[] =
     "Enables the tracking protection UI + prefs that will be used for the 3PCD "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 01616ec..2613d7fe4 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2402,9 +2402,6 @@
 extern const char kTpcdMetadataGrantsName[];
 extern const char kTpcdMetadataGrantsDescription[];
 
-extern const char kActFeaturesName[];
-extern const char kActFeaturesDescription[];
-
 extern const char kTrackingProtection3pcdName[];
 extern const char kTrackingProtection3pcdDescription[];
 
diff --git a/chrome/browser/lifetime/browser_close_manager.cc b/chrome/browser/lifetime/browser_close_manager.cc
index 47b495c..28724af 100644
--- a/chrome/browser/lifetime/browser_close_manager.cc
+++ b/chrome/browser/lifetime/browser_close_manager.cc
@@ -194,7 +194,7 @@
       // force skip these warnings and manually close all the tabs to make sure
       // the browser is destroyed and cleanup can happen.
       browser->tab_strip_model()->CloseAllTabs();
-      browser->window()->DestroyBrowser();
+      browser->SynchronouslyDestroyBrowser();
       // Destroying the browser should have removed it from the browser list.
       DCHECK(!base::Contains(*BrowserList::GetInstance(), browser));
     }
diff --git a/chrome/browser/media/webrtc/multi_capture/multi_capture_usage_indicator_service.cc b/chrome/browser/media/webrtc/multi_capture/multi_capture_usage_indicator_service.cc
index 38c989f..9f69828 100644
--- a/chrome/browser/media/webrtc/multi_capture/multi_capture_usage_indicator_service.cc
+++ b/chrome/browser/media/webrtc/multi_capture/multi_capture_usage_indicator_service.cc
@@ -246,9 +246,8 @@
       message_center::NotificationType::NOTIFICATION_TYPE_SIMPLE,
       // TODO(crbug.com/428895081): Prevent this text from being trimmed.
       kPrivacyIndicatorsMultiCaptureLoginNotificationId,
-      /*title=*/u"",
-      /*message=*/
-      CreateFutureCaptureNotificationMessage(apps),
+      /*title=*/CreateFutureCaptureNotificationMessage(apps),
+      /*message=*/u"",
       /*icon=*/ui::ImageModel(),
       /*display_source=*/std::u16string(),
       /*origin_url=*/GURL(),
@@ -275,7 +274,6 @@
 
   notification.set_system_notification_warning_level(
       message_center::SystemNotificationWarningLevel::NORMAL);
-  notification.set_accent_color_id(ui::kColorAshPrivacyIndicatorsBackground);
   return notification;
 }
 
@@ -310,14 +308,14 @@
   message_center::Notification notification(
       message_center::NotificationType::NOTIFICATION_TYPE_SIMPLE,
       notification_id,
-      /*title=*/u"",
-      /*message=*/
+      /*title=*/
       base::i18n::MessageFormatter::FormatWithNamedArgs(
           l10n_util::GetStringUTF16(
               IDS_MULTI_CAPTURE_ACTIVE_CAPTURE_NOTIFICATION_MESSAGE),
           "NUM_APPS", /*plurality=*/1, "APP_NAME",
           gfx::TruncateString(base::UTF8ToUTF16(app_name), kAppLength,
                               gfx::BreakType::WORD_BREAK)),
+      /*message=*/u"",
       /*icon=*/ui::ImageModel(),
       /*display_source=*/std::u16string(),
       /*origin_url=*/GURL(),
@@ -330,7 +328,6 @@
       base::MakeRefCounted<message_center::NotificationDelegate>());
   notification.set_system_notification_warning_level(
       message_center::SystemNotificationWarningLevel::NORMAL);
-  notification.set_accent_color_id(ui::kColorAshPrivacyIndicatorsBackground);
 
   return notification;
 }
diff --git a/chrome/browser/media/webrtc/multi_capture/multi_capture_usage_indicator_service_browsertest.cc b/chrome/browser/media/webrtc/multi_capture/multi_capture_usage_indicator_service_browsertest.cc
index 4ccb7c8..d83bb088 100644
--- a/chrome/browser/media/webrtc/multi_capture/multi_capture_usage_indicator_service_browsertest.cc
+++ b/chrome/browser/media/webrtc/multi_capture/multi_capture_usage_indicator_service_browsertest.cc
@@ -65,8 +65,8 @@
   std::vector<InstalledApp> allowlisted_capture_apps;
   std::vector<InstalledApp> skip_notification_apps;
   std::vector<InstalledApp> capturing_apps;
-  std::u16string expected_icon_notification_message_before_capture;
-  std::u16string expected_icon_notification_message_after_capture;
+  std::u16string expected_icon_notification_title_before_capture;
+  std::u16string expected_icon_notification_title_after_capture;
   std::optional<std::u16string>
       expected_no_icon_notification_message_after_capture;
 };
@@ -256,9 +256,9 @@
       "multi-capture-login-privacy-indicators"));
   const auto& notification =
       visible_notifications_.at("multi-capture-login-privacy-indicators");
-  EXPECT_EQ(notification.title(), u"");
-  EXPECT_EQ(notification.message(),
-            GetParam().expected_icon_notification_message_before_capture);
+  EXPECT_EQ(notification.title(),
+            GetParam().expected_icon_notification_title_before_capture);
+  EXPECT_EQ(notification.message(), u"");
 }
 
 IN_PROC_BROWSER_TEST_P(
@@ -276,9 +276,9 @@
       "multi-capture-login-privacy-indicators"));
   const auto& notification =
       visible_notifications_.at("multi-capture-login-privacy-indicators");
-  EXPECT_EQ(notification.title(), u"");
-  EXPECT_EQ(notification.message(),
-            GetParam().expected_icon_notification_message_before_capture);
+  EXPECT_EQ(notification.title(),
+            GetParam().expected_icon_notification_title_before_capture);
+  EXPECT_EQ(notification.message(), u"");
 
   if (GetParam().capturing_apps.empty()) {
     return;
@@ -294,14 +294,13 @@
       visible_notifications_,
       Contains(Pair(
           "multi-capture-login-privacy-indicators",
-          AllOf(
-              Property(&message_center::Notification::title, u""),
-              Property(
-                  &message_center::Notification::message,
-                  GetParam().expected_icon_notification_message_after_capture),
-              Property(&message_center::Notification::notifier_id,
-                       Field(&message_center::NotifierId::id,
-                             "multi-capture-login-privacy-indicators"))))));
+          AllOf(Property(
+                    &message_center::Notification::title,
+                    GetParam().expected_icon_notification_title_after_capture),
+                Property(&message_center::Notification::message, u""),
+                Property(&message_center::Notification::notifier_id,
+                         Field(&message_center::NotifierId::id,
+                               "multi-capture-login-privacy-indicators"))))));
 
   if (GetParam()
           .expected_no_icon_notification_message_after_capture.has_value()) {
@@ -309,12 +308,12 @@
         visible_notifications_,
         Contains(Pair(
             GetLastCapturingNotificationWithAppId(),
-            AllOf(Property(&message_center::Notification::title, u""),
-                  Property(
-                      &message_center::Notification::message,
+            AllOf(Property(
+                      &message_center::Notification::title,
                       GetParam()
                           .expected_no_icon_notification_message_after_capture
-                          .value())))));
+                          .value()),
+                  Property(&message_center::Notification::message, u"")))));
   }
 }
 
@@ -341,10 +340,10 @@
       Contains(Pair(
           "multi-capture-login-privacy-indicators",
           AllOf(
-              Property(&message_center::Notification::title, u""),
-              Property(&message_center::Notification::message,
+              Property(&message_center::Notification::title,
                        u"Your administrator can record your screen with app 1. "
                        u"You will not be notified when the recording starts."),
+              Property(&message_center::Notification::message, u""),
               Property(&message_center::Notification::notifier_id,
                        Field(&message_center::NotifierId::id,
                              "multi-capture-login-privacy-indicators"))))));
@@ -355,10 +354,10 @@
       visible_notifications_,
       Contains(Pair(
           "multi-capture-login-privacy-indicators",
-          AllOf(Property(&message_center::Notification::title, u""),
-                Property(&message_center::Notification::message,
+          AllOf(Property(&message_center::Notification::title,
                          u"Your administrator can record your screen with app "
                          u"1 and app 2."),
+                Property(&message_center::Notification::message, u""),
                 Property(&message_center::Notification::notifier_id,
                          Field(&message_center::NotifierId::id,
                                "multi-capture-login-privacy-indicators"))))));
@@ -375,10 +374,10 @@
             .allowlisted_capture_apps = {kApp1},
             .skip_notification_apps = {},
             .capturing_apps = {kApp1},
-            .expected_icon_notification_message_before_capture =
+            .expected_icon_notification_title_before_capture =
                 u"Your administrator can record your screen with app 1. "
                 "You will be notified when the recording starts.",
-            .expected_icon_notification_message_after_capture =
+            .expected_icon_notification_title_after_capture =
                 u"Your administrator is recording your screen with app 1.",
             .expected_no_icon_notification_message_after_capture =
                 std::nullopt},
@@ -389,10 +388,10 @@
             .allowlisted_capture_apps = {kApp1, kApp2},
             .skip_notification_apps = {},
             .capturing_apps = {kApp1},
-            .expected_icon_notification_message_before_capture =
+            .expected_icon_notification_title_before_capture =
                 u"Your administrator can record your screen with app 1. "
                 "You will be notified when the recording starts.",
-            .expected_icon_notification_message_after_capture =
+            .expected_icon_notification_title_after_capture =
                 u"Your administrator is recording your screen with app 1.",
             .expected_no_icon_notification_message_after_capture =
                 std::nullopt},
@@ -405,10 +404,10 @@
             .allowlisted_capture_apps = {kApp1, kApp2},
             .skip_notification_apps = {},
             .capturing_apps = {kApp1},
-            .expected_icon_notification_message_before_capture =
+            .expected_icon_notification_title_before_capture =
                 u"Your administrator can record your screen with app 1 and "
                 u"app 2. You will be notified when the recording starts.",
-            .expected_icon_notification_message_after_capture =
+            .expected_icon_notification_title_after_capture =
                 u"Your administrator can record your screen with app 2. You "
                 u"will be notified when the recording starts.",
             .expected_no_icon_notification_message_after_capture =
@@ -421,10 +420,10 @@
             .allowlisted_capture_apps = {kApp1, kApp2},
             .skip_notification_apps = {},
             .capturing_apps = {kApp1, kApp2},
-            .expected_icon_notification_message_before_capture =
+            .expected_icon_notification_title_before_capture =
                 u"Your administrator can record your screen with app 1 and "
                 u"app 2. You will be notified when the recording starts.",
-            .expected_icon_notification_message_after_capture =
+            .expected_icon_notification_title_after_capture =
                 u"Your administrator is recording your screen with app 1.",
             .expected_no_icon_notification_message_after_capture =
                 u"Your administrator is recording your screen with app 2."},
@@ -435,10 +434,10 @@
             .allowlisted_capture_apps = {kApp1},
             .skip_notification_apps = {kApp1},
             .capturing_apps = {},
-            .expected_icon_notification_message_before_capture =
+            .expected_icon_notification_title_before_capture =
                 u"Your administrator can record your screen with app 1. You "
                 u"will not be notified when the recording starts.",
-            .expected_icon_notification_message_after_capture =
+            .expected_icon_notification_title_after_capture =
                 u"Your administrator can record your screen with app 1. You "
                 u"will not be notified when the recording starts.",
             .expected_no_icon_notification_message_after_capture =
@@ -450,10 +449,10 @@
             .allowlisted_capture_apps = {kApp1, kApp2},
             .skip_notification_apps = {kApp1},
             .capturing_apps = {kApp1},
-            .expected_icon_notification_message_before_capture =
+            .expected_icon_notification_title_before_capture =
                 u"Your administrator can record your screen with app 1. You "
                 u"will not be notified when the recording starts.",
-            .expected_icon_notification_message_after_capture =
+            .expected_icon_notification_title_after_capture =
                 u"Your administrator can record your screen with app 1. You "
                 u"will not be notified when the recording starts.",
             .expected_no_icon_notification_message_after_capture =
@@ -466,10 +465,10 @@
             .allowlisted_capture_apps = {kApp1, kApp2},
             .skip_notification_apps = {kApp1},
             .capturing_apps = {kApp2},
-            .expected_icon_notification_message_before_capture =
+            .expected_icon_notification_title_before_capture =
                 u"Your administrator can record your screen with app 1 and app "
                 u"2.",
-            .expected_icon_notification_message_after_capture =
+            .expected_icon_notification_title_after_capture =
                 u"Your administrator can record your screen with app 1. You "
                 u"will not be notified when the recording starts.",
             .expected_no_icon_notification_message_after_capture =
@@ -482,10 +481,10 @@
             .allowlisted_capture_apps = {kApp1, kApp2},
             .skip_notification_apps = {kApp1},
             .capturing_apps = {kApp1},
-            .expected_icon_notification_message_before_capture =
+            .expected_icon_notification_title_before_capture =
                 u"Your administrator can record your screen with app 1 and app "
                 u"2.",
-            .expected_icon_notification_message_after_capture =
+            .expected_icon_notification_title_after_capture =
                 u"Your administrator can record your screen with app 1 and app "
                 u"2.",
             .expected_no_icon_notification_message_after_capture =
@@ -498,10 +497,10 @@
             .allowlisted_capture_apps = {kApp1, kApp2},
             .skip_notification_apps = {kApp1, kApp2},
             .capturing_apps = {kApp1, kApp2},
-            .expected_icon_notification_message_before_capture =
+            .expected_icon_notification_title_before_capture =
                 u"Your administrator can record your screen with app 1 and app "
                 u"2. You will not be notified when the recording starts.",
-            .expected_icon_notification_message_after_capture =
+            .expected_icon_notification_title_after_capture =
                 u"Your administrator can record your screen with app 1 and app "
                 u"2. You will not be notified when the recording starts.",
             .expected_no_icon_notification_message_after_capture =
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index 4f312809..38fd63a5 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -49,7 +49,6 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
@@ -3600,8 +3599,7 @@
   // objects and the rest of the browser process and appears to be unsupported
   // in tests.
   chrome::CloseWindow(incognito);
-  BrowserView* incognito_view = static_cast<BrowserView*>(incognito->window());
-  incognito_view->DestroyBrowser();
+  incognito->SynchronouslyDestroyBrowser();
 
   // The test succeeds if it doesn't crash when the posted PDF task attempts to
   // run (the task should be canceled/ignored), so wait for this to happen.
@@ -4373,9 +4371,7 @@
   // The `content::WebContents` needs to be deleted before the browser can be
   // destroyed.
   incognito->tab_strip_model()->DetachAndDeleteWebContentsAt(0);
-
-  BrowserView* incognito_view = static_cast<BrowserView*>(incognito->window());
-  incognito_view->DestroyBrowser();
+  incognito->SynchronouslyDestroyBrowser();
 
   // The test succeeds if it doesn't crash when the posted PDF task attempts to
   // run (the task should be canceled/ignored), so wait for this to happen.
diff --git a/chrome/browser/resources/new_tab_page/untrusted/one_google_bar_api.ts b/chrome/browser/resources/new_tab_page/untrusted/one_google_bar_api.ts
index f1e26db2..eb55a86 100644
--- a/chrome/browser/resources/new_tab_page/untrusted/one_google_bar_api.ts
+++ b/chrome/browser/resources/new_tab_page/untrusted/one_google_bar_api.ts
@@ -133,7 +133,7 @@
         return;
       }
 
-      await callAsyncBarApi(queuedTask.fnName, queuedTask.args);
+      await callAsyncBarApi(queuedTask.fnName, ...queuedTask.args);
       queuedTask = null;
     },
   };
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.ts b/chrome/browser/resources/settings/settings_main/settings_main.ts
index 5abd2dbc..76d99d9b 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.ts
+++ b/chrome/browser/resources/settings/settings_main/settings_main.ts
@@ -28,6 +28,7 @@
 import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
 import type {CrViewManagerElement} from 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.js';
 import {assert} from 'chrome://resources/js/assert.js';
+import {PromiseResolver} from 'chrome://resources/js/promise_resolver.js';
 import {beforeNextRender, flush, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {ensureLazyLoaded} from '../ensure_lazy_loaded.js';
@@ -148,6 +149,7 @@
   declare private languages_?: LanguagesModel;
   // </if>
 
+  private pendingViewSwitching_: PromiseResolver<void> = new PromiseResolver();
   private topLevelEquivalentRoute_: Route = getTopLevelRoute();
 
   override connectedCallback() {
@@ -166,6 +168,8 @@
   }
 
   override async currentRouteChanged(route: Route) {
+    this.pendingViewSwitching_ = new PromiseResolver();
+
     if (routes.ADVANCED && routes.ADVANCED.contains(route)) {
       // Load the lazy module immediately, don't wait for requestIdleCallback()
       // to fire. No-op if it has already fired.
@@ -177,6 +181,7 @@
 
     if (this.lastRoute_ === effectiveRoute) {
       // Nothing to do.
+      this.pendingViewSwitching_.resolve();
       return;
     }
 
@@ -191,14 +196,23 @@
       if (this.lastRoute_ !== effectiveRoute || !this.isConnected) {
         // A newer currentRouteChanged call happened while awaiting or no longer
         // connected (both can happen in tests). Do nothing.
+        this.pendingViewSwitching_.resolve();
         return;
       }
       sectionElement = this.$.switcher.querySelector(`#${newSection}`);
     }
 
     assert(sectionElement);
-    this.$.switcher.switchView(
+    await this.$.switcher.switchView(
         sectionElement.id, 'no-animation', 'no-animation');
+    this.pendingViewSwitching_.resolve();
+  }
+
+  // Exposed for tests, to allow making visibility assertions about
+  // cr-view-manager views without flaking. Should be called after
+  // currentRouteChanged is called.
+  whenViewSwitchingDone(): Promise<void> {
+    return this.pendingViewSwitching_.promise;
   }
 
   /**
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 6b2c163..6e8e5d7c 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -84,9 +84,6 @@
     "simple_message_box.h",
     "simple_message_box_internal.cc",
     "simple_message_box_internal.h",
-    "startup/bad_flags_prompt.cc",
-    "startup/bidding_and_auction_consented_debugging_infobar_delegate.cc",
-    "startup/test_third_party_cookie_phaseout_infobar_delegate.cc",
     "status_bubble.h",
     "storage_pressure_bubble.h",
     "tab_dialogs.cc",
@@ -379,6 +376,7 @@
     "//chrome/browser/ui/serial",
     "//chrome/browser/ui/serial:impl",
     "//chrome/browser/ui/startup",
+    "//chrome/browser/ui/startup:impl",
     "//chrome/browser/ui/startup/default_browser_prompt",
     "//chrome/browser/ui/startup/default_browser_prompt:impl",
     "//chrome/browser/ui/sync",
@@ -725,6 +723,7 @@
     "//chrome/browser/ui/bluetooth:impl",
     "//chrome/browser/ui/profiles:impl",
     "//chrome/browser/ui/serial:impl",
+    "//chrome/browser/ui/startup:impl",
     "//chrome/browser/ui/tab_contents:impl",
     "//chrome/browser/ui/toolbar:impl",
     "//chrome/browser/search_engine_choice:impl",
@@ -1086,14 +1085,6 @@
       "scoped_tabbed_browser_displayer.h",
       "singleton_tabs.cc",
       "singleton_tabs.h",
-      "startup/automation_infobar_delegate.cc",
-      "startup/google_api_keys_infobar_delegate.cc",
-      "startup/infobar_utils.cc",
-      "startup/launch_mode_recorder.cc",
-      "startup/obsolete_system_infobar_delegate.cc",
-      "startup/startup_browser_creator.cc",
-      "startup/startup_browser_creator_impl.cc",
-      "startup/startup_tab_provider.cc",
       "tab_modal_confirm_dialog_delegate.cc",
       "tab_modal_confirm_dialog_delegate.h",
       "tabs/glic_actor_task_icon_controller.cc",
@@ -1477,10 +1468,6 @@
       ]
     }
 
-    if (is_chrome_for_testing) {
-      sources += [ "startup/chrome_for_testing_infobar_delegate.cc" ]
-    }
-
     # Non-android deps for "ui" target.
     deps += [
       ":browser_tab_strip",
@@ -2879,7 +2866,6 @@
       "passwords/password_cross_domain_confirmation_popup_controller_impl.cc",
       "passwords/password_cross_domain_confirmation_popup_controller_impl.h",
       "passwords/password_cross_domain_confirmation_popup_controller_interface.h",
-      "startup/web_app_startup_utils.cc",
       "views/autofill/payments/webauthn_dialog_view.cc",
       "views/autofill/payments/webauthn_dialog_view.h",
       "views/close_bubble_on_tab_activation_helper.cc",
@@ -2926,8 +2912,6 @@
 
   if (is_win || is_mac || is_linux) {
     sources += [
-      "startup/first_run_service.cc",
-      "startup/web_app_info_recorder_utils.cc",
       "views/media_preview/active_devices_media_coordinator.cc",
       "views/media_preview/active_devices_media_coordinator.h",
       "views/media_preview/camera_preview/camera_coordinator.cc",
@@ -3299,8 +3283,6 @@
     sources += [
       "network_profile_bubble.cc",
       "network_profile_bubble.h",
-      "startup/credential_provider_signin_dialog_win.cc",
-      "startup/credential_provider_signin_info_fetcher_win.cc",
       "views/apps/app_window_desktop_native_widget_aura_win.cc",
       "views/apps/app_window_desktop_native_widget_aura_win.h",
       "views/apps/app_window_desktop_window_tree_host_win.cc",
diff --git a/chrome/browser/ui/ash/app_list/DEPS b/chrome/browser/ui/ash/app_list/DEPS
index b1ba0816..8b6a768b 100644
--- a/chrome/browser/ui/ash/app_list/DEPS
+++ b/chrome/browser/ui/ash/app_list/DEPS
@@ -3,10 +3,6 @@
   # details.
   "-chrome",
 
-  # This directory is in //chrome, which violates the rule above. Allow this
-  # directory to #include its own files.
-  "+chrome/browser/ui/ash/app_list",
-
   # Existing dependencies within //chrome. There is an active effort to
   # refactor ash codes in //chrome to break these dependencies; see b/332804822.
   # Whenever possible, avoid adding new //chrome dependencies to this list.
diff --git a/chrome/browser/ui/ash/arc/DEPS b/chrome/browser/ui/ash/arc/DEPS
index 22d5747a..04d9edf 100644
--- a/chrome/browser/ui/ash/arc/DEPS
+++ b/chrome/browser/ui/ash/arc/DEPS
@@ -9,7 +9,6 @@
   "+chrome/browser/ash/arc/arc_util.h",
   "+chrome/browser/ash/arc/fileapi",
   "+chrome/browser/ash/arc/intent_helper",
-  "+chrome/browser/ash/crosapi",
   "+chrome/browser/ash/fileapi",
   "+chrome/browser/ash/file_manager",
   "+chrome/browser/ash/profiles",
diff --git a/chrome/browser/ui/ash/arc/arc_app_dialog_view/DEPS b/chrome/browser/ui/ash/arc/arc_app_dialog_view/DEPS
index 80d4ebd..a7f06e1 100644
--- a/chrome/browser/ui/ash/arc/arc_app_dialog_view/DEPS
+++ b/chrome/browser/ui/ash/arc/arc_app_dialog_view/DEPS
@@ -3,10 +3,6 @@
   # details.
   "-chrome",
 
-  # This directory is in //chrome, which violates the rule above. Allow this
-  # directory to #include its own files.
-  "+chrome/browser/ui/ash/arc/arc_app_dialog_view",
-
   # Existing dependencies within //chrome. There is an active effort to
   # refactor ash codes in //chrome to break these dependencies; see b/332804822.
   # Whenever possible, avoid adding new //chrome dependencies to this list.
diff --git a/chrome/browser/ui/ash/arc/arc_data_removal_dialog_view/DEPS b/chrome/browser/ui/ash/arc/arc_data_removal_dialog_view/DEPS
index ed6efb76..0941c4af 100644
--- a/chrome/browser/ui/ash/arc/arc_data_removal_dialog_view/DEPS
+++ b/chrome/browser/ui/ash/arc/arc_data_removal_dialog_view/DEPS
@@ -3,10 +3,6 @@
   # details.
   "-chrome",
 
-  # This directory is in //chrome, which violates the rule above. Allow this
-  # directory to #include its own files.
-  "+chrome/browser/ui/ash/arc/arc_data_removal_dialog_view",
-
   # Existing dependencies within //chrome. There is an active effort to
   # refactor ash codes in //chrome to break these dependencies; see b/332804822.
   # Whenever possible, avoid adding new //chrome dependencies to this list.
diff --git a/chrome/browser/ui/ash/assistant/DEPS b/chrome/browser/ui/ash/assistant/DEPS
index dec693e..1d2c964 100644
--- a/chrome/browser/ui/ash/assistant/DEPS
+++ b/chrome/browser/ui/ash/assistant/DEPS
@@ -11,23 +11,12 @@
   # refactor ash codes in //chrome to break these dependencies; see b/332804822.
   # Whenever possible, avoid adding new //chrome dependencies to this list.
   "+chrome/browser/apps/app_service",
-  "+chrome/browser/ash/app_list/arc",
-  "+chrome/browser/ash/arc/arc_util.h",
-  "+chrome/browser/ash/arc/session",
-  "+chrome/browser/ash/arc/test",
   "+chrome/browser/ash/assistant",
-  "+chrome/browser/ash/crosapi",
-  "+chrome/browser/ash/login/test",
   "+chrome/browser/ash/login/users",
   "+chrome/browser/ash/profiles",
-  "+chrome/browser/lifetime",
   "+chrome/browser/profiles",
-  "+chrome/browser/signin/identity_manager_factory.h",
   "+chrome/browser/ui/browser_list.h",
-  "+chrome/browser/ui/settings_window_manager_chromeos.h",
   "+chrome/browser/ui/views/frame/browser_view.h",
-  "+chrome/browser/ui/webui/ash/assistant_optin",
-  "+chrome/browser/ui/webui/chrome_web_ui_controller_factory.h",
   "+chrome/browser/web_applications",
   "+chrome/common",
   "+chrome/test",
diff --git a/chrome/browser/ui/ash/birch/DEPS b/chrome/browser/ui/ash/birch/DEPS
index be007e00..7ea7034 100644
--- a/chrome/browser/ui/ash/birch/DEPS
+++ b/chrome/browser/ui/ash/birch/DEPS
@@ -13,7 +13,6 @@
   "+chrome/browser/ash/app_list/search",
   "+chrome/browser/ash/app_restore",
   "+chrome/browser/ash/calendar",
-  "+chrome/browser/ash/crosapi",
   "+chrome/browser/ash/file_suggest",
   "+chrome/browser/ash/login/users",
   "+chrome/browser/ash/release_notes",
diff --git a/chrome/browser/ui/ash/boca/DEPS b/chrome/browser/ui/ash/boca/DEPS
index da5f184c..6e91335 100644
--- a/chrome/browser/ui/ash/boca/DEPS
+++ b/chrome/browser/ui/ash/boca/DEPS
@@ -11,7 +11,6 @@
   # refactor ash codes in //chrome to break these dependencies; see b/332804822.
   # Whenever possible, avoid adding new //chrome dependencies to this list.
   "+chrome/browser/apps/platform_apps",
-  "+chrome/browser/favicon",
   "+chrome/browser/profiles/profile.h",
   "+chrome/browser/ui/browser_list.h",
   "+chrome/browser/ui/browser_tabstrip.h",
diff --git a/chrome/browser/ui/ash/capture_mode/DEPS b/chrome/browser/ui/ash/capture_mode/DEPS
index 805c1e2c..22a3c5c 100644
--- a/chrome/browser/ui/ash/capture_mode/DEPS
+++ b/chrome/browser/ui/ash/capture_mode/DEPS
@@ -29,14 +29,12 @@
   "+chrome/browser/screen_ai",
   "+chrome/browser/search_engines",
   "+chrome/browser/signin",
-  "+chrome/browser/ui/ash/screenshot_area.h",
   "+chrome/browser/ui/ash/system_web_apps",
   "+chrome/browser/ui/ash/web_view",
   "+chrome/browser/ui/browser.h",
   "+chrome/browser/ui/browser_navigator.h",
   "+chrome/browser/ui/browser_navigator_params.h",
   "+chrome/browser/ui/browser_window.h",
-  "+chrome/browser/ui/lens",
   "+chrome/browser/ui/views/frame",
   "+chrome/browser/ui/webui/ash/cloud_upload",
   "+chrome/common",
diff --git a/chrome/browser/ui/ash/cast_config/DEPS b/chrome/browser/ui/ash/cast_config/DEPS
index 83343e8..eca2118 100644
--- a/chrome/browser/ui/ash/cast_config/DEPS
+++ b/chrome/browser/ui/ash/cast_config/DEPS
@@ -13,6 +13,5 @@
   "+chrome/browser/ash/profiles",
   "+chrome/browser/media/router",
   "+chrome/browser/profiles",
-  "+chrome/browser/ui/ui_features.h",
   "+chrome/common",
 ]
diff --git a/chrome/browser/ui/ash/desks/DEPS b/chrome/browser/ui/ash/desks/DEPS
index 3ac4138..2ff1e36 100644
--- a/chrome/browser/ui/ash/desks/DEPS
+++ b/chrome/browser/ui/ash/desks/DEPS
@@ -4,7 +4,6 @@
   # Whenever possible, avoid adding new //chrome dependencies to this list.
   "+chrome/app/vector_icons/vector_icons.h",
   "+chrome/browser/apps/app_service",
-  "+chrome/browser/apps/browser_instance",
   "+chrome/browser/apps/icon_standardizer.h",
   "+chrome/browser/apps/platform_apps",
   "+chrome/browser/ash/app_restore",
@@ -13,7 +12,6 @@
   "+chrome/browser/ash/login/test",
   "+chrome/browser/ash/login/users",
   "+chrome/browser/ash/profiles",
-  "+chrome/browser/ash/system_web_apps/apps",
   "+chrome/browser/ash/system_web_apps/system_web_app_manager.h",
   "+chrome/browser/chromeos/extensions/wm",
   "+chrome/browser/extensions/extension_apitest.h",
diff --git a/chrome/browser/ui/ash/gemini_app/DEPS b/chrome/browser/ui/ash/gemini_app/DEPS
index 6322cdb..1c561bb6 100644
--- a/chrome/browser/ui/ash/gemini_app/DEPS
+++ b/chrome/browser/ui/ash/gemini_app/DEPS
@@ -2,14 +2,6 @@
   # ChromeOS should not depend on //chrome. See //docs/chromeos/code.md for
   # details.
   "-chrome",
-
-  # This directory is in //chrome, which violates the rule above. Allow this
-  # directory to #include its own files.
-  "+chrome/browser/ui/ash/gemini_app",
-
-  # Existing dependencies within //chrome. There is an active effort to
-  # refactor ash codes in //chrome to break these dependencies; see b/332804822.
-  # Whenever possible, avoid adding new //chrome dependencies to this list.
 ]
 
 specific_include_rules = {
diff --git a/chrome/browser/ui/ash/global_media_controls/DEPS b/chrome/browser/ui/ash/global_media_controls/DEPS
index c36b2c5..1d1de7e 100644
--- a/chrome/browser/ui/ash/global_media_controls/DEPS
+++ b/chrome/browser/ui/ash/global_media_controls/DEPS
@@ -10,7 +10,6 @@
   # Existing dependencies within //chrome. There is an active effort to
   # refactor ash codes in //chrome to break these dependencies; see b/332804822.
   # Whenever possible, avoid adding new //chrome dependencies to this list.
-  "+chrome/browser/ash/crosapi",
   "+chrome/browser/ash/profiles",
   "+chrome/browser/media/router",
   "+chrome/browser/profiles",
diff --git a/chrome/browser/ui/ash/google_one/DEPS b/chrome/browser/ui/ash/google_one/DEPS
index aeb1124..c25c10dba 100644
--- a/chrome/browser/ui/ash/google_one/DEPS
+++ b/chrome/browser/ui/ash/google_one/DEPS
@@ -11,7 +11,6 @@
   # refactor ash codes in //chrome to break these dependencies; see b/332804822.
   # Whenever possible, avoid adding new //chrome dependencies to this list.
   "+chrome/browser/ash/login/test",
-  "+chrome/browser/ash/policy/core",
   "+chrome/browser/ash/profiles",
   "+chrome/browser/ash/scalable_iph",
   "+chrome/browser/ash/settings",
@@ -20,6 +19,5 @@
   "+chrome/browser/policy",
   "+chrome/browser/profiles/profile.h",
   "+chrome/browser/ui/browser.h",
-  "+chrome/browser/ui/browser_navigator_params.h",
   "+chrome/test",
 ]
diff --git a/chrome/browser/ui/ash/holding_space/DEPS b/chrome/browser/ui/ash/holding_space/DEPS
index 5d13132..95587466 100644
--- a/chrome/browser/ui/ash/holding_space/DEPS
+++ b/chrome/browser/ui/ash/holding_space/DEPS
@@ -12,7 +12,6 @@
   # Whenever possible, avoid adding new //chrome dependencies to this list.
   "+chrome/browser/ash/arc/arc_util.h",
   "+chrome/browser/ash/arc/fileapi",
-  "+chrome/browser/ash/crosapi",
   "+chrome/browser/ash/drive",
   "+chrome/browser/ash/fileapi",
   "+chrome/browser/ash/file_manager",
diff --git a/chrome/browser/ui/ash/keyboard/DEPS b/chrome/browser/ui/ash/keyboard/DEPS
index da229a6d..2d84e84 100644
--- a/chrome/browser/ui/ash/keyboard/DEPS
+++ b/chrome/browser/ui/ash/keyboard/DEPS
@@ -12,7 +12,6 @@
   # Whenever possible, avoid adding new //chrome dependencies to this list.
   "+chrome/browser/apps/platform_apps",
   "+chrome/browser/ash/input_method",
-  "+chrome/browser/extensions/extension_service.h",
   "+chrome/browser/media/webrtc",
   "+chrome/browser/profiles",
   "+chrome/browser/ui/browser.h",
diff --git a/chrome/browser/ui/ash/login/DEPS b/chrome/browser/ui/ash/login/DEPS
index de967dd..0a3b11e 100644
--- a/chrome/browser/ui/ash/login/DEPS
+++ b/chrome/browser/ui/ash/login/DEPS
@@ -74,7 +74,6 @@
   "+chrome/browser/ui/webui/chrome_web_contents_handler.h",
   "+chrome/browser/ui/webui/feedback",
   "+chrome/common",
-  "+chrome/common/channel_info.h",
   "+chrome/common/chrome_constants.h",
   "+chrome/common/chrome_switches.h",
   "+chrome/common/pref_names.h",
diff --git a/chrome/browser/ui/ash/magic_boost/DEPS b/chrome/browser/ui/ash/magic_boost/DEPS
index 0de15ae0..6341137 100644
--- a/chrome/browser/ui/ash/magic_boost/DEPS
+++ b/chrome/browser/ui/ash/magic_boost/DEPS
@@ -1,5 +1,4 @@
 include_rules = [
-  "+chrome/browser/ash/crosapi",
   "+chrome/browser/ash/magic_boost",
   "+chrome/browser/ui/ash/editor_menu/utils",
   "+chrome/browser/ui/ash/read_write_cards",
diff --git a/chrome/browser/ui/ash/main_extra_parts/DEPS b/chrome/browser/ui/ash/main_extra_parts/DEPS
index 2887f1d..8033e86 100644
--- a/chrome/browser/ui/ash/main_extra_parts/DEPS
+++ b/chrome/browser/ui/ash/main_extra_parts/DEPS
@@ -12,14 +12,11 @@
   # Whenever possible, avoid adding new //chrome dependencies to this list.
   "+chrome/browser/ash/app_list",
   "+chrome/browser/ash/app_restore",
-  "+chrome/browser/ash/arc/util",
   "+chrome/browser/ash/auth",
   "+chrome/browser/ash/boca",
   "+chrome/browser/ash/geolocation",
   "+chrome/browser/ash/growth",
   "+chrome/browser/ash/input_device_settings",
-  "+chrome/browser/ash/lobster",
-  "+chrome/browser/ash/login/demo_mode",
   "+chrome/browser/ash/login/signin",
   "+chrome/browser/ash/magic_boost",
   "+chrome/browser/ash/mahi",
diff --git a/chrome/browser/ui/ash/management_disclosure/DEPS b/chrome/browser/ui/ash/management_disclosure/DEPS
index 8030f36..1afcc4a 100644
--- a/chrome/browser/ui/ash/management_disclosure/DEPS
+++ b/chrome/browser/ui/ash/management_disclosure/DEPS
@@ -6,15 +6,15 @@
   # This directory is in //chrome, which violates the rule above. Allow this
   # directory to #include its own files.
   "+chrome/browser/ui/ash/management_disclosure",
-  "+chrome/browser/ash/policy/core/browser_policy_connector_ash.h",
-  "+chrome/browser/ui/webui/management/management_ui_handler_chromeos.h",
-  "+chrome/browser/ui/webui/management/management_ui.h",
-  "+chrome/browser/profiles/profile.h",
-  "+chrome/browser/ash/login/lock/screen_locker_tester.h",
-  "+chrome/browser/ash/login/login_manager_test.h",
-  "+chrome/browser/ash/login/test/login_manager_mixin.h",
 
   # Existing dependencies within //chrome. There is an active effort to
   # refactor ash codes in //chrome to break these dependencies; see b/332804822.
   # Whenever possible, avoid adding new //chrome dependencies to this list.
+  "+chrome/browser/ash/login/lock/screen_locker_tester.h",
+  "+chrome/browser/ash/login/login_manager_test.h",
+  "+chrome/browser/ash/login/test/login_manager_mixin.h",
+  "+chrome/browser/ash/policy/core/browser_policy_connector_ash.h",
+  "+chrome/browser/profiles/profile.h",
+  "+chrome/browser/ui/webui/management/management_ui_handler_chromeos.h",
+  "+chrome/browser/ui/webui/management/management_ui.h",
 ]
diff --git a/chrome/browser/ui/ash/privacy_hub/DEPS b/chrome/browser/ui/ash/privacy_hub/DEPS
index a9ae1c9f..e9bf6fa 100644
--- a/chrome/browser/ui/ash/privacy_hub/DEPS
+++ b/chrome/browser/ui/ash/privacy_hub/DEPS
@@ -3,10 +3,6 @@
   # details.
   "-chrome",
 
-  # This directory is in //chrome, which violates the rule above. Allow this
-  # directory to #include its own files.
-  "+chrome/browser/ui/ash/privacy_hub",
-
   # Existing dependencies within //chrome. There is an active effort to
   # refactor ash codes in //chrome to break these dependencies; see b/332804822.
   # Whenever possible, avoid adding new //chrome dependencies to this list.
diff --git a/chrome/browser/ui/ash/quick_answers/DEPS b/chrome/browser/ui/ash/quick_answers/DEPS
index 52292650..7c20436 100644
--- a/chrome/browser/ui/ash/quick_answers/DEPS
+++ b/chrome/browser/ui/ash/quick_answers/DEPS
@@ -7,7 +7,6 @@
   "+chrome/browser/ash/magic_boost",
   "+chrome/browser/ui/ash/read_write_cards",
   "+chrome/browser/ui/settings_window_manager_chromeos.h",
-  "+chrome/browser/ui/ash/editor_menu/editor_menu_controller_impl.h",
   "+chrome/browser/ui/ash/editor_menu/utils/focus_search.h",
   "+chrome/browser/ui/ash/editor_menu/utils/pre_target_handler.h",
 ]
diff --git a/chrome/browser/ui/ash/quick_insert/DEPS b/chrome/browser/ui/ash/quick_insert/DEPS
index baacc2b..e5400ca7 100644
--- a/chrome/browser/ui/ash/quick_insert/DEPS
+++ b/chrome/browser/ui/ash/quick_insert/DEPS
@@ -13,7 +13,6 @@
   "+chrome/browser/ash/accessibility",
   "+chrome/browser/ash/app_list/app_list_controller_delegate.h",
   "+chrome/browser/ash/app_list/search",
-  "+chrome/browser/ash/crosapi",
   "+chrome/browser/ash/drive",
   "+chrome/browser/ash/fileapi",
   "+chrome/browser/ash/file_manager",
@@ -21,7 +20,6 @@
   "+chrome/browser/ash/input_method",
   "+chrome/browser/ash/login/session",
   "+chrome/browser/bookmarks",
-  "+chrome/browser/chromeos/launcher_search",
   "+chrome/browser/favicon",
   "+chrome/browser/history",
   "+chrome/browser/profiles",
diff --git a/chrome/browser/ui/ash/session/DEPS b/chrome/browser/ui/ash/session/DEPS
index 26c90af9..207d085 100644
--- a/chrome/browser/ui/ash/session/DEPS
+++ b/chrome/browser/ui/ash/session/DEPS
@@ -11,7 +11,6 @@
   # refactor ash codes in //chrome to break these dependencies; see b/332804822.
   # Whenever possible, avoid adding new //chrome dependencies to this list.
   "+chrome/browser/app_mode",
-  "+chrome/browser/ash/crosapi",
   "+chrome/browser/ash/floating_workspace",
   "+chrome/browser/ash/login/demo_mode",
   "+chrome/browser/ash/login/lock",
diff --git a/chrome/browser/ui/ash/shelf/DEPS b/chrome/browser/ui/ash/shelf/DEPS
index 8e04fe6..8ed428c 100644
--- a/chrome/browser/ui/ash/shelf/DEPS
+++ b/chrome/browser/ui/ash/shelf/DEPS
@@ -21,7 +21,6 @@
   "+chrome/browser/ash/arc/arc_util.h",
   "+chrome/browser/ash/arc/icon_decode_request.h",
   "+chrome/browser/ash/arc/session",
-  "+chrome/browser/ash/crosapi",
   "+chrome/browser/ash/crostini",
   "+chrome/browser/ash/eche_app",
   "+chrome/browser/ash/extensions",
@@ -46,7 +45,6 @@
   "+chrome/browser/media/router",
   "+chrome/browser/prefs",
   "+chrome/browser/profiles",
-  "+chrome/browser/ash/scalable_iph",
   "+chrome/browser/sync",
   "+chrome/browser/ui/apps",
   "+chrome/browser/ui/ash/app_icon_color_cache",
diff --git a/chrome/browser/ui/ash/shelf/app_service/DEPS b/chrome/browser/ui/ash/shelf/app_service/DEPS
index 976c946..d5e32824 100644
--- a/chrome/browser/ui/ash/shelf/app_service/DEPS
+++ b/chrome/browser/ui/ash/shelf/app_service/DEPS
@@ -22,7 +22,6 @@
   "+chrome/browser/ash/arc/session",
   "+chrome/browser/ash/borealis",
   "+chrome/browser/ash/bruschetta",
-  "+chrome/browser/ash/crosapi",
   "+chrome/browser/ash/crostini",
   "+chrome/browser/ash/guest_os",
   "+chrome/browser/ash/plugin_vm",
diff --git a/chrome/browser/ui/ash/shell_delegate/DEPS b/chrome/browser/ui/ash/shell_delegate/DEPS
index d2b5b73f..4ec54fe 100644
--- a/chrome/browser/ui/ash/shell_delegate/DEPS
+++ b/chrome/browser/ui/ash/shell_delegate/DEPS
@@ -33,7 +33,6 @@
   "+chrome/browser/ui/ash/back_gesture",
   "+chrome/browser/ui/ash/boca",
   "+chrome/browser/ui/ash/capture_mode",
-  "+chrome/browser/ui/ash/chrome_accelerator_prefs_delegate.h",
   "+chrome/browser/ui/ash/clipboard",
   "+chrome/browser/ui/ash/desks",
   "+chrome/browser/ui/ash/focus_mode",
@@ -55,7 +54,6 @@
   "+chrome/browser/ui/scoped_tabbed_browser_displayer.h",
   "+chrome/browser/ui/settings_window_manager_chromeos.h",
   "+chrome/browser/ui/tabs/tab_strip_model.h",
-  "+chrome/browser/ui/views/chrome_browser_main_extra_parts_views.h",
   "+chrome/browser/ui/views/frame",
   "+chrome/browser/ui/views/tabs",
   "+chrome/browser/ui/webui/ash/diagnostics_dialog/diagnostics_dialog.h",
diff --git a/chrome/browser/ui/ash/system/DEPS b/chrome/browser/ui/ash/system/DEPS
index 8337f0f..9794eb7 100644
--- a/chrome/browser/ui/ash/system/DEPS
+++ b/chrome/browser/ui/ash/system/DEPS
@@ -12,7 +12,6 @@
   # Whenever possible, avoid adding new //chrome dependencies to this list.
   "+chrome/browser/apps/app_service",
   "+chrome/browser/ash/accessibility",
-  "+chrome/browser/ash/eol",
   "+chrome/browser/ash/login/help_app_launcher.h",
   "+chrome/browser/ash/login/lock",
   "+chrome/browser/ash/login/login_manager_test.h",
@@ -20,7 +19,6 @@
   "+chrome/browser/ash/login/test",
   "+chrome/browser/ash/policy/core",
   "+chrome/browser/ash/profiles",
-  "+chrome/browser/ash/settings",
   "+chrome/browser/ash/system",
   "+chrome/browser/ash/system_web_apps/apps/personalization_app",
   "+chrome/browser/chromeos/extensions/vpn_provider",
@@ -44,7 +42,6 @@
   "+chrome/browser/ui/webui/ash/multidevice_setup",
   "+chrome/browser/ui/webui/ash/set_time",
   "+chrome/browser/upgrade_detector",
-  "+chrome/browser/web_applications",
   "+chrome/common",
   "+chrome/test",
 ]
diff --git a/chrome/browser/ui/ash/system_web_apps/DEPS b/chrome/browser/ui/ash/system_web_apps/DEPS
index 27584a2f..e02ae96 100644
--- a/chrome/browser/ui/ash/system_web_apps/DEPS
+++ b/chrome/browser/ui/ash/system_web_apps/DEPS
@@ -7,7 +7,6 @@
   "+chrome/browser/ash/system_web_apps",
   "+chrome/browser/profiles",
   "+chrome/browser/ash/browser_delegate/browser_type_conversion.h",
-  "+chrome/browser/ash/scalable_iph",
   "+chrome/browser/ui/ash/multi_user",
   "+chrome/browser/ui/browser.h",
   "+chrome/browser/ui/browser_list.h",
diff --git a/chrome/browser/ui/ash/test/DEPS b/chrome/browser/ui/ash/test/DEPS
index 0ee0044..6ce3242 100644
--- a/chrome/browser/ui/ash/test/DEPS
+++ b/chrome/browser/ui/ash/test/DEPS
@@ -3,10 +3,6 @@
   # details.
   "-chrome",
 
-  # This directory is in //chrome, which violates the rule above. Allow this
-  # directory to #include its own files.
-  "+chrome/browser/ui/ash/test",
-
   # Existing dependencies within //chrome. There is an active effort to
   # refactor ash codes in //chrome to break these dependencies; see b/332804822.
   # Whenever possible, avoid adding new //chrome dependencies to this list.
diff --git a/chrome/browser/ui/ash/thumbnail_loader/DEPS b/chrome/browser/ui/ash/thumbnail_loader/DEPS
index cae7c45..55f8c4f 100644
--- a/chrome/browser/ui/ash/thumbnail_loader/DEPS
+++ b/chrome/browser/ui/ash/thumbnail_loader/DEPS
@@ -12,7 +12,6 @@
   # Whenever possible, avoid adding new //chrome dependencies to this list.
   "+chrome/browser/ash/fileapi",
   "+chrome/browser/ash/file_manager",
-  "+chrome/browser/extensions/api/messaging",
   "+chrome/browser/extensions/component_loader.h",
   "+chrome/browser/image_decoder",
   "+chrome/browser/profiles/profile.h",
diff --git a/chrome/browser/ui/ash/user_education/views/DEPS b/chrome/browser/ui/ash/user_education/views/DEPS
index 7123ecc..ab412fd 100644
--- a/chrome/browser/ui/ash/user_education/views/DEPS
+++ b/chrome/browser/ui/ash/user_education/views/DEPS
@@ -3,10 +3,6 @@
   # details.
   "-chrome",
 
-  # This directory is in //chrome, which violates the rule above. Allow this
-  # directory to #include its own files.
-  "+chrome/browser/ui/ash/user_education/views",
-
   # Existing dependencies within //chrome. There is an active effort to
   # refactor ash codes in //chrome to break these dependencies; see b/332804822.
   # Whenever possible, avoid adding new //chrome dependencies to this list.
diff --git a/chrome/browser/ui/ash/user_education/welcome_tour/DEPS b/chrome/browser/ui/ash/user_education/welcome_tour/DEPS
index ba8007dc..cee1d26 100644
--- a/chrome/browser/ui/ash/user_education/welcome_tour/DEPS
+++ b/chrome/browser/ui/ash/user_education/welcome_tour/DEPS
@@ -3,10 +3,6 @@
   # details.
   "-chrome",
 
-  # This directory is in //chrome, which violates the rule above. Allow this
-  # directory to #include its own files.
-  "+chrome/browser/ui/ash/user_education/welcome_tour",
-
   # Existing dependencies within //chrome. There is an active effort to
   # refactor ash codes in //chrome to break these dependencies; see b/332804822.
   # Whenever possible, avoid adding new //chrome dependencies to this list.
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 4ab10a5b..dec508b3 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -1200,6 +1200,11 @@
   return did_become_inactive_callback_list_.Add(std::move(callback));
 }
 
+void Browser::SynchronouslyDestroyBrowser() {
+  CHECK(window_);
+  window_->DestroyBrowser();
+}
+
 ExclusiveAccessManager* Browser::GetExclusiveAccessManager() {
   return GetFeatures().exclusive_access_manager();
 }
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index 74152e6..a87e55f9 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -846,6 +846,13 @@
   void DidBecomeActive();
   void DidBecomeInactive();
 
+  // Synchronously destroys the browser, `this` is no longer valid after the
+  // operation completes.
+  // WARNING: Clients should generally not use this and instead prefer
+  // requesting the browser close via BrowserWindow::Close(), which happens
+  // async and allows graceful teardown of the tab strip and associated data.
+  void SynchronouslyDestroyBrowser();
+
 #if BUILDFLAG(IS_CHROMEOS)
   bool IsLockedForOnTask();
   void SetLockedForOnTask(bool locked);
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index a2b7dfa..8bd30b03 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -656,8 +656,10 @@
   virtual BrowserView* AsBrowserView() = 0;
 
  protected:
-  friend class BrowserCloseManager;
-  friend class BrowserView;
+  // Synchronously destroys the Browser.
+  // TODO(crbug.com/413168662): This can be removed once the ownership structure
+  // is updated and Browser owns BrowserWindow.
+  friend class Browser;
   virtual void DestroyBrowser() = 0;
 };
 
diff --git a/chrome/browser/ui/startup/BUILD.gn b/chrome/browser/ui/startup/BUILD.gn
index 62e4fb7e..91358b0 100644
--- a/chrome/browser/ui/startup/BUILD.gn
+++ b/chrome/browser/ui/startup/BUILD.gn
@@ -5,6 +5,8 @@
 import("//build/buildflag_header.gni")
 import("//build/config/chrome_build.gni")
 import("//build/config/ui.gni")
+import("//extensions/buildflags/buildflags.gni")
+import("//rlz/buildflags/buildflags.gni")
 
 # Allow browser tests that startup with --gcpw-signin flag only on
 # non-Google Chrome builds.
@@ -94,3 +96,189 @@
     ]
   }
 }
+
+source_set("impl") {
+  sources = [
+    "bad_flags_prompt.cc",
+    "bidding_and_auction_consented_debugging_infobar_delegate.cc",
+    "test_third_party_cookie_phaseout_infobar_delegate.cc",
+  ]
+  deps = [
+    ":startup",
+    "//base",
+    "//base:base_static",
+    "//cc/base",
+    "//chrome/app:branded_strings",
+    "//chrome/app:generated_resources",
+    "//chrome/browser:browser_process",
+    "//chrome/browser/devtools",
+    "//chrome/browser/infobars",
+    "//chrome/browser/profiles",
+    "//chrome/browser/profiles:profile",
+    "//chrome/browser/profiles:profile_util",
+    "//chrome/browser/signin",
+    "//chrome/browser/sync",
+    "//chrome/browser/sync:factories",
+    "//chrome/browser/ui/profiles",
+    "//chrome/browser/webauthn",
+    "//chrome/common:chrome_features",
+    "//chrome/common:constants",
+    "//chrome/common:non_code_constants",
+    "//components/autofill/core/common",
+    "//components/history_clusters/core",
+    "//components/infobars/content",
+    "//components/infobars/core",
+    "//components/media_router/common/providers/cast/certificate",
+    "//components/network_session_configurator/common",
+    "//components/prefs",
+    "//components/signin/public/base",
+    "//components/signin/public/identity_manager",
+    "//components/startup_metric_utils",
+    "//components/translate/core/common",
+    "//components/vector_icons",
+    "//content/public/browser",
+    "//content/public/common",
+    "//google_apis",
+    "//gpu/config",
+    "//media",
+    "//media:media_buildflags",
+    "//sandbox/policy",
+    "//services/network/public/cpp:flags_and_switches",
+    "//services/webnn:webnn_switches",
+    "//third_party/blink/public:runtime_features_for_public",
+    "//ui/base",
+    "//ui/gfx",
+    "//url",
+  ]
+  public_deps = [ "//chrome/browser:browser_public_dependencies" ]
+
+  if (!is_android) {
+    sources += [
+      "automation_infobar_delegate.cc",
+      "google_api_keys_infobar_delegate.cc",
+      "infobar_utils.cc",
+      "launch_mode_recorder.cc",
+      "obsolete_system_infobar_delegate.cc",
+      "startup_browser_creator.cc",
+      "startup_browser_creator_impl.cc",
+      "startup_tab_provider.cc",
+    ]
+    deps += [
+      ":startup_tab",
+      "//apps",
+      "//base:i18n",
+      "//build:branding_buildflags",
+      "//build:buildflag_header_h",
+      "//chrome/browser:global_features",
+      "//chrome/browser:shell_integration",
+      "//chrome/browser/actor",
+      "//chrome/browser/apps/app_service",
+      "//chrome/browser/apps/platform_apps",
+      "//chrome/browser/extensions",
+      "//chrome/browser/headless",
+      "//chrome/browser/headless:command_processor",
+      "//chrome/browser/prefs",
+      "//chrome/browser/prefs:util",
+      "//chrome/browser/privacy_sandbox:headers",
+      "//chrome/browser/privacy_sandbox/notice:desktop_entrypoint_handlers_helper",
+      "//chrome/browser/profiles/keep_alive",
+      "//chrome/browser/search",
+      "//chrome/browser/search_engines",
+      "//chrome/browser/ui:browser_list",
+      "//chrome/browser/ui:browser_navigator_params_headers",
+      "//chrome/browser/ui:ui_features",
+      "//chrome/browser/ui/browser_window",
+      "//chrome/browser/ui/extensions",
+      "//chrome/browser/ui/startup/default_browser_prompt",
+      "//chrome/browser/ui/tabs",
+      "//chrome/browser/ui/tabs:tab_group",
+      "//chrome/browser/ui/tabs:tab_strip",
+      "//chrome/browser/ui/toasts",
+      "//chrome/browser/ui/toasts/api:toasts",
+      "//chrome/browser/ui/webui/whats_new",
+      "//chrome/browser/web_applications",
+      "//chrome/common",
+      "//chrome/common:buildflags",
+      "//chrome/common:version_header",
+      "//chrome/common/extensions",
+      "//chrome/installer/util:with_no_strings",
+      "//components/custom_handlers",
+      "//components/google/core/common",
+      "//components/headless/policy",
+      "//components/keep_alive_registry",
+      "//components/privacy_sandbox:features",
+      "//components/search_engines",
+      "//components/services/app_service/public/cpp:app_types",
+      "//components/strings:components_strings",
+      "//components/url_formatter",
+      "//extensions/browser",
+      "//net",
+      "//printing/buildflags",
+      "//services/device/public/cpp/hid",
+    ]
+    if (is_chromeos) {
+      deps += [
+        "//chrome/browser/ash/app_mode",
+        "//chrome/browser/ash/app_restore",
+        "//chrome/browser/ash/floating_workspace",
+        "//chrome/browser/ash/floating_workspace:utils",
+        "//chrome/browser/ash/profiles",
+        "//chromeos/ash/components/browser_context_helper",
+        "//chromeos/ash/components/cryptohome",
+        "//components/user_manager",
+      ]
+    }
+    if (is_win || is_mac) {
+      deps += [ "//chrome/browser/ui/pdf/infobar" ]
+    }
+    if (is_win) {
+      deps +=
+          [ "//chrome/browser/ui/startup/default_browser_prompt/pin_infobar" ]
+    }
+    if (is_win && is_chrome_branded) {
+      deps += [ "//chrome/browser/win/installer_downloader:controller" ]
+    }
+    if (enable_rlz) {
+      deps += [ "//components/rlz" ]
+    }
+  }
+
+  if (toolkit_views) {
+    deps += [ "//ui/views" ]
+  }
+
+  if (enable_extensions) {
+    deps += [ "//extensions/common" ]
+  }
+
+  if (is_chrome_for_testing) {
+    sources += [ "chrome_for_testing_infobar_delegate.cc" ]
+  }
+
+  if (is_win || is_mac || is_linux || is_chromeos) {
+    sources += [ "web_app_startup_utils.cc" ]
+    deps += [
+      "//chrome/browser/lifetime:termination_notification",
+      "//components/webapps/common",
+    ]
+  }
+
+  if (is_win || is_mac || is_linux) {
+    sources += [
+      "first_run_service.cc",
+      "web_app_info_recorder_utils.cc",
+    ]
+    deps += [ "//chrome/browser/ui/web_applications" ]
+  }
+
+  if (is_win) {
+    assert(toolkit_views)
+    assert(use_aura)
+
+    sources += [
+      "credential_provider_signin_dialog_win.cc",
+      "credential_provider_signin_info_fetcher_win.cc",
+    ]
+    deps += [ "//chrome/credential_provider/common:common_constants" ]
+  }
+}
diff --git a/chrome/browser/ui/startup/bad_flags_prompt.cc b/chrome/browser/ui/startup/bad_flags_prompt.cc
index 6d08c29..1a268e6 100644
--- a/chrome/browser/ui/startup/bad_flags_prompt.cc
+++ b/chrome/browser/ui/startup/bad_flags_prompt.cc
@@ -34,13 +34,11 @@
 #include "components/translate/core/common/translate_switches.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
-#include "extensions/common/switches.h"
 #include "google_apis/gaia/gaia_switches.h"
 #include "gpu/config/gpu_switches.h"
 #include "media/base/media_switches.h"
 #include "media/media_buildflags.h"
 #include "sandbox/policy/switches.h"
-#include "services/device/public/cpp/hid/hid_switches.h"
 #include "services/network/public/cpp/network_switches.h"
 #include "third_party/blink/public/common/features_generated.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -58,6 +56,11 @@
 #include "chrome/browser/flags/android/chrome_feature_list.h"
 #else
 #include "chrome/browser/actor/actor_switches.h"
+#include "services/device/public/cpp/hid/hid_switches.h"
+#endif
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "extensions/common/switches.h"
 #endif
 
 namespace {
@@ -144,8 +147,10 @@
     switches::kWebNNOrtEpLibraryPathForTesting,
 #endif
 
+#if !BUILDFLAG(IS_ANDROID)
     // A flag to bypass the WebHID blocklist for testing purposes.
     switches::kDisableHidBlocklist,
+#endif
 
     // This flag tells Chrome to automatically install an Isolated Web App in
     // developer mode. The flag should contain the path to an unsigned Web
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc
index 44b4c1c1f..3869eda3 100644
--- a/chrome/browser/ui/startup/startup_browser_creator.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -40,7 +40,6 @@
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/apps/platform_apps/app_load_service.h"
 #include "chrome/browser/apps/platform_apps/platform_app_launch.h"
-#include "chrome/browser/ash/floating_workspace/floating_workspace_service_factory.h"
 #include "chrome/browser/browser_features.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
@@ -104,6 +103,7 @@
 #include "chrome/browser/ash/app_restore/full_restore_service.h"
 #include "chrome/browser/ash/app_restore/full_restore_service_factory.h"
 #include "chrome/browser/ash/floating_workspace/floating_workspace_service.h"
+#include "chrome/browser/ash/floating_workspace/floating_workspace_service_factory.h"
 #include "chrome/browser/ash/floating_workspace/floating_workspace_util.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h
index bb1453c..f2e3347 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h
@@ -33,7 +33,6 @@
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_observer.h"
 #include "chrome/browser/ui/webui/customize_buttons/customize_buttons.mojom.h"
-#include "chrome/browser/ui/webui/new_tab_page/composebox/composebox_handler.h"
 #include "chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom.h"
 #include "chrome/common/webui_url_constants.h"
 #include "components/omnibox/browser/searchbox.mojom-forward.h"
@@ -71,6 +70,7 @@
 }  // namespace ui
 
 class BrowserCommandHandler;
+class ComposeboxHandler;
 class CustomizeButtonsHandler;
 class DriveSuggestionHandler;
 #if !defined(OFFICIAL_BUILD)
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index 6c12f64..1c087ff 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1754222300-9bb903c0dc013aae1739e52615409e154f90d936-9b3977b2e6f1f8f628e141f90ec7092bbf716342.profdata
+chrome-android32-main-1754264961-328b4f8f45885da88d5c00d09226380f915cd88d-b03057e2cd6bb55b34c4f0f0d22d157de573807b.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index f4eefab..555e57f 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1754215234-0fabec944c58b68746ebd8e7176d0afac6a56c02-620e0ed8bab2d802377173c93a2c10ae06ea02c4.profdata
+chrome-android64-main-1754277689-c39026c1af291c57dce0114812c0204bfb0956b3-075588fcf198331d314595dcce222edd20087d24.profdata
diff --git a/chrome/build/android-desktop-x64.pgo.txt b/chrome/build/android-desktop-x64.pgo.txt
index 85e6c45..ccb7be6 100644
--- a/chrome/build/android-desktop-x64.pgo.txt
+++ b/chrome/build/android-desktop-x64.pgo.txt
@@ -1 +1 @@
-chrome-android-desktop-x64-main-1754222300-43799f802162b89a9cd2acee5aa605dce87d140d-9b3977b2e6f1f8f628e141f90ec7092bbf716342.profdata
+chrome-android-desktop-x64-main-1754264961-377a2902e00f98a14ef4f3e931687202ba789ee7-b03057e2cd6bb55b34c4f0f0d22d157de573807b.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 8ba03de..95beef107 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1754200082-b002a08fe1fff9c1f007e99a148b221461cd7724-6c0cd46d2200f6052a72bc168fc1e176333b2843.profdata
+chrome-mac-arm-main-1754272622-4d2697cd8a8766f8a2e7e274a8e71b3e069e619b-b6d3c7d0ab8c6c99f45ae64ab68d2cff789fe174.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 25bc376e..26b62dc 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1754179009-76ff6930b3c1a5c74a7421e5bae6fecb8e1a7746-1dd2444ad00c754411b270cccffcf43fe5c99778.profdata
+chrome-mac-main-1754243914-7481f3c93310a19aa152553a093b009f53304f02-1e7fc039133d2dfc53ede73bceb1fe1e5fea9bda.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 5ac315e6..817f59c5 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1754200082-416e416ce3806f7a5009936ec118fd70c7700966-6c0cd46d2200f6052a72bc168fc1e176333b2843.profdata
+chrome-win32-main-1754264961-6fb6646e859be78ab2c33b102db75af894b9bce4-b03057e2cd6bb55b34c4f0f0d22d157de573807b.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 08cf673..8ab2aab 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1754189924-21657fd77410b726fbe33b3e77934890a2bde418-abc6cbb226a0e6556d71b83aa0fd0189cbace172.profdata
+chrome-win64-main-1754264961-8a93788262cdac2d9d390480a78f6c51e9064a41-b03057e2cd6bb55b34c4f0f0d22d157de573807b.profdata
diff --git a/chrome/renderer/commerce/OWNERS b/chrome/renderer/commerce/OWNERS
index ddde9c60..da44be55 100644
--- a/chrome/renderer/commerce/OWNERS
+++ b/chrome/renderer/commerce/OWNERS
@@ -1,3 +1,2 @@
-yuezhanggg@chromium.org
 
-file://components/commerce/OWNERS
\ No newline at end of file
+file://components/commerce/OWNERS
diff --git a/chrome/test/data/webui/settings/settings_main_plugins_test.ts b/chrome/test/data/webui/settings/settings_main_plugins_test.ts
index 1744e67a..ac54503c 100644
--- a/chrome/test/data/webui/settings/settings_main_plugins_test.ts
+++ b/chrome/test/data/webui/settings/settings_main_plugins_test.ts
@@ -47,6 +47,7 @@
 
   setup(function() {
     createSettingsMain();
+    return settingsMain.whenViewSwitchingDone();
   });
 
   test('UpdatesActiveViewWhenRouteChanges', async function() {
@@ -86,7 +87,7 @@
 
     for (const {route, pluginTag} of routesToVisit) {
       Router.getInstance().navigateTo(route);
-      await flushTasks();
+      await settingsMain.whenViewSwitchingDone();
       assertActive(pluginTag, route.path);
     }
   });
@@ -174,7 +175,7 @@
 
     // Case2: Guest mode.
     createSettingsMain({isGuest: true});
-    await flushTasks();
+    await settingsMain.whenViewSwitchingDone();
     active = settingsMain.$.switcher.querySelector<HTMLElement>(
         '.active[slot=view]');
     assertTrue(!!active);
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index cc95f6c..28aeb61 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-16370.0.0-1070720
\ No newline at end of file
+16370.0.0-1070732
\ No newline at end of file
diff --git a/clank b/clank
index bdf12c2..45c2f62 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit bdf12c2772f61caaa6fe2ba099b9b6f81b8accd0
+Subproject commit 45c2f62260d04feed5cd4f2c0a44ed4c7fc77985
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc
index e7d517bb..b264c6c9 100644
--- a/components/autofill/core/browser/autofill_field.cc
+++ b/components/autofill/core/browser/autofill_field.cc
@@ -213,12 +213,7 @@
 // exceptions. Check function `ComputedType` for more details.
 DenseSet<HtmlFieldType> BelievedHtmlTypes(FieldType heuristic_prediction,
                                           FieldType server_prediction) {
-  DenseSet<HtmlFieldType> believed_html_types = {};
-  constexpr auto kMin = base::to_underlying(HtmlFieldType::kMinValue);
-  constexpr auto kMax = base::to_underlying(HtmlFieldType::kMaxValue);
-  for (auto i = kMin; i <= kMax; ++i) {
-    believed_html_types.insert(static_cast<HtmlFieldType>(i));
-  }
+  DenseSet<HtmlFieldType> believed_html_types = kAllHtmlFieldTypes;
   // We always override unspecified autocomplete attribute.
   believed_html_types.erase(HtmlFieldType::kUnspecified);
   auto is_street_name_or_house_number_type = [](FieldType field_type) {
diff --git a/components/autofill/core/browser/autofill_field_unittest.cc b/components/autofill/core/browser/autofill_field_unittest.cc
index 775c399..3446eab5 100644
--- a/components/autofill/core/browser/autofill_field_unittest.cc
+++ b/components/autofill/core/browser/autofill_field_unittest.cc
@@ -134,6 +134,28 @@
   EXPECT_EQ(field.PredictionSource(), std::nullopt);
 }
 
+// There are two ways to map a HtmlFieldType `t` to a FieldTypeGroup:
+// - `GroupTypeOfHtmlFieldType(t)`
+// - `GroupTypeOfFieldType(HtmlFieldTypeToBestCorrespondingFieldType(t))`
+// This test validates that they're mostly equivalent.
+// TODO(crbug.com/432827625): Make them fully equivalent.
+TEST_F(AutofillFieldTest, GroupsOfHtmlTypes) {
+  using enum HtmlFieldType;
+  static constexpr DenseSet<HtmlFieldType> kInconsistent = {
+      kTransactionAmount, kTransactionCurrency};
+  for (HtmlFieldType t : kAllHtmlFieldTypes) {
+    SCOPED_TRACE(testing::Message()
+                 << "HtmlFieldType: " << FieldTypeToStringView(t));
+    if (kInconsistent.contains(t)) {
+      continue;
+    }
+    FieldTypeGroup g1 = GroupTypeOfHtmlFieldType(t);
+    FieldTypeGroup g2 =
+        GroupTypeOfFieldType(HtmlFieldTypeToBestCorrespondingFieldType(t));
+    EXPECT_EQ(g1, g2);
+  }
+}
+
 constexpr HeuristicSource kRegexSource = HeuristicSource::kRegexes;
 constexpr HeuristicSource kMlSource = HeuristicSource::kAutofillMachineLearning;
 
diff --git a/components/autofill/core/browser/filling/form_filler.cc b/components/autofill/core/browser/filling/form_filler.cc
index 7fda1fe..9f75626 100644
--- a/components/autofill/core/browser/filling/form_filler.cc
+++ b/components/autofill/core/browser/filling/form_filler.cc
@@ -1202,7 +1202,15 @@
             return {value, autofill_field.Type().GetPasswordManagerType()};
           }},
       filling_payload.variant);
-  CHECK_NE(filled_field_type, UNKNOWN_TYPE, base::NotFatalUntil::M143);
+  CHECK(filled_field_type != UNKNOWN_TYPE ||
+            // The skip reasons lump all Autofill AI types together because
+            // there is only a single FillingProduct for Autofill AI. Therefore,
+            // when two Autofill AI FieldTypes of different entities appear in
+            // the form, only the above std::visit() calls detects that the
+            // value is not fillable and returns UNKNOWN_TYPE in that case.
+            std::holds_alternative<AugmentedFillingPayload::EntityPayload>(
+                filling_payload.variant),
+        base::NotFatalUntil::M143);
   return {value_to_fill, filled_field_type, /*value_is_an_override=*/false};
 }
 
diff --git a/components/autofill/core/browser/metrics/suggestions_list_metrics.cc b/components/autofill/core/browser/metrics/suggestions_list_metrics.cc
index a53b6a4..eb0d346 100644
--- a/components/autofill/core/browser/metrics/suggestions_list_metrics.cc
+++ b/components/autofill/core/browser/metrics/suggestions_list_metrics.cc
@@ -126,12 +126,13 @@
   base::UmaHistogramEnumeration(
       "Autofill.AddressSuggestionOnTyping.AddressFieldTypeUsed",
       field_type_used, FieldType::MAX_VALID_FIELD_TYPE);
-  FieldTypeSet field_types = autofill_trigger_field->Type().GetTypes();
+  FieldTypeSet field_types = autofill_trigger_field
+                                 ? autofill_trigger_field->Type().GetTypes()
+                                 : FieldTypeSet{};
   base::UmaHistogramBoolean(
       "Autofill.AddressSuggestionOnTypingAcceptance.FieldClassication",
-      autofill_trigger_field &&
-          !FieldTypeSet{NO_SERVER_DATA, UNKNOWN_TYPE, EMPTY_TYPE}.contains_all(
-              field_types));
+      !FieldTypeSet{NO_SERVER_DATA, UNKNOWN_TYPE, EMPTY_TYPE}.contains_all(
+          field_types));
   if (autofill_trigger_field) {
     base::UmaHistogramCounts100(
         "Autofill.AddressSuggestionOnTypingAcceptance.NumberOfCharactersTyped",
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index ec6f6380..662068c 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "62.3",
-  "log_list_timestamp": "2025-08-02T12:53:22Z",
+  "version": "62.4",
+  "log_list_timestamp": "2025-08-03T12:54:42Z",
   "operators": [
     {
       "name": "Google",
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index fceb9fb..733dfb4 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -1214,6 +1214,9 @@
     // The FeatureList needs to be created before starting the ThreadPool.
     StartBrowserThreadPool();
 
+    BrowserTaskExecutor::
+        InstallPartitionAllocSchedulerLoopQuarantineTaskObserver();
+
     // PowerMonitor is needed in reduced mode. BrowserMainLoop will safely skip
     // initializing it again if it has already been initialized.
     base::PowerMonitor::GetInstance()->Initialize(
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 882c11b..8b715f0d 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -1643,7 +1643,8 @@
   kNoRestart = 4,
   kTooManyRestart = 5,
   kSendingErrorAborted = 6,
-  kMaxValue = kSendingErrorAborted,
+  kDuringExclusiveTask = 7,
+  kMaxValue = kDuringExclusiveTask,
 };
 // LINT.ThenChange(//tools/metrics/histograms/metadata/navigation/enums.xml:OnAcceptCHFrameReceivedReturnLocation)
 
@@ -1761,6 +1762,18 @@
     return;
   }
 
+  if (loader_holder_.HasExclusiveTask()) {
+    // `OnAcceptCHFrameReceived()` is called unexpectedly during another
+    // exclusive task (typically `NavigationLoaderInterceptor`) is running.
+    // Cancel the navigation.
+    // TODO(https://crbug.com/436046316): Investigate why and fix this.
+    OnComplete(network::URLLoaderCompletionStatus(net::ERR_ABORTED));
+    std::move(callback).Run(net::ERR_ABORTED);
+    RecordOnAcceptCHFrameReceivedReturnLocation(
+        OnAcceptCHFrameReceivedReturnLocation::kDuringExclusiveTask);
+    return;
+  }
+
   std::move(callback).Run(net::ERR_ABORTED);
   RecordOnAcceptCHFrameReceivedReturnLocation(
       OnAcceptCHFrameReceivedReturnLocation::kSendingErrorAborted);
diff --git a/content/browser/network_service_browsertest.cc b/content/browser/network_service_browsertest.cc
index 8df05dc..8f3b26f 100644
--- a/content/browser/network_service_browsertest.cc
+++ b/content/browser/network_service_browsertest.cc
@@ -742,7 +742,6 @@
       EXPECT_GT(size_or_error, 0);
     }
     return loader->NetError();
-    ;
   }
 };
 
diff --git a/content/browser/preloading/anchor_element_interaction_host_impl.cc b/content/browser/preloading/anchor_element_interaction_host_impl.cc
index 9fa4d1b..ac40b38 100644
--- a/content/browser/preloading/anchor_element_interaction_host_impl.cc
+++ b/content/browser/preloading/anchor_element_interaction_host_impl.cc
@@ -13,6 +13,7 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/origin_util.h"
 #include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom-data-view.h"
 
 namespace content {
 
@@ -147,7 +148,10 @@
 void AnchorElementInteractionHostImpl::OnPointerHoverEager(
     const GURL& url,
     blink::mojom::AnchorElementPointerDataPtr mouse_data) {
-  // TODO(https://crbug.com/40287486): pipe this to PreloadingDecider.
+  auto* preloading_decider =
+      PreloadingDecider::GetOrCreateForCurrentDocument(&render_frame_host());
+  preloading_decider->OnPointerHover(
+      url, std::move(mouse_data), blink::mojom::SpeculationEagerness::kEager);
 }
 
 void AnchorElementInteractionHostImpl::OnPointerHoverModerate(
@@ -155,7 +159,9 @@
     blink::mojom::AnchorElementPointerDataPtr mouse_data) {
   auto* preloading_decider =
       PreloadingDecider::GetOrCreateForCurrentDocument(&render_frame_host());
-  preloading_decider->OnPointerHover(url, std::move(mouse_data));
+  preloading_decider->OnPointerHover(
+      url, std::move(mouse_data),
+      blink::mojom::SpeculationEagerness::kModerate);
   MaybePrewarmHttpDiskCache(url, render_frame_host());
   MaybeWarmUpServiceWorkerOnPointerHover(url, render_frame_host());
 }
diff --git a/content/browser/preloading/anchor_element_interaction_host_impl_unittest.cc b/content/browser/preloading/anchor_element_interaction_host_impl_unittest.cc
index 5efe7211..a38a65f4 100644
--- a/content/browser/preloading/anchor_element_interaction_host_impl_unittest.cc
+++ b/content/browser/preloading/anchor_element_interaction_host_impl_unittest.cc
@@ -14,6 +14,7 @@
 #include "content/test/test_web_contents.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom-data-view.h"
 #include "third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom-forward.h"
 #include "ui/base/page_transition_types.h"
 
@@ -40,10 +41,23 @@
       const std::vector<blink::mojom::SpeculationCandidatePtr>& candidates)
       override {}
   void OnPointerDown(const GURL& url) override { on_pointer_down_url_ = url; }
-  void OnPointerHover(const GURL& url) override { on_pointer_hover_url_ = url; }
+  void OnPointerHover(
+      const GURL& url,
+      blink::mojom::SpeculationEagerness target_eagerness) override {
+    on_pointer_hover_url_ = url;
+    on_pointer_hover_target_eagerness_ = target_eagerness;
+  }
+
+  void Reset() {
+    on_pointer_down_url_.reset();
+    on_pointer_hover_url_.reset();
+    on_pointer_hover_target_eagerness_.reset();
+  }
 
   std::optional<GURL> on_pointer_down_url_;
   std::optional<GURL> on_pointer_hover_url_;
+  std::optional<blink::mojom::SpeculationEagerness>
+      on_pointer_hover_target_eagerness_;
 
  private:
   raw_ptr<RenderFrameHostImpl> rfh_;
@@ -60,16 +74,13 @@
                                            remote.BindNewPipeAndPassReceiver());
 
   ScopedPreloadingDeciderObserver observer(render_frame_host);
-  observer.on_pointer_down_url_.reset();
-  observer.on_pointer_hover_url_.reset();
   const auto pointer_down_url = GURL("www.example.com/page1.html");
   remote->OnPointerDown(pointer_down_url);
   remote.FlushForTesting();
   EXPECT_EQ(pointer_down_url, observer.on_pointer_down_url_);
   EXPECT_FALSE(observer.on_pointer_hover_url_.has_value());
 
-  observer.on_pointer_down_url_.reset();
-  observer.on_pointer_hover_url_.reset();
+  observer.Reset();
   const auto pointer_hover_url = GURL("www.example.com/page2.html");
   remote->OnPointerHoverModerate(
       pointer_hover_url,
@@ -77,6 +88,20 @@
   remote.FlushForTesting();
   EXPECT_FALSE(observer.on_pointer_down_url_.has_value());
   EXPECT_EQ(pointer_hover_url, observer.on_pointer_hover_url_);
+  EXPECT_TRUE(observer.on_pointer_hover_target_eagerness_.has_value());
+  EXPECT_EQ(observer.on_pointer_hover_target_eagerness_,
+            blink::mojom::SpeculationEagerness::kModerate);
+
+  observer.Reset();
+  remote->OnPointerHoverEager(
+      pointer_hover_url,
+      blink::mojom::AnchorElementPointerData::New(false, 0.0, 0.0));
+  remote.FlushForTesting();
+  EXPECT_FALSE(observer.on_pointer_down_url_.has_value());
+  EXPECT_EQ(pointer_hover_url, observer.on_pointer_hover_url_);
+  EXPECT_TRUE(observer.on_pointer_hover_target_eagerness_.has_value());
+  EXPECT_EQ(observer.on_pointer_hover_target_eagerness_,
+            blink::mojom::SpeculationEagerness::kEager);
 }
 
 TEST_F(AnchorElementInteractionHostImplTest, OnViewportHeuristicTriggered) {
diff --git a/content/browser/preloading/preloading_decider.cc b/content/browser/preloading/preloading_decider.cc
index 05ededc8..628cb0d 100644
--- a/content/browser/preloading/preloading_decider.cc
+++ b/content/browser/preloading/preloading_decider.cc
@@ -9,6 +9,7 @@
 #include <string_view>
 #include <vector>
 
+#include "base/check_is_test.h"
 #include "base/check_op.h"
 #include "base/containers/enum_set.h"
 #include "base/feature_list.h"
@@ -33,6 +34,8 @@
 #include "content/public/browser/web_contents.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/preloading/anchor_element_interaction_host.mojom.h"
+#include "third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom-data-view.h"
+#include "third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom-forward.h"
 
 namespace content {
 
@@ -103,6 +106,14 @@
     pointer_hover_eagerness_ =
         EagernessSet{blink::mojom::SpeculationEagerness::kModerate};
 
+    if (base::FeatureList::IsEnabled(
+            blink::features::kPreloadingEagerHeuristics)) {
+      pointer_down_eagerness_.Put(blink::mojom::SpeculationEagerness::kEager);
+      pointer_hover_eagerness_.Put(blink::mojom::SpeculationEagerness::kEager);
+    }
+
+    CHECK(pointer_down_eagerness_.HasAll(pointer_hover_eagerness_));
+
     static const base::FeatureParam<std::string> kViewportHeuristicEagerness{
         &blink::features::kPreloadingViewportHeuristics,
         "viewport_heuristic_eagerness", "moderate"};
@@ -294,9 +305,17 @@
 
 void PreloadingDecider::OnPointerHover(
     const GURL& url,
-    blink::mojom::AnchorElementPointerDataPtr mouse_data) {
+    blink::mojom::AnchorElementPointerDataPtr mouse_data,
+    blink::mojom::SpeculationEagerness target_eagerness) {
+  // In non-test code, target eagerness must be either "moderate" or "eager".
+  if (target_eagerness != blink::mojom::SpeculationEagerness::kModerate &&
+      target_eagerness != blink::mojom::SpeculationEagerness::kEager) {
+    CHECK_IS_TEST();
+    return;
+  }
+
   if (observer_for_testing_) {
-    observer_for_testing_->OnPointerHover(url);
+    observer_for_testing_->OnPointerHover(url, target_eagerness);
   }
 
   WebContents* web_contents =
@@ -314,9 +333,16 @@
   // Preconnecting on hover events should not be done if the link is not safe
   // to prefetch or prerender.
   constexpr bool fallback_to_preconnect = false;
+  // Filter `kModerate` for the "eager" mouse hover to prevent false preloading.
+  EagernessSet eagerness_to_exclude;
+  if (base::FeatureList::IsEnabled(
+          blink::features::kPreloadingEagerHeuristics)) {
+    eagerness_to_exclude = EagernessSet::All();
+    eagerness_to_exclude.Remove(target_eagerness);
+  }
   MaybeEnactCandidate(url, preloading_predictor::kUrlPointerHoverOnAnchor,
                       PreloadingConfidence{100}, fallback_to_preconnect,
-                      /*eagerness_to_exclude=*/{});
+                      eagerness_to_exclude);
 }
 
 void PreloadingDecider::OnViewportHeuristicTriggered(const GURL& url) {
diff --git a/content/browser/preloading/preloading_decider.h b/content/browser/preloading/preloading_decider.h
index 79aa43c..497607a 100644
--- a/content/browser/preloading/preloading_decider.h
+++ b/content/browser/preloading/preloading_decider.h
@@ -27,7 +27,9 @@
   virtual void UpdateSpeculationCandidates(
       const std::vector<blink::mojom::SpeculationCandidatePtr>& candidates) = 0;
   virtual void OnPointerDown(const GURL& url) = 0;
-  virtual void OnPointerHover(const GURL& url) = 0;
+  virtual void OnPointerHover(
+      const GURL& url,
+      blink::mojom::SpeculationEagerness target_eagerness) = 0;
 };
 
 // Processes user interaction events and developer provided speculation-rules
@@ -51,7 +53,8 @@
 
   // Receives and processes on pointer hover event for 'url' target link.
   void OnPointerHover(const GURL& url,
-                      blink::mojom::AnchorElementPointerDataPtr mouse_data);
+                      blink::mojom::AnchorElementPointerDataPtr mouse_data,
+                      blink::mojom::SpeculationEagerness target_eagerness);
 
   //  Receives and processes ML model score for 'url' target link.
   void OnPreloadingHeuristicsModelDone(const GURL& url, float score);
diff --git a/content/browser/preloading/preloading_decider_browsertest.cc b/content/browser/preloading/preloading_decider_browsertest.cc
index 17398447..439e1fe0 100644
--- a/content/browser/preloading/preloading_decider_browsertest.cc
+++ b/content/browser/preloading/preloading_decider_browsertest.cc
@@ -182,7 +182,8 @@
   } else if (predictor() == preloading_predictor::kUrlPointerHoverOnAnchor) {
     preloading_decider->OnPointerHover(
         next_page_url,
-        blink::mojom::AnchorElementPointerData::New(true, 0.0, 0.0));
+        blink::mojom::AnchorElementPointerData::New(true, 0.0, 0.0),
+        blink::mojom::SpeculationEagerness::kModerate);
   } else if (predictor() ==
              preloading_predictor::kPreloadingHeuristicsMLModel) {
     preloading_decider->OnPreloadingHeuristicsModelDone(next_page_url,
diff --git a/content/browser/preloading/preloading_decider_unittest.cc b/content/browser/preloading/preloading_decider_unittest.cc
index 511e141..5cdc74ca 100644
--- a/content/browser/preloading/preloading_decider_unittest.cc
+++ b/content/browser/preloading/preloading_decider_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "base/feature_list.h"
 #include "base/strings/strcat.h"
 #include "base/strings/to_string.h"
 #include "base/test/scoped_feature_list.h"
@@ -31,6 +32,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/preloading/anchor_element_interaction_host.mojom.h"
+#include "third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom-data-view.h"
 #include "third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom-shared.h"
 
 namespace content {
@@ -227,6 +229,9 @@
       PreloadingDecider::GetOrCreateForCurrentDocument(&GetPrimaryMainFrame());
   ASSERT_TRUE(preloading_decider != nullptr);
 
+  const bool use_eager_heurisctics =
+      base::FeatureList::IsEnabled(blink::features::kPreloadingEagerHeuristics);
+
   // Create list of SpeculationCandidatePtrs.
   std::vector<std::tuple<bool, GURL, blink::mojom::SpeculationAction,
                          blink::mojom::SpeculationEagerness>>
@@ -236,7 +241,10 @@
                  {true, GetCrossOriginUrl("/candidate2.html"),
                   blink::mojom::SpeculationAction::kPrefetch,
                   blink::mojom::SpeculationEagerness::kModerate},
-                 {false, GetCrossOriginUrl("/candidate3.html"),
+                 {use_eager_heurisctics, GetCrossOriginUrl("/candidate3.html"),
+                  blink::mojom::SpeculationAction::kPrefetch,
+                  blink::mojom::SpeculationEagerness::kEager},
+                 {false, GetCrossOriginUrl("/candidate4.html"),
                   blink::mojom::SpeculationAction::kPrefetch,
                   blink::mojom::SpeculationEagerness::kImmediate},
                  {true, GetCrossOriginUrl("/candidate1.html"),
@@ -245,7 +253,10 @@
                  {true, GetCrossOriginUrl("/candidate2.html"),
                   blink::mojom::SpeculationAction::kPrerender,
                   blink::mojom::SpeculationEagerness::kModerate},
-                 {false, GetCrossOriginUrl("/candidate3.html"),
+                 {use_eager_heurisctics, GetCrossOriginUrl("/candidate3.html"),
+                  blink::mojom::SpeculationAction::kPrerender,
+                  blink::mojom::SpeculationEagerness::kEager},
+                 {false, GetCrossOriginUrl("/candidate4.html"),
                   blink::mojom::SpeculationAction::kPrerender,
                   blink::mojom::SpeculationEagerness::kImmediate}};
   std::vector<blink::mojom::SpeculationCandidatePtr> candidates;
@@ -266,7 +277,22 @@
 class PreloadingDeciderPointerEventHeuristicsTest
     : public PreloadingDeciderTest,
       public ::testing::WithParamInterface<
-          std::tuple<EventType, blink::mojom::SpeculationEagerness>> {};
+          std::tuple<EventType, blink::mojom::SpeculationEagerness>> {
+ public:
+  void SetUp() override {
+    feature_list_.InitAndEnableFeature(
+        blink::features::kPreloadingEagerHeuristics);
+    PreloadingDeciderTest::SetUp();
+  }
+
+  void TearDown() override {
+    PreloadingDeciderTest::TearDown();
+    feature_list_.Reset();
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
 
 TEST_P(PreloadingDeciderPointerEventHeuristicsTest,
        PrefetchOnPointerEventHeuristics) {
@@ -291,7 +317,8 @@
         break;
       case EventType::kPointerHover:
         preloading_decider->OnPointerHover(
-            url, blink::mojom::AnchorElementPointerData::New(false, 0.0, 0.0));
+            url, blink::mojom::AnchorElementPointerData::New(false, 0.0, 0.0),
+            eagerness);
         break;
     }
   };
@@ -399,7 +426,8 @@
         break;
       case EventType::kPointerHover:
         preloading_decider->OnPointerHover(
-            url, blink::mojom::AnchorElementPointerData::New(false, 0.0, 0.0));
+            url, blink::mojom::AnchorElementPointerData::New(false, 0.0, 0.0),
+            eagerness);
         break;
     }
   };
@@ -498,7 +526,8 @@
     PreloadingDeciderPointerEventHeuristicsTest,
     testing::Combine(
         testing::Values(EventType::kPointerDown, EventType::kPointerHover),
-        testing::Values(blink::mojom::SpeculationEagerness::kModerate,
+        testing::Values(blink::mojom::SpeculationEagerness::kEager,
+                        blink::mojom::SpeculationEagerness::kModerate,
                         blink::mojom::SpeculationEagerness::kConservative)));
 
 TEST_F(PreloadingDeciderTest, UmaRecallStats) {
@@ -588,15 +617,17 @@
   candidates.push_back(candidate_1.Clone());
   candidates.push_back(candidate_2.Clone());
 
-  // Add conservative and moderate  preload candidate and preload on
+  // Add conservative and moderate preload candidate and preload on
   // pointer-hover.
   preloading_decider->UpdateSpeculationCandidates(candidates);
   const auto& prefetches = GetPrefetchService()->prefetches_;
   preloading_decider->OnPointerHover(
-      url, blink::mojom::AnchorElementPointerData::New(
-               /*is_mouse_pointer=*/true,
-               /*mouse_velocity=*/75.0,
-               /*mouse_acceleration=*/0.0));
+      url,
+      blink::mojom::AnchorElementPointerData::New(
+          /*is_mouse_pointer=*/true,
+          /*mouse_velocity=*/75.0,
+          /*mouse_acceleration=*/0.0),
+      blink::mojom::SpeculationEagerness::kModerate);
 
   EXPECT_TRUE(prefetches[0]->HasSpeculationRulesTags());
   EXPECT_EQ(prefetches[0]->GetSpeculationRulesTagsHeaderString().value(),
@@ -957,17 +988,21 @@
 
   GURL url1{"https://www.example.com"};
   preloading_decider->OnPointerHover(
-      url1, blink::mojom::AnchorElementPointerData::New(
-                /*is_mouse_pointer=*/true,
-                /*mouse_velocity=*/50.0,
-                /*mouse_acceleration=*/0.0));
+      url1,
+      blink::mojom::AnchorElementPointerData::New(
+          /*is_mouse_pointer=*/true,
+          /*mouse_velocity=*/50.0,
+          /*mouse_acceleration=*/0.0),
+      /*is_eager=*/blink::mojom::SpeculationEagerness::kModerate);
 
   GURL url2{"https://www.google.com"};
   preloading_decider->OnPointerHover(
-      url2, blink::mojom::AnchorElementPointerData::New(
-                /*is_mouse_pointer=*/true,
-                /*mouse_velocity=*/75.0,
-                /*mouse_acceleration=*/0.0));
+      url2,
+      blink::mojom::AnchorElementPointerData::New(
+          /*is_mouse_pointer=*/true,
+          /*mouse_velocity=*/75.0,
+          /*mouse_acceleration=*/0.0),
+      /*is_eager=*/blink::mojom::SpeculationEagerness::kModerate);
 
   // Navigate to `url2`.
   NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(), url2);
@@ -1162,7 +1197,8 @@
   // The page has never received a prediction from the ML model, so we fallback
   // to the decisions of the hover heuristic.
   preloading_decider->OnPointerHover(
-      url, blink::mojom::AnchorElementPointerData::New(true, 0.0, 0.0));
+      url, blink::mojom::AnchorElementPointerData::New(true, 0.0, 0.0),
+      blink::mojom::SpeculationEagerness::kModerate);
   EXPECT_EQ(1u, prefetches.size());
 }
 
@@ -1320,7 +1356,8 @@
   // The model has indicated that the candidate is not worth prefetching, so we
   // should not prefetch based on the hover heuristic either.
   preloading_decider->OnPointerHover(
-      url, blink::mojom::AnchorElementPointerData::New(true, 0.0, 0.0));
+      url, blink::mojom::AnchorElementPointerData::New(true, 0.0, 0.0),
+      blink::mojom::SpeculationEagerness::kModerate);
   EXPECT_TRUE(prefetches.empty());
   // But once we have a stronger signal like pointer down, we should prefetch.
   preloading_decider->OnPointerDown(url);
diff --git a/content/browser/preloading/prerender/prerender_browsertest.cc b/content/browser/preloading/prerender/prerender_browsertest.cc
index d23ffef1..22c0655 100644
--- a/content/browser/preloading/prerender/prerender_browsertest.cc
+++ b/content/browser/preloading/prerender/prerender_browsertest.cc
@@ -11,6 +11,7 @@
 #include "base/command_line.h"
 #include "base/containers/flat_map.h"
 #include "base/containers/flat_set.h"
+#include "base/feature_list.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/functional/callback_forward.h"
@@ -35,6 +36,7 @@
 #include "base/test/test_mock_time_task_runner.h"
 #include "base/test/test_timeouts.h"
 #include "base/thread_annotations.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "cc/base/features.h"
@@ -885,7 +887,9 @@
 #endif  // !BUILDFLAG(IS_ANDROID)
   }
 
-  void PointerHoverToAnchor(const GURL& url) {
+  void PointerHoverToAnchor(
+      const GURL& url,
+      const std::optional<base::TimeDelta>& hover_time = std::nullopt) {
     ResetPointerPosition();
 
 #if !BUILDFLAG(IS_ANDROID)
@@ -896,6 +900,13 @@
     SimulateMouseEvent(web_contents(), blink::WebMouseEvent::Type::kMouseMove,
                        blink::WebMouseEvent::Button::kNoButton, point);
     waiter.Wait();
+    if (hover_time) {
+      base::RunLoop run_loop;
+      base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
+          FROM_HERE, run_loop.QuitClosure(), *hover_time);
+      run_loop.Run();
+      ResetPointerPosition();
+    }
 #else
     // TODO(crbug.com/40269669): Simulate |WebGestureEvent| to make this
     // function work for Android.
@@ -10619,6 +10630,9 @@
  public:
   void SetUp() override {
 #if !BUILDFLAG(IS_ANDROID)
+    sub_feature_list_.InitAndEnableFeatureWithParameters(
+        blink::features::kPreloadingEagerHeuristics,
+        {{"hover_dwell_time", "50ms"}});
     PrerenderBrowserTest::SetUp();
 #else
     // TODO(crbug.com/40269669): Add the implementation of pointer interaction
@@ -10626,6 +10640,14 @@
     GTEST_SKIP();
 #endif  // BUILDFLAG(IS_ANDROID)
   }
+
+  void TearDown() override {
+    PrerenderBrowserTest::TearDown();
+    sub_feature_list_.Reset();
+  }
+
+ private:
+  base::test::ScopedFeatureList sub_feature_list_;
 };
 
 namespace {
@@ -10653,7 +10675,9 @@
     OnEventCalled(Events::kUpdateSpeculationCandidates);
   }
 
-  void OnPointerHover(const GURL& url) override {
+  void OnPointerHover(
+      const GURL& url,
+      blink::mojom::SpeculationEagerness target_eagerness) override {
     OnEventCalled(Events::kOnPointerHover);
   }
 
@@ -10741,8 +10765,9 @@
 }
 
 // Tests speculation rules prerendering where the eagerness is "eager".
-// Currently, its behavior is the same as that of "immediate".
-// TODO(crbug.com/40287486): Update this test after the behavior changes.
+// Unless `kPreloadingEagerHeuristics` is enabled, its behavior is the same as
+// that of "immediate"; otherwise, there are dedicated rules to activate
+// speculative loads.
 IN_PROC_BROWSER_TEST_F(PrerenderEagernessBrowserTest, kEager) {
   const GURL initial_url = GetUrl("/empty.html");
   const GURL prerendering_url = GetUrl("/empty.html?prerender");
@@ -10751,20 +10776,66 @@
   ASSERT_TRUE(NavigateToURL(shell(), initial_url));
   InsertAnchor(prerendering_url);
 
-  RenderFrameHostImpl* rfh = current_frame_host();
-  auto* preloading_decider =
-      PreloadingDecider::GetOrCreateForCurrentDocument(rfh);
+  if (base::FeatureList::IsEnabled(
+          blink::features::kPreloadingEagerHeuristics)) {
+    const base::TimeDelta moderate_hover_time = base::Milliseconds(200);
+    const base::TimeDelta eager_hover_time =
+        blink::features::kPreloadingEagerHeuristicsHoverDwellTime.Get();
+    ASSERT_LE(eager_hover_time, moderate_hover_time);
+    // Use `eager_hover_time` + eps. The median time can cause flakiness.
+    const base::TimeDelta mid_hover_time =
+        eager_hover_time + (moderate_hover_time - eager_hover_time) / 10;
 
-  // Add speculation rules with the eagerness.
-  // When the eagerness is "immediate", speculation candidates will never be
-  // kept in the |on_standby_candidates_| on |PreloadingDecider|, and
-  // |PrerenderHost| will be created immediately.
-  AddPrerenderWithEagernessAsync(prerendering_url,
-                                 blink::mojom::SpeculationEagerness::kEager);
-  WaitForPrerenderLoadCompletion(prerendering_url);
-  EXPECT_TRUE(HasHostForUrl(prerendering_url));
-  EXPECT_FALSE(preloading_decider->IsOnStandByForTesting(
-      prerendering_url, blink::mojom::SpeculationAction::kPrerender));
+    RenderFrameHostImpl* rfh = current_frame_host();
+    PreloadingDeciderObserverForPrerenderTesting preloading_decider_observer(
+        rfh);
+    auto* preloading_decider =
+        PreloadingDecider::GetOrCreateForCurrentDocument(rfh);
+    // Add speculation rules with the "eager" eagerness.
+    // When the eagerness is not "immediate", speculation candidates will be
+    // kept in the |on_standby_candidates_| on |PreloadingDecider|.
+    // |PrerenderHost| will not be created at this time, waiting for user
+    // interaction(pointer hovering for the "eager").
+    AddPrerenderWithEagernessAsync(prerendering_url,
+                                   blink::mojom::SpeculationEagerness::kEager);
+    preloading_decider_observer.WaitUpdateSpeculationCandidates();
+    EXPECT_FALSE(HasHostForUrl(prerendering_url));
+    EXPECT_TRUE(preloading_decider->IsOnStandByForTesting(
+        prerendering_url, blink::mojom::SpeculationAction::kPrerender));
+    // Hover the anchor of the prerendering page. When eagerness is "eager" with
+    // `kPreloadingEagerHeuristics` enabled, this interaction invokes the
+    // creation of |PrerenderHost|.
+    // TODO(crbug.com/435622290): Test this on Mac
+#if !BUILDFLAG(IS_MAC)
+    ASSERT_GT(eager_hover_time, base::Milliseconds(0));
+    // Hover very briefly so that prerender is not triggered.
+    PointerHoverToAnchor(prerendering_url, eager_hover_time / 10);
+    EXPECT_TRUE(preloading_decider->IsOnStandByForTesting(
+        prerendering_url, blink::mojom::SpeculationAction::kPrerender));
+#endif  // !BUILDFLAG(IS_MAC)
+    // Hover enough time so that prerender is triggered for "eager".
+    PointerHoverToAnchor(prerendering_url, mid_hover_time);
+    preloading_decider_observer.WaitOnPointerHover();
+    WaitForPrerenderLoadCompletion(prerendering_url);
+    EXPECT_TRUE(HasHostForUrl(prerendering_url));
+    EXPECT_FALSE(preloading_decider->IsOnStandByForTesting(
+        prerendering_url, blink::mojom::SpeculationAction::kPrerender));
+  } else {
+    RenderFrameHostImpl* rfh = current_frame_host();
+    auto* preloading_decider =
+        PreloadingDecider::GetOrCreateForCurrentDocument(rfh);
+    // Add speculation rules with the "eager" eagerness.
+    // With `kPreloadingEagerHeuristics` disabled, the eagerness is the same as
+    // "immediate", speculation candidates will never be kept in the
+    // |on_standby_candidates_| on |PreloadingDecider|, and |PrerenderHost| will
+    // be created immediately.
+    AddPrerenderWithEagernessAsync(prerendering_url,
+                                   blink::mojom::SpeculationEagerness::kEager);
+    WaitForPrerenderLoadCompletion(prerendering_url);
+    EXPECT_TRUE(HasHostForUrl(prerendering_url));
+    EXPECT_FALSE(preloading_decider->IsOnStandByForTesting(
+        prerendering_url, blink::mojom::SpeculationAction::kPrerender));
+  }
 
   // Activate the prerendered page by clicking the anchor.
   FrameTreeNodeId host_id = GetHostForUrl(prerendering_url);
@@ -10802,8 +10873,27 @@
   EXPECT_TRUE(preloading_decider->IsOnStandByForTesting(
       prerendering_url, blink::mojom::SpeculationAction::kPrerender));
 
-  // Hover the anchor of the prerendering page. When eagerness is "moderate",
-  // this interaction invokes the creation of |PrerenderHost|.
+  // Hover the anchor of the prerendering page so briefly that only the hover
+  // event for "eager" is triggered but not triggered for "moderate".
+  if (base::FeatureList::IsEnabled(
+          blink::features::kPreloadingEagerHeuristics)) {
+    const base::TimeDelta moderate_hover_time = base::Milliseconds(200);
+    const base::TimeDelta eager_hover_time =
+        blink::features::kPreloadingEagerHeuristicsHoverDwellTime.Get();
+    // Use `eager_hover_time` + eps. The median time can cause flakiness.
+    const base::TimeDelta mid_hover_time =
+        eager_hover_time + (moderate_hover_time - eager_hover_time) / 10;
+    ASSERT_LT(mid_hover_time, moderate_hover_time);
+    PointerHoverToAnchor(prerendering_url, mid_hover_time);
+    preloading_decider_observer.WaitOnPointerHover();
+    EXPECT_FALSE(HasHostForUrl(prerendering_url));
+    EXPECT_TRUE(preloading_decider->IsOnStandByForTesting(
+        prerendering_url, blink::mojom::SpeculationAction::kPrerender));
+  }
+
+  // Hover the anchor of the prerendering page for a long enough time. When
+  // eagerness is "moderate", this interaction invokes the creation of
+  // |PrerenderHost|.
   PointerHoverToAnchor(prerendering_url);
   preloading_decider_observer.WaitOnPointerHover();
   WaitForPrerenderLoadCompletion(prerendering_url);
@@ -10895,19 +10985,22 @@
   AddPrerender(prerendering_url);
 
   // Navigate to the another url.
-  // Expect that the categories "Total" and "Immediate" record 1 and others
+  // Expect that the categories "Total" and "Immediate2" record 1 and others
   // record 0, as there was one immediate prerender of the previous page.
   const GURL next_url = GetUrl("/empty.html?next");
   ASSERT_TRUE(NavigateToURL(shell(), next_url));
   EXPECT_THAT(GetAllSamples("Conservative"),
               base::BucketsAre(base::Bucket(0, 1)));
   EXPECT_THAT(GetAllSamples("Moderate"), base::BucketsAre(base::Bucket(0, 1)));
-  EXPECT_THAT(GetAllSamples("Immediate"), base::BucketsAre(base::Bucket(1, 1)));
+  EXPECT_THAT(GetAllSamples("Eager2"), base::BucketsAre(base::Bucket(0, 1)));
+  EXPECT_THAT(GetAllSamples("Immediate2"),
+              base::BucketsAre(base::Bucket(1, 1)));
 
   // Next, try to trigger followings:
   // a) 4 prerenders whose eagerness is immediate
-  // b) 2 prerenders whose eagerness is moderate
-  // c) 1 prerenders whose eagerness is conservative
+  // b) 2 prerenders whose eagerness is eager
+  // c) 2 prerenders whose eagerness is moderate
+  // d) 1 prerenders whose eagerness is conservative
   // Then, try to activate the one of the URL(choosing conservative one).
 
   // a)
@@ -10919,6 +11012,22 @@
 
   // b)
   for (int i = 0; i < 2; ++i) {
+    GURL prerendering_url_eager =
+        GetUrl("/empty.html?prerender_eager_" + base::NumberToString(i));
+    if (base::FeatureList::IsEnabled(
+            blink::features::kPreloadingEagerHeuristics)) {
+      InsertAnchor(prerendering_url_eager);
+      AddPrerenderWithEagernessAsync(
+          prerendering_url_eager, blink::mojom::SpeculationEagerness::kEager);
+      PointerHoverToAnchor(prerendering_url_eager);
+      WaitForPrerenderLoadCompletion(prerendering_url_eager);
+    } else {
+      AddPrerender(prerendering_url_eager);
+    }
+  }
+
+  // c)
+  for (int i = 0; i < 2; ++i) {
     GURL prerendering_url_moderate =
         GetUrl("/empty.html?prerender_moderate_" + base::NumberToString(i));
     InsertAnchor(prerendering_url_moderate);
@@ -10929,7 +11038,7 @@
     WaitForPrerenderLoadCompletion(prerendering_url_moderate);
   }
 
-  // c)
+  // d)
   const GURL prerendering_url_conservative =
       GetUrl("/empty.html?prerender_conservative");
   InsertAnchor(prerendering_url_conservative);
@@ -10947,8 +11056,10 @@
   ASSERT_TRUE(activation_manager.was_activated());
 
   // Expect our results:
-  EXPECT_THAT(GetAllSamples("Immediate"),
+  EXPECT_THAT(GetAllSamples("Immediate2"),
               base::BucketsAre(base::Bucket(1, 1), base::Bucket(4, 1)));
+  EXPECT_THAT(GetAllSamples("Eager2"),
+              base::BucketsAre(base::Bucket(0, 1), base::Bucket(2, 1)));
   EXPECT_THAT(GetAllSamples("Moderate"),
               base::BucketsAre(base::Bucket(0, 1), base::Bucket(2, 1)));
   EXPECT_THAT(GetAllSamples("Conservative"),
@@ -11319,12 +11430,11 @@
 // Test whether speculation rules prerendering is processed again on pages
 // restored from BFCache via forward navigation.
 // When the eagerness is kImmediate(default), speculation rules prerendering
-// will no longer be processed after restoration. For non-immediate cases
-// (kModerate, kConservative), candidates are stored between restoration unless
-// they were triggered by user action (This test scenario reproduces only this
-// case). However, once after processed by user action, then they will not be
-// processed again until they are retriggered (crbug.com/1449163 for more
-// information).
+// will no longer be processed after restoration. For non-immediate cases,
+// candidates are stored between restoration unless they were triggered by user
+// action (This test scenario reproduces only this case). However, once after
+// processed by user action, then they will not be processed again until they
+// are retriggered (crbug.com/1449163 for more information).
 IN_PROC_BROWSER_TEST_P(PrerenderBackForwardCacheRestorationBrowserTest,
                        RestoredViaForwardNavigation) {
   const GURL initial_url = GetUrl("/empty.html");
diff --git a/content/browser/preloading/prerenderer_impl.cc b/content/browser/preloading/prerenderer_impl.cc
index 724206b..3ba3499 100644
--- a/content/browser/preloading/prerenderer_impl.cc
+++ b/content/browser/preloading/prerenderer_impl.cc
@@ -604,10 +604,10 @@
         conservative, trigger_type, "Conservative");
     RecordReceivedPrerendersPerPrimaryPageChangedCount(moderate, trigger_type,
                                                        "Moderate");
-    // `kEager` is treated as `kImmediate` here for historical reasons.
-    // TODO(crbug.com/40287486): Create new metrics to separate them.
-    RecordReceivedPrerendersPerPrimaryPageChangedCount(
-        eager + immediate, trigger_type, "Immediate");
+    RecordReceivedPrerendersPerPrimaryPageChangedCount(eager, trigger_type,
+                                                       "Eager2");
+    RecordReceivedPrerendersPerPrimaryPageChangedCount(immediate, trigger_type,
+                                                       "Immediate2");
   }
 }
 
diff --git a/content/browser/preloading/speculation_rules/speculation_host_impl_unittest.cc b/content/browser/preloading/speculation_rules/speculation_host_impl_unittest.cc
index f1d576b..00f3525 100644
--- a/content/browser/preloading/speculation_rules/speculation_host_impl_unittest.cc
+++ b/content/browser/preloading/speculation_rules/speculation_host_impl_unittest.cc
@@ -112,7 +112,9 @@
     }
   }
   void OnPointerDown(const GURL& url) override {}
-  void OnPointerHover(const GURL& url) override {}
+  void OnPointerHover(
+      const GURL& url,
+      blink::mojom::SpeculationEagerness target_eagerness) override {}
 
   std::vector<blink::mojom::SpeculationCandidatePtr> candidates_;
 
diff --git a/content/browser/preloading/speculation_rules/speculation_rules_util.h b/content/browser/preloading/speculation_rules/speculation_rules_util.h
index bbaf9e2..72e878d 100644
--- a/content/browser/preloading/speculation_rules/speculation_rules_util.h
+++ b/content/browser/preloading/speculation_rules/speculation_rules_util.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_BROWSER_PRELOADING_SPECULATION_RULES_SPECULATION_RULES_UTIL_H_
 #define CONTENT_BROWSER_PRELOADING_SPECULATION_RULES_SPECULATION_RULES_UTIL_H_
 
+#include "base/feature_list.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom-shared.h"
 
 namespace content {
@@ -20,8 +22,10 @@
     // `kEager` trigger strategies.
     // TODO(crbug.com/40287486): Update this according to the latest situation.
     case blink::mojom::SpeculationEagerness::kImmediate:
-    case blink::mojom::SpeculationEagerness::kEager:
       return true;
+    case blink::mojom::SpeculationEagerness::kEager:
+      return !base::FeatureList::IsEnabled(
+          blink::features::kPreloadingEagerHeuristics);
     case blink::mojom::SpeculationEagerness::kModerate:
     case blink::mojom::SpeculationEagerness::kConservative:
       return false;
diff --git a/content/browser/scheduler/browser_task_executor.cc b/content/browser/scheduler/browser_task_executor.cc
index ed96d73..b830e38 100644
--- a/content/browser/scheduler/browser_task_executor.cc
+++ b/content/browser/scheduler/browser_task_executor.cc
@@ -6,6 +6,7 @@
 
 #include <atomic>
 
+#include "base/check_deref.h"
 #include "base/functional/bind.h"
 #include "base/message_loop/message_pump_type.h"
 #include "base/run_loop.h"
@@ -299,4 +300,11 @@
   return io_thread;
 }
 
+// static
+void BrowserTaskExecutor::
+    InstallPartitionAllocSchedulerLoopQuarantineTaskObserver() {
+  CHECK_DEREF(Get()->browser_ui_thread_scheduler_.get())
+      .InstallPartitionAllocSchedulerLoopQuarantineTaskObserver();
+}
+
 }  // namespace content
diff --git a/content/browser/scheduler/browser_task_executor.h b/content/browser/scheduler/browser_task_executor.h
index 52cdf3b..2f75ebf9 100644
--- a/content/browser/scheduler/browser_task_executor.h
+++ b/content/browser/scheduler/browser_task_executor.h
@@ -113,6 +113,10 @@
       std::unique_ptr<BrowserUIThreadScheduler> browser_ui_thread_scheduler,
       std::unique_ptr<BrowserIOThreadDelegate> browser_io_thread_delegate);
 
+  // This must be called after the FeatureList has been initialized in order
+  // for scheduling experiments to function.
+  static void InstallPartitionAllocSchedulerLoopQuarantineTaskObserver();
+
   // Winds down the BrowserTaskExecutor, after this no tasks can be executed
   // and the base::TaskExecutor APIs are non-functional but won't crash if
   // called. In unittests however we need to clean up, so
diff --git a/content/browser/scheduler/browser_task_queues.cc b/content/browser/scheduler/browser_task_queues.cc
index 816b062..c91e31f 100644
--- a/content/browser/scheduler/browser_task_queues.cc
+++ b/content/browser/scheduler/browser_task_queues.cc
@@ -289,4 +289,10 @@
   }
 }
 
+void BrowserTaskQueues::AddTaskObserver(base::TaskObserver* task_observer) {
+  for (const auto& queue : queue_data_) {
+    queue.task_queue->AddTaskObserver(task_observer);
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/scheduler/browser_task_queues.h b/content/browser/scheduler/browser_task_queues.h
index f2e87d2c..03c06dca 100644
--- a/content/browser/scheduler/browser_task_queues.h
+++ b/content/browser/scheduler/browser_task_queues.h
@@ -173,6 +173,8 @@
 
   scoped_refptr<Handle> GetHandle() { return handle_; }
 
+  void AddTaskObserver(base::TaskObserver* task_observer);
+
  private:
   struct QueueData {
    public:
diff --git a/content/browser/scheduler/browser_ui_thread_scheduler.cc b/content/browser/scheduler/browser_ui_thread_scheduler.cc
index 2a5c92f9..a2edf29 100644
--- a/content/browser/scheduler/browser_ui_thread_scheduler.cc
+++ b/content/browser/scheduler/browser_ui_thread_scheduler.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/scheduler/browser_ui_thread_scheduler.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/feature_list.h"
@@ -21,6 +22,7 @@
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "content/browser/scheduler/browser_task_priority.h"
+#include "content/common/features.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_features.h"
 
@@ -35,9 +37,19 @@
 
 // static
 std::unique_ptr<BrowserUIThreadScheduler>
+BrowserUIThreadScheduler::CreateForTesting() {
+  auto scheduler = base::WrapUnique(new BrowserUIThreadScheduler());
+  scheduler->InstallPartitionAllocSchedulerLoopQuarantineTaskObserver();
+  return scheduler;
+}
+// static
+std::unique_ptr<BrowserUIThreadScheduler>
 BrowserUIThreadScheduler::CreateForTesting(
     base::sequence_manager::SequenceManager* sequence_manager) {
-  return base::WrapUnique(new BrowserUIThreadScheduler(sequence_manager));
+  auto scheduler =
+      base::WrapUnique(new BrowserUIThreadScheduler(sequence_manager));
+  scheduler->InstallPartitionAllocSchedulerLoopQuarantineTaskObserver();
+  return scheduler;
 }
 BrowserUIThreadScheduler* BrowserUIThreadScheduler::Get() {
   DCHECK(g_browser_ui_thread_scheduler);
@@ -92,4 +104,13 @@
   task_timing->RecordUmaOnCpuMetrics("BrowserScheduler.UIThread");
 }
 
+void BrowserUIThreadScheduler::
+    InstallPartitionAllocSchedulerLoopQuarantineTaskObserver() {
+  if (base::FeatureList::IsEnabled(
+          features::
+              kPartitionAllocSchedulerLoopQuarantineTaskObserverForBrowserUIThread)) {
+    task_queues_.AddTaskObserver(&scheduler_loop_quarantine_task_observer_);
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/scheduler/browser_ui_thread_scheduler.h b/content/browser/scheduler/browser_ui_thread_scheduler.h
index c5ee314f..45d35acc 100644
--- a/content/browser/scheduler/browser_ui_thread_scheduler.h
+++ b/content/browser/scheduler/browser_ui_thread_scheduler.h
@@ -12,6 +12,7 @@
 #include "base/time/time.h"
 #include "content/browser/scheduler/browser_task_queues.h"
 #include "content/common/content_export.h"
+#include "content/common/scheduler_loop_quarantine_task_observer.h"
 
 namespace base {
 namespace sequence_manager {
@@ -37,6 +38,10 @@
 
   static BrowserUIThreadScheduler* Get();
 
+  // Unlike the default constructor, this assumes a feature list is ready to be
+  // used. `InstallPartitionAllocSchedulerLoopQuarantineTaskObserver()` is
+  // called automatically.
+  static std::unique_ptr<BrowserUIThreadScheduler> CreateForTesting();
   // Setting the DefaultTaskRunner is up to the caller.
   static std::unique_ptr<BrowserUIThreadScheduler> CreateForTesting(
       base::sequence_manager::SequenceManager* sequence_manager);
@@ -57,6 +62,9 @@
   void CommonSequenceManagerSetup(
       base::sequence_manager::SequenceManager* sequence_manager);
 
+  // Reads a feature list; need to be called after its initialization.
+  void InstallPartitionAllocSchedulerLoopQuarantineTaskObserver();
+
   void OnTaskCompleted(
       const base::sequence_manager::Task& task,
       base::sequence_manager::TaskQueue::TaskTiming* task_timing,
@@ -68,6 +76,7 @@
       owned_sequence_manager_;
 
   BrowserTaskQueues task_queues_;
+  SchedulerLoopQuarantineTaskObserver scheduler_loop_quarantine_task_observer_;
 
   scoped_refptr<Handle> handle_;
 };
diff --git a/content/browser/scheduler/browser_ui_thread_scheduler_unittest.cc b/content/browser/scheduler/browser_ui_thread_scheduler_unittest.cc
index 77bbd37..5fedfca7 100644
--- a/content/browser/scheduler/browser_ui_thread_scheduler_unittest.cc
+++ b/content/browser/scheduler/browser_ui_thread_scheduler_unittest.cc
@@ -13,8 +13,15 @@
 #include "base/run_loop.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
+#include "base/test/bind.h"
 #include "base/test/mock_callback.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/test_future.h"
+#include "content/common/features.h"
 #include "content/public/browser/browser_thread.h"
+#include "partition_alloc/extended_api.h"
+#include "partition_alloc/partition_alloc_for_testing.h"
+#include "partition_alloc/scheduler_loop_quarantine_support.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace content {
@@ -63,6 +70,66 @@
   EXPECT_TRUE(run);
 }
 
+class BrowserUIThreadSchedulerLoopQuarantineTest : public testing::Test {
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_{
+      features::
+          kPartitionAllocSchedulerLoopQuarantineTaskObserverForBrowserUIThread};
+};
+
+TEST_F(BrowserUIThreadSchedulerLoopQuarantineTest,
+       TestAllocationGetPurgedFromQuarantineAfterTaskCompletion) {
+#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
+  GTEST_SKIP() << "This test does not work with memory tools.";
+#elif !PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) || \
+    !PA_CONFIG(THREAD_CACHE_SUPPORTED)
+  GTEST_SKIP() << "This test requires PA-E and ThreadCache.";
+#else
+  std::unique_ptr<BrowserUIThreadScheduler> browser_ui_thread_scheduler =
+      BrowserUIThreadScheduler::CreateForTesting();
+  browser_ui_thread_scheduler->GetHandle()->OnStartupComplete();
+
+  // Pick up a queue.
+  auto task_queue =
+      browser_ui_thread_scheduler->GetHandle()->GetBrowserTaskRunner(
+          BrowserUIThreadScheduler::QueueType::kUserBlocking);
+
+  // Prepare PA root for testing.
+  partition_alloc::PartitionOptions opts;
+  opts.scheduler_loop_quarantine_thread_local_config.enable_quarantine = true;
+  opts.scheduler_loop_quarantine_thread_local_config.branch_capacity_in_bytes =
+      4096;
+  partition_alloc::PartitionAllocatorForTesting allocator(opts);
+  partition_alloc::PartitionRoot& root = *allocator.root();
+
+  // Disables ThreadCache for the default allocator and enables it for the
+  // testing allocator.
+  partition_alloc::internal::ThreadCacheProcessScopeForTesting tcache_scope(
+      &root);
+
+  partition_alloc::internal::
+      ScopedSchedulerLoopQuarantineBranchAccessorForTesting branch_accessor(
+          &root);
+
+  void* ptr = root.Alloc(16);
+
+  base::test::TestFuture<void> future;
+  task_queue->PostTaskAndReply(
+      FROM_HERE, base::BindLambdaForTesting([&]() {
+        EXPECT_FALSE(branch_accessor.IsQuarantined(ptr));
+        root.Free<
+            partition_alloc::internal::FreeFlags::kSchedulerLoopQuarantine>(
+            ptr);
+        EXPECT_TRUE(branch_accessor.IsQuarantined(ptr));
+      }),
+      future.GetCallback());
+  EXPECT_TRUE(future.Wait());
+
+  // `ptr` must not be in the quarantine as the scheduler finished its loop.
+  EXPECT_FALSE(branch_accessor.IsQuarantined(ptr));
+#endif
+}
+
 }  // namespace
 
 }  // namespace content
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index a6f89819..733ae2d 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -153,6 +153,8 @@
     "process_visibility_tracker.h",
     "pseudonymization_salt.cc",
     "pseudonymization_salt.h",
+    "scheduler_loop_quarantine_task_observer.cc",
+    "scheduler_loop_quarantine_task_observer.h",
     "service_worker/forwarded_race_network_request_url_loader_factory.cc",
     "service_worker/forwarded_race_network_request_url_loader_factory.h",
     "service_worker/race_network_request_read_buffer_manager.cc",
diff --git a/content/common/features.cc b/content/common/features.cc
index 05898243..c53e0eb 100644
--- a/content/common/features.cc
+++ b/content/common/features.cc
@@ -296,6 +296,14 @@
              "RemoveRendererProcessLimit",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+// Purge PartitionAlloc's Scheduler-Loop quarantine when the UI thread is done
+// executing a task. This allow purging memory without scanning the stack. See:
+// https://crbug.com/329027914
+BASE_FEATURE(
+    kPartitionAllocSchedulerLoopQuarantineTaskObserverForBrowserUIThread,
+    "PartitionAllocSchedulerLoopQuarantineTaskObserverForBrowserUIThread",
+    base::FEATURE_DISABLED_BY_DEFAULT);
+
 // A feature flag for the memory-backed code cache.
 BASE_FEATURE(kInMemoryCodeCache,
              "InMemoryCodeCache",
diff --git a/content/common/features.h b/content/common/features.h
index 1be3c8f8..5cc31620 100644
--- a/content/common/features.h
+++ b/content/common/features.h
@@ -152,6 +152,8 @@
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kContinueGestureOnLosingFocus);
 #endif
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kRemoveRendererProcessLimit);
+CONTENT_EXPORT BASE_DECLARE_FEATURE(
+    kPartitionAllocSchedulerLoopQuarantineTaskObserverForBrowserUIThread);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kSendBeaconThrowForBlobWithNonSimpleType);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(
     kServiceWorkerAvoidMainThreadForInitialization);
diff --git a/content/common/scheduler_loop_quarantine_task_observer.cc b/content/common/scheduler_loop_quarantine_task_observer.cc
new file mode 100644
index 0000000..2526d3a
--- /dev/null
+++ b/content/common/scheduler_loop_quarantine_task_observer.cc
@@ -0,0 +1,18 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/scheduler_loop_quarantine_task_observer.h"
+
+namespace content {
+void SchedulerLoopQuarantineTaskObserver::WillProcessTask(
+    const base::PendingTask&,
+    bool) {
+  scan_policy_updater_.DisallowScanlessPurge();
+}
+
+void SchedulerLoopQuarantineTaskObserver::DidProcessTask(
+    const base::PendingTask&) {
+  scan_policy_updater_.AllowScanlessPurge();
+}
+}  // namespace content
diff --git a/content/common/scheduler_loop_quarantine_task_observer.h b/content/common/scheduler_loop_quarantine_task_observer.h
new file mode 100644
index 0000000..a9e65220
--- /dev/null
+++ b/content/common/scheduler_loop_quarantine_task_observer.h
@@ -0,0 +1,38 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_SCHEDULER_LOOP_QUARANTINE_TASK_OBSERVER_H_
+#define CONTENT_COMMON_SCHEDULER_LOOP_QUARANTINE_TASK_OBSERVER_H_
+
+#include "base/memory/safety_checks.h"
+#include "base/task/task_observer.h"
+#include "content/common/content_export.h"
+
+namespace content {
+// Scheduler-Loop Quarantine is a PartitionAlloc feature to protect pointers
+// on stack memory. This is a task observer to tell when stack memory is
+// nearly emptied based on task scheduling.
+//
+// For more details on the quarantine, see
+// `partition_alloc/scheduler_loop_quarantine.h`.
+class CONTENT_EXPORT SchedulerLoopQuarantineTaskObserver final
+    : public base::TaskObserver {
+ private:
+  // A task is about to start. To protect the task from Use-after-Free,
+  // this forces Scheduler-Loop Quarantine to perform stack-scanning
+  // when it needs to purge quarantined allocations.
+  // Re-entrancy is taken care of inside `scan_policy_updater_`.
+  void WillProcessTask(const base::PendingTask&, bool) final;
+
+  // At this point, the task is finished and we can say all local variables
+  // for it were destroyed. It implies there is no risk of dangling local
+  // pointer, hence allowing scan-less purge (faster but less secure).
+  void DidProcessTask(const base::PendingTask&) final;
+
+  base::SchedulerLoopQuarantineScanPolicyUpdater scan_policy_updater_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_SCHEDULER_LOOP_QUARANTINE_TASK_OBSERVER_H_
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 47cc7806..28887735 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -3148,6 +3148,7 @@
     ":test_support",
     "//base",
     "//base/allocator:buildflags",
+    "//base/allocator/partition_allocator/src/partition_alloc:test_support",
     "//base/test:fuzztest_support",
     "//base/test:proto_test_support",
     "//base/test:test_support",
diff --git a/internal b/internal
index ac35660..efb4f0a1 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit ac3566084be15e2d1322eeb396e76469b50d19b0
+Subproject commit efb4f0a19e8ccb65722c1639bb21e0572fe9a249
diff --git a/ios/chrome/browser/intelligence/bwg/model/bwg_session_delegate.h b/ios/chrome/browser/intelligence/bwg/model/bwg_session_delegate.h
index ec4bae7..2205d445 100644
--- a/ios/chrome/browser/intelligence/bwg/model/bwg_session_delegate.h
+++ b/ios/chrome/browser/intelligence/bwg/model/bwg_session_delegate.h
@@ -52,6 +52,7 @@
               pageContextAttached:(BOOL)pageContextAttached;
 
 // Called when a new chat button is tapped.
+// TODO(crbug.com/436019705) Rename this to `clientID` and `serverID`.
 - (void)didTapNewChatButtonWithSessionID:(NSString*)sessionID
                           conversationID:(NSString*)conversationID;
 
diff --git a/ios/chrome/browser/intelligence/bwg/model/bwg_session_handler.mm b/ios/chrome/browser/intelligence/bwg/model/bwg_session_handler.mm
index d45beb4..d146f7b 100644
--- a/ios/chrome/browser/intelligence/bwg/model/bwg_session_handler.mm
+++ b/ios/chrome/browser/intelligence/bwg/model/bwg_session_handler.mm
@@ -73,7 +73,12 @@
 // Called when a new chat button is tapped.
 - (void)didTapNewChatButtonWithSessionID:(NSString*)sessionID
                           conversationID:(NSString*)conversationID {
-  // NO-OP.
+  web::WebState* webState = [self webStateWithClientID:sessionID];
+  if (!webState) {
+    return;
+  }
+  BwgTabHelper* BWGTabHelper = BwgTabHelper::FromWebState(webState);
+  BWGTabHelper->DeleteBwgSessionInStorage();
 }
 
 #pragma mark - Private
diff --git a/ios/chrome/browser/intelligence/bwg/model/bwg_tab_helper.mm b/ios/chrome/browser/intelligence/bwg/model/bwg_tab_helper.mm
index c746c73f..0b22706 100644
--- a/ios/chrome/browser/intelligence/bwg/model/bwg_tab_helper.mm
+++ b/ios/chrome/browser/intelligence/bwg/model/bwg_tab_helper.mm
@@ -229,6 +229,15 @@
 }
 
 void BwgTabHelper::CleanupSessionFromPrefs(std::string session_id) {
+  if (IsGeminiCrossTabEnabled()) {
+    // TODO(crbug.com/436012307): Once this launches, remove `session_id` from
+    // method.
+    PrefService* pref_service =
+        ProfileIOS::FromBrowserState(web_state_->GetBrowserState())->GetPrefs();
+    pref_service->ClearPref(prefs::kGeminiConversationId);
+    return;
+  }
+
   if (session_id.empty()) {
     return;
   }
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 52b8a01..b58517f 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 @@
-3f648145bac0ea4bdffac53ef0f5345dc536a106
\ No newline at end of file
+339a6f56ddbcf9326e742369914642da1f142213
\ 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 72972121..c42d54d 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 @@
-c60140003e852c734e5e98767651d16f28f8ea4f
\ No newline at end of file
+636c7622a9ea404b044c6f7cd433eb8f566f5771
\ 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 5059703..eb077ed7 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 @@
-c4f03325f380962bd5a57e673f156ab3f0180e46
\ No newline at end of file
+400801f47ee79d8f267435510435d9411da0ad10
\ 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 5f47b694e..dcbbc6c 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 @@
-da939f40adf36bc69118e4963bdadc12d2971b27
\ No newline at end of file
+a1b591c192b5727ccb856a80a985d1f62b65edef
\ 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 0bd187b..a0cf158 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 @@
-d4326d1b262c3b23e3ec3aec81971c1a26c137de
\ No newline at end of file
+b2730042a613316fb773a023899c79825cafaeff
\ 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 868d074b..a6e25ac 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 @@
-a422e39865a822096bf17dc335dd024bdc23e4f9
\ No newline at end of file
+d96bf5617c67be1e391251e579c6e1d51bc1c04c
\ 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 d4601ac..5b73ac34d 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 @@
-8e21d8939ab53e6e6c907d4fc1479aeae65ce839
\ No newline at end of file
+bec882ee7b880b3ea2975446d5e7eb25e184f8d5
\ 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 27795ee..85c1342d 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 @@
-8575d0f12eb2147433ee0284856bdd403aa90d7f
\ No newline at end of file
+96541e8e02edb4e5eca186d3e16d40acb01afcdd
\ 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 b119bd3..b2cf1fe 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 @@
-672054b9527c45bf0e36f43fe13e0be9a8a5fa4d
\ No newline at end of file
+51c3754f0e2597bcbbe6d3940916e0dfefcc1e76
\ 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 1a56cb0..4f0531f 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 @@
-7c3958f3159c132b464a3b374df5de0ad4e0fcf3
\ No newline at end of file
+cc52d8f4efe43e07ec1a157d65e91b3b88b6b581
\ 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 26315c5..6865be4 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 @@
-97600b7ed30e8da4ccbce5fd7e0ae146f94f8084
\ No newline at end of file
+b72a4375c10b5a78fd288c8f6994d7bd64514c16
\ 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 4f71fb0..dec696c 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 @@
-0f9e847624d6acc56218df1afccefac0176e1929
\ No newline at end of file
+f539a3e4210f1630af93bb407e3b595172b34311
\ 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 c67e2fe..f62da6b3 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 @@
-df76c60c50e53078ae62f6684679ad18b0c6a676
\ No newline at end of file
+8dbe26a6e8ae6c1c3d7141f9f0cd14ca594ef18a
\ 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 2284b73..883f385 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 @@
-3c0ce9d8e6dd547d7cc10654f10a1f0927e55d8d
\ No newline at end of file
+ea5ff4046bee90f28d2dbd5cc1ff6d3b6450fbad
\ 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 e606343..50ea69f 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 @@
-1a3e671ae05a5abb634d32c0b9816fa555904f3d
\ No newline at end of file
+f2429605dd6b78288b0ac1b3d4ae44ed819df044
\ 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 602e5e6b..efa0988 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 @@
-e49f9c0864b49076bb683e7515480458693cb839
\ No newline at end of file
+0364e3a5144ad8f9cb4a1e869d01fd658c00559a
\ 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 4edb6c68..5efdbac 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 @@
-8498e55b64523cedf9cf152b6607cc34af94bfae
\ No newline at end of file
+2124c9d53e721a1305014ba09e0f2d9d1f0b54ab
\ 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 53a2616..5add6851 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 @@
-4bcfa5518df8dc628fb10cfd3a3644aee824e4e4
\ No newline at end of file
+27330ab98db7cc74fd28e6faac9b0943bb37621b
\ 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 157d7d6..77028a14 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 @@
-5200767f95bee40a91da86780fe9fd63e496c05a
\ No newline at end of file
+931bd8ed36aacb4982bc9bf3fd06a2314f635e47
\ 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 f413aa2..68ff22b 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 @@
-7a4c99eefae0bd129fc5734e5bce76210c859b07
\ No newline at end of file
+b888493205dd1206b75c34881b68d57c8ed20365
\ 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 89ba7e6..936b2c4 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 @@
-54ad7f096be08a4433422e049593ee1a6adc3b21
\ No newline at end of file
+d2b765b2823ea12b0156320cae2a5f8adf037c11
\ 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 ba4f7665..ff07732 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 @@
-39a8cfd85586c911947db35e8060136fda06a5e1
\ No newline at end of file
+8f0174662ca2ef1b39eac46b12151322dd4ab9fb
\ 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 3cced4f2c..bb3ed42f 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 @@
-f7d5c712320b2ea719cb52de3e7fd945261eb849
\ No newline at end of file
+24b62c24edb532788a6fa3b1a3c0f4b1c54fbcfb
\ 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 6f1e50eb..e257689 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 @@
-7046dd25d19cd6add0c8b5bf8420bc5b6074faf6
\ No newline at end of file
+6a4e92816b2565f6f6c7a0b1ff017802face1aad
\ 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 e358606..e3554677 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 @@
-71b3ef5c81a6456a4e33b1818a29eca3a39203d4
\ No newline at end of file
+eb94b8e5d55b4b4d4354005ffa12ebca10bdd270
\ 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 630bde9..861ea708 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 @@
-fa18329a95ce624969d5ca420211cf42a2a3ed4a
\ No newline at end of file
+63ecb478c8d5226828cf60be004a151a5e9c97dd
\ 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 0a90c67..57f6ed092 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 @@
-c2c428b5a5c1adca1501462ad97543dd28e737d9
\ No newline at end of file
+1e7d9d42fbc6d8c14dcafdbff647ac38f050aeb4
\ 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 18cbeee..d3480e05 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 @@
-81eda78755a5bbb9de71404f4d4783294614848f
\ No newline at end of file
+dcebd4d213d21dfc349c18c0ba70e4da11d2e809
\ No newline at end of file
diff --git a/ios_internal b/ios_internal
index 2895e17..aa425b7 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit 2895e17b8cb4e8f1c26617d9f104be21967694ab
+Subproject commit aa425b74d980d8414aa5b414fe70e1e68a2265ff
diff --git a/net/http/bidirectional_stream.cc b/net/http/bidirectional_stream.cc
index 0a99fd3..c4cf85d 100644
--- a/net/http/bidirectional_stream.cc
+++ b/net/http/bidirectional_stream.cc
@@ -211,7 +211,7 @@
   stream_request_ =
       session_->http_stream_factory()->RequestBidirectionalStreamImpl(
           http_request_info, request_info_->priority, /*allowed_bad_certs=*/{},
-          this, /* enable_ip_based_pooling = */ true,
+          this, /* enable_ip_based_pooling_for_h2 = */ true,
           /* enable_alternative_services = */ true, net_log_);
   // Check that this call does not fail.
   DCHECK(stream_request_);
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 89dc681..4593bdc 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -1097,7 +1097,7 @@
   // IP based pooling is only disabled on a retry after 421 Misdirected Request
   // is received. Alternative Services are also disabled in this case (though
   // they can also be disabled when retrying after a QUIC error).
-  if (!enable_ip_based_pooling_) {
+  if (!enable_ip_based_pooling_for_h2_) {
     DCHECK(!enable_alternative_services_);
   }
 
@@ -1111,11 +1111,13 @@
         session_->http_stream_factory()->RequestWebSocketHandshakeStream(
             *request_, priority_, /*allowed_bad_certs=*/observed_bad_certs_,
             this, websocket_handshake_stream_base_create_helper_,
-            enable_ip_based_pooling_, enable_alternative_services_, net_log_);
+            enable_ip_based_pooling_for_h2_, enable_alternative_services_,
+            net_log_);
   } else {
     stream_request_ = session_->http_stream_factory()->RequestStream(
         *request_, priority_, /*allowed_bad_certs=*/observed_bad_certs_, this,
-        enable_ip_based_pooling_, enable_alternative_services_, net_log_);
+        enable_ip_based_pooling_for_h2_, enable_alternative_services_,
+        net_log_);
   }
   DCHECK(stream_request_.get());
   return ERR_IO_PENDING;
@@ -1686,14 +1688,14 @@
       request_->upload_data_stream &&
       request_->upload_data_stream->has_null_source();
   if (response_.headers->response_code() == 421 &&
-      (enable_ip_based_pooling_ || enable_alternative_services_) &&
+      (enable_ip_based_pooling_for_h2_ || enable_alternative_services_) &&
       !has_body_with_null_source) {
 #if BUILDFLAG(ENABLE_REPORTING)
     GenerateNetworkErrorLoggingReport(OK);
 #endif  // BUILDFLAG(ENABLE_REPORTING)
     // Retry the request with both IP based pooling and Alternative Services
     // disabled.
-    enable_ip_based_pooling_ = false;
+    enable_ip_based_pooling_for_h2_ = false;
     enable_alternative_services_ = false;
     net_log_.AddEvent(
         NetLogEventType::HTTP_TRANSACTION_RESTART_MISDIRECTED_REQUEST);
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h
index f575984..c40a683 100644
--- a/net/http/http_network_transaction.h
+++ b/net/http/http_network_transaction.h
@@ -464,7 +464,11 @@
 
   // Enable pooling to a SpdySession with matching IP and certificate
   // even if the SpdySessionKey is different.
-  bool enable_ip_based_pooling_ = true;
+  // While QUIC also has a notion of IP based pooling / connection aliasing,
+  // this field does not affect QUIC. `enable_alternative_services_` is always
+  // set to false when this field is, which disables QUIC. If that ever changes,
+  // this field should probably be wired up to QUIC sessions as well.
+  bool enable_ip_based_pooling_for_h2_ = true;
 
   // Enable using alternative services for the request.
   bool enable_alternative_services_ = true;
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index bcdd0a2..285167f8 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -11854,7 +11854,7 @@
   EXPECT_THAT(rv, IsOk());
   EXPECT_TRUE(session->spdy_session_pool()->HasAvailableSession(
       kSpdySessionKey,
-      /*enable_ip_based_pooling=*/true, /*is_websocket=*/false));
+      /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false));
 
   EXPECT_FALSE(trans.IsReadyToRestartForAuth());
 
@@ -11905,7 +11905,7 @@
       url::SchemeHostPort(request.url), NetworkAnonymizationKey()));
   EXPECT_FALSE(session->spdy_session_pool()->HasAvailableSession(
       kSpdySessionKey,
-      /*enable_ip_based_pooling=*/true, /*is_websocket=*/false));
+      /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false));
 }
 
 // Same as above, but with a host mapping in place. The mapped host is the one
@@ -12035,7 +12035,7 @@
   EXPECT_THAT(rv, IsOk());
   EXPECT_TRUE(session->spdy_session_pool()->HasAvailableSession(
       kMappedSpdySessionKey,
-      /*enable_ip_based_pooling=*/true, /*is_websocket=*/false));
+      /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false));
 
   EXPECT_FALSE(trans.IsReadyToRestartForAuth());
 
@@ -12088,7 +12088,7 @@
       url::SchemeHostPort(GURL(kMappedUrl)), NetworkAnonymizationKey()));
   EXPECT_FALSE(session->spdy_session_pool()->HasAvailableSession(
       kMappedSpdySessionKey,
-      /*enable_ip_based_pooling=*/true, /*is_websocket=*/false));
+      /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false));
 }
 
 // Same as NTLMOverHttp2, but with HTTP proxy.
@@ -12224,7 +12224,7 @@
   EXPECT_THAT(rv, IsOk());
   EXPECT_TRUE(session->spdy_session_pool()->HasAvailableSession(
       kSpdySessionKey,
-      /*enable_ip_based_pooling=*/true, /*is_websocket=*/false));
+      /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false));
 
   const HttpResponseInfo* response = trans.GetResponseInfo();
   ASSERT_TRUE(response);
@@ -12266,7 +12266,7 @@
       url::SchemeHostPort(request.url), NetworkAnonymizationKey()));
   EXPECT_FALSE(session->spdy_session_pool()->HasAvailableSession(
       kSpdySessionKey,
-      /*enable_ip_based_pooling=*/true, /*is_websocket=*/false));
+      /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false));
 }
 
 #if BUILDFLAG(ENABLE_WEBSOCKETS)
@@ -12461,7 +12461,7 @@
   EXPECT_THAT(websocket_callback.GetResult(rv), IsOk());
   EXPECT_TRUE(session->spdy_session_pool()->HasAvailableSession(
       kSpdySessionKey,
-      /*enable_ip_based_pooling=*/true, /*is_websocket=*/true));
+      /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/true));
 
   EXPECT_FALSE(websocket_trans.IsReadyToRestartForAuth());
 
@@ -12491,7 +12491,7 @@
       url::SchemeHostPort(kInitialUrl), NetworkAnonymizationKey()));
   EXPECT_FALSE(session->spdy_session_pool()->HasAvailableSession(
       kSpdySessionKey,
-      /*enable_ip_based_pooling=*/true, /*is_websocket=*/true));
+      /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/true));
 }
 
 #endif  // BUILDFLAG(ENABLE_WEBSOCKETS)
diff --git a/net/http/http_proxy_connect_job.cc b/net/http/http_proxy_connect_job.cc
index 5f131321..a34459b3 100644
--- a/net/http/http_proxy_connect_job.cc
+++ b/net/http/http_proxy_connect_job.cc
@@ -513,7 +513,7 @@
     // Skip making a new connection if we have an existing HTTP/2 session.
     if (params_->tunnel() &&
         common_connect_job_params()->spdy_session_pool->FindAvailableSession(
-            CreateSpdySessionKey(), /*enable_ip_based_pooling=*/false,
+            CreateSpdySessionKey(), /*enable_ip_based_pooling_for_h2=*/false,
             /*is_websocket=*/false, net_log())) {
       next_state_ = STATE_SPDY_PROXY_CREATE_STREAM;
       return OK;
@@ -678,7 +678,7 @@
   SpdySessionKey key = CreateSpdySessionKey();
   base::WeakPtr<SpdySession> spdy_session =
       common_connect_job_params()->spdy_session_pool->FindAvailableSession(
-          key, /* enable_ip_based_pooling = */ false,
+          key, /* enable_ip_based_pooling_for_h2 = */ false,
           /* is_websocket = */ false, net_log());
   // It's possible that a session to the proxy has recently been created
   if (spdy_session) {
diff --git a/net/http/http_proxy_connect_job_unittest.cc b/net/http/http_proxy_connect_job_unittest.cc
index a5972c7..93f7fa2 100644
--- a/net/http/http_proxy_connect_job_unittest.cc
+++ b/net/http/http_proxy_connect_job_unittest.cc
@@ -1300,7 +1300,7 @@
                          SessionUsage::kProxy, SocketTag(),
                          NetworkAnonymizationKey(), SecureDnsPolicy::kDisable,
                          /*disable_cert_verification_network_fetches=*/true),
-          /* enable_ip_based_pooling = */ false,
+          /* enable_ip_based_pooling_for_h2 = */ false,
           /* is_websocket = */ false, NetLogWithSource()));
   EXPECT_FALSE(
       common_connect_job_params_->spdy_session_pool->FindAvailableSession(
@@ -1309,7 +1309,7 @@
                          SessionUsage::kProxy, SocketTag(),
                          NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
                          /*disable_cert_verification_network_fetches=*/true),
-          /* enable_ip_based_pooling = */ false,
+          /* enable_ip_based_pooling_for_h2 = */ false,
           /* is_websocket = */ false, NetLogWithSource()));
 }
 
@@ -1386,7 +1386,7 @@
                          SessionUsage::kProxy, SocketTag(),
                          NetworkAnonymizationKey(), SecureDnsPolicy::kDisable,
                          /*disable_cert_verification_network_fetches=*/true),
-          /*enable_ip_based_pooling=*/false,
+          /*enable_ip_based_pooling_for_h2=*/false,
           /*is_websocket=*/false, NetLogWithSource()));
 }
 
@@ -1435,7 +1435,7 @@
                          SessionUsage::kProxy, SocketTag(),
                          NetworkAnonymizationKey(), SecureDnsPolicy::kDisable,
                          /*disable_cert_verification_network_fetches=*/true),
-          /*enable_ip_based_pooling=*/false,
+          /*enable_ip_based_pooling_for_h2=*/false,
           /*is_websocket=*/false, NetLogWithSource()));
 }
 
@@ -1472,7 +1472,7 @@
                          SessionUsage::kProxy, SocketTag(),
                          NetworkAnonymizationKey(), SecureDnsPolicy::kDisable,
                          /*disable_cert_verification_network_fetches=*/true),
-          /*enable_ip_based_pooling=*/false,
+          /*enable_ip_based_pooling_for_h2=*/false,
           /*is_websocket=*/false, NetLogWithSource()));
 }
 
@@ -1517,7 +1517,7 @@
                          SessionUsage::kProxy, SocketTag(),
                          NetworkAnonymizationKey(), SecureDnsPolicy::kDisable,
                          /*disable_cert_verification_network_fetches=*/true),
-          /*enable_ip_based_pooling=*/false,
+          /*enable_ip_based_pooling_for_h2=*/false,
           /*is_websocket=*/false, NetLogWithSource()));
 }
 
diff --git a/net/http/http_stream_factory.cc b/net/http/http_stream_factory.cc
index 17b2e358..b506ce5 100644
--- a/net/http/http_stream_factory.cc
+++ b/net/http/http_stream_factory.cc
@@ -169,14 +169,14 @@
     RequestPriority priority,
     const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
     HttpStreamRequest::Delegate* delegate,
-    bool enable_ip_based_pooling,
+    bool enable_ip_based_pooling_for_h2,
     bool enable_alternative_services,
     const NetLogWithSource& net_log) {
-  return RequestStreamInternal(request_info, priority, allowed_bad_certs,
-                               delegate, nullptr,
-                               HttpStreamRequest::HTTP_STREAM,
-                               /*is_websocket=*/false, enable_ip_based_pooling,
-                               enable_alternative_services, net_log);
+  return RequestStreamInternal(
+      request_info, priority, allowed_bad_certs, delegate, nullptr,
+      HttpStreamRequest::HTTP_STREAM,
+      /*is_websocket=*/false, enable_ip_based_pooling_for_h2,
+      enable_alternative_services, net_log);
 }
 
 std::unique_ptr<HttpStreamRequest>
@@ -186,15 +186,15 @@
     const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
     HttpStreamRequest::Delegate* delegate,
     WebSocketHandshakeStreamBase::CreateHelper* create_helper,
-    bool enable_ip_based_pooling,
+    bool enable_ip_based_pooling_for_h2,
     bool enable_alternative_services,
     const NetLogWithSource& net_log) {
   DCHECK(create_helper);
-  return RequestStreamInternal(request_info, priority, allowed_bad_certs,
-                               delegate, create_helper,
-                               HttpStreamRequest::HTTP_STREAM,
-                               /*is_websocket=*/true, enable_ip_based_pooling,
-                               enable_alternative_services, net_log);
+  return RequestStreamInternal(
+      request_info, priority, allowed_bad_certs, delegate, create_helper,
+      HttpStreamRequest::HTTP_STREAM,
+      /*is_websocket=*/true, enable_ip_based_pooling_for_h2,
+      enable_alternative_services, net_log);
 }
 
 std::unique_ptr<HttpStreamRequest>
@@ -203,16 +203,16 @@
     RequestPriority priority,
     const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
     HttpStreamRequest::Delegate* delegate,
-    bool enable_ip_based_pooling,
+    bool enable_ip_based_pooling_for_h2,
     bool enable_alternative_services,
     const NetLogWithSource& net_log) {
   DCHECK(request_info.url.SchemeIs(url::kHttpsScheme));
 
-  return RequestStreamInternal(request_info, priority, allowed_bad_certs,
-                               delegate, nullptr,
-                               HttpStreamRequest::BIDIRECTIONAL_STREAM,
-                               /*is_websocket=*/false, enable_ip_based_pooling,
-                               enable_alternative_services, net_log);
+  return RequestStreamInternal(
+      request_info, priority, allowed_bad_certs, delegate, nullptr,
+      HttpStreamRequest::BIDIRECTIONAL_STREAM,
+      /*is_websocket=*/false, enable_ip_based_pooling_for_h2,
+      enable_alternative_services, net_log);
 }
 
 std::unique_ptr<HttpStreamRequest> HttpStreamFactory::RequestStreamInternal(
@@ -224,7 +224,7 @@
         websocket_handshake_stream_create_helper,
     HttpStreamRequest::StreamType stream_type,
     bool is_websocket,
-    bool enable_ip_based_pooling,
+    bool enable_ip_based_pooling_for_h2,
     bool enable_alternative_services,
     const NetLogWithSource& net_log) {
   // This is only needed in the non-preconnect path, as preconnects do not
@@ -233,7 +233,7 @@
 
   auto job_controller = std::make_unique<JobController>(
       this, delegate, session_, job_factory_.get(), request_info,
-      /* is_preconnect = */ false, is_websocket, enable_ip_based_pooling,
+      /* is_preconnect = */ false, is_websocket, enable_ip_based_pooling_for_h2,
       enable_alternative_services,
       session_->context()
           .quic_context->params()
@@ -261,7 +261,7 @@
       this, nullptr, session_, job_factory_.get(), request_info,
       /*is_preconnect=*/true,
       /*is_websocket=*/false,
-      /*enable_ip_based_pooling=*/true,
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*enable_alternative_services=*/true,
       session_->context()
           .quic_context->params()
diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h
index f18b6e6..48eb850 100644
--- a/net/http/http_stream_factory.h
+++ b/net/http/http_stream_factory.h
@@ -131,7 +131,7 @@
       RequestPriority priority,
       const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
       HttpStreamRequest::Delegate* delegate,
-      bool enable_ip_based_pooling,
+      bool enable_ip_based_pooling_for_h2,
       bool enable_alternative_services,
       const NetLogWithSource& net_log);
 
@@ -144,7 +144,7 @@
       const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
       HttpStreamRequest::Delegate* delegate,
       WebSocketHandshakeStreamBase::CreateHelper* create_helper,
-      bool enable_ip_based_pooling,
+      bool enable_ip_based_pooling_for_h2,
       bool enable_alternative_services,
       const NetLogWithSource& net_log);
 
@@ -158,7 +158,7 @@
       RequestPriority priority,
       const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
       HttpStreamRequest::Delegate* delegate,
-      bool enable_ip_based_pooling,
+      bool enable_ip_based_pooling_for_h2,
       bool enable_alternative_services,
       const NetLogWithSource& net_log);
 
@@ -198,7 +198,7 @@
       WebSocketHandshakeStreamBase::CreateHelper* create_helper,
       HttpStreamRequest::StreamType stream_type,
       bool is_websocket,
-      bool enable_ip_based_pooling,
+      bool enable_ip_based_pooling_for_h2,
       bool enable_alternative_services,
       const NetLogWithSource& net_log);
 
diff --git a/net/http/http_stream_factory_job.cc b/net/http/http_stream_factory_job.cc
index f8c2e21..d2ff50d 100644
--- a/net/http/http_stream_factory_job.cc
+++ b/net/http/http_stream_factory_job.cc
@@ -113,7 +113,7 @@
     NextProto alternative_protocol,
     quic::ParsedQuicVersion quic_version,
     bool is_websocket,
-    bool enable_ip_based_pooling,
+    bool enable_ip_based_pooling_for_h2,
     std::optional<ConnectionManagementConfig> management_config,
     NetLog* net_log)
     : request_info_(request_info),
@@ -132,8 +132,8 @@
       try_websocket_over_http2_(is_websocket_ &&
                                 origin_url_.SchemeIs(url::kWssScheme)),
       // Only support IP-based pooling for non-proxied streams.
-      enable_ip_based_pooling_(enable_ip_based_pooling &&
-                               proxy_info.is_direct()),
+      enable_ip_based_pooling_for_h2_(enable_ip_based_pooling_for_h2 &&
+                                      proxy_info.is_direct()),
       delegate_(delegate),
       job_type_(job_type),
       using_ssl_(origin_url_.SchemeIs(url::kHttpsScheme) ||
@@ -744,7 +744,7 @@
 
         bool is_blocking_request_for_session;
         existing_spdy_session_ = session_->spdy_session_pool()->RequestSession(
-            spdy_session_key_, enable_ip_based_pooling_, is_websocket_,
+            spdy_session_key_, enable_ip_based_pooling_for_h2_, is_websocket_,
             net_log_, resume_callback, this, &spdy_session_request_,
             &is_blocking_request_for_session);
         if (!existing_spdy_session_ && should_throttle_connect &&
@@ -755,7 +755,7 @@
               FROM_HERE, resume_callback, base::Milliseconds(kHTTP2ThrottleMs));
           return ERR_IO_PENDING;
         }
-      } else if (enable_ip_based_pooling_) {
+      } else if (enable_ip_based_pooling_for_h2_) {
         // If already watching for an H2 session, still need to check for an
         // existing connection that can be reused through IP pooling, as those
         // don't post session available notifications.
@@ -764,8 +764,8 @@
         // callback.
         existing_spdy_session_ =
             session_->spdy_session_pool()->FindAvailableSession(
-                spdy_session_key_, enable_ip_based_pooling_, is_websocket_,
-                net_log_);
+                spdy_session_key_, enable_ip_based_pooling_for_h2_,
+                is_websocket_, net_log_);
       }
     }
     if (existing_spdy_session_) {
@@ -1140,7 +1140,7 @@
 
     existing_spdy_session_ =
         session_->spdy_session_pool()->FindAvailableSession(
-            spdy_session_key_, enable_ip_based_pooling_,
+            spdy_session_key_, enable_ip_based_pooling_for_h2_,
             /* is_websocket = */ false, net_log_);
   }
   if (existing_spdy_session_) {
@@ -1267,7 +1267,7 @@
     url::SchemeHostPort destination,
     GURL origin_url,
     bool is_websocket,
-    bool enable_ip_based_pooling,
+    bool enable_ip_based_pooling_for_h2,
     NetLog* net_log,
     NextProto alternative_protocol,
     quic::ParsedQuicVersion quic_version,
@@ -1275,8 +1275,8 @@
   return std::make_unique<HttpStreamFactory::Job>(
       delegate, job_type, session, request_info, priority, proxy_info,
       allowed_bad_certs, std::move(destination), origin_url,
-      alternative_protocol, quic_version, is_websocket, enable_ip_based_pooling,
-      management_config, net_log);
+      alternative_protocol, quic_version, is_websocket,
+      enable_ip_based_pooling_for_h2, management_config, net_log);
 }
 
 bool HttpStreamFactory::Job::ShouldThrottleConnectForSpdy() const {
diff --git a/net/http/http_stream_factory_job.h b/net/http/http_stream_factory_job.h
index f1d1848..dd7236d8 100644
--- a/net/http/http_stream_factory_job.h
+++ b/net/http/http_stream_factory_job.h
@@ -159,7 +159,7 @@
       NextProto alternative_protocol,
       quic::ParsedQuicVersion quic_version,
       bool is_websocket,
-      bool enable_ip_based_pooling,
+      bool enable_ip_based_pooling_for_h2,
       std::optional<ConnectionManagementConfig> management_config,
       NetLog* net_log);
 
@@ -405,7 +405,7 @@
 
   // Enable pooling to a SpdySession with matching IP and certificate
   // even if the SpdySessionKey is different.
-  const bool enable_ip_based_pooling_;
+  const bool enable_ip_based_pooling_for_h2_;
 
   // Unowned. |this| job is owned by |delegate_|.
   const raw_ptr<Delegate> delegate_;
@@ -510,7 +510,7 @@
       url::SchemeHostPort destination,
       GURL origin_url,
       bool is_websocket,
-      bool enable_ip_based_pooling,
+      bool enable_ip_based_pooling_for_h2,
       NetLog* net_log,
       NextProto alternative_protocol,
       quic::ParsedQuicVersion quic_version,
diff --git a/net/http/http_stream_factory_job_controller.cc b/net/http/http_stream_factory_job_controller.cc
index 5bfea10..a49e20c 100644
--- a/net/http/http_stream_factory_job_controller.cc
+++ b/net/http/http_stream_factory_job_controller.cc
@@ -147,7 +147,7 @@
     const HttpRequestInfo& http_request_info,
     bool is_preconnect,
     bool is_websocket,
-    bool enable_ip_based_pooling,
+    bool enable_ip_based_pooling_for_h2,
     bool enable_alternative_services,
     bool delay_main_job_with_available_spdy_session,
     const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs)
@@ -157,7 +157,7 @@
       delegate_(delegate),
       is_preconnect_(is_preconnect),
       is_websocket_(is_websocket),
-      enable_ip_based_pooling_(enable_ip_based_pooling),
+      enable_ip_based_pooling_for_h2_(enable_ip_based_pooling_for_h2),
       enable_alternative_services_(enable_alternative_services),
       delay_main_job_with_available_spdy_session_(
           delay_main_job_with_available_spdy_session),
@@ -901,9 +901,10 @@
     std::unique_ptr<Job> preconnect_job = job_factory_->CreateJob(
         this, dns_alpn_h3_job_enabled ? PRECONNECT_DNS_ALPN_H3 : PRECONNECT,
         session_, request_info_, IDLE, proxy_info_, allowed_bad_certs_,
-        destination, origin_url_, is_websocket_, enable_ip_based_pooling_,
-        net_log_.net_log(), NextProto::kProtoUnknown,
-        quic::ParsedQuicVersion::Unsupported(), management_config_);
+        destination, origin_url_, is_websocket_,
+        enable_ip_based_pooling_for_h2_, net_log_.net_log(),
+        NextProto::kProtoUnknown, quic::ParsedQuicVersion::Unsupported(),
+        management_config_);
     // When there is an valid alternative service info, and `preconnect_job`
     // has no existing QUIC session, create a job for the alternative service.
     if (alternative_service_info_.protocol() != NextProto::kProtoUnknown &&
@@ -919,7 +920,7 @@
       main_job_ = job_factory_->CreateJob(
           this, PRECONNECT, session_, request_info_, IDLE, proxy_info_,
           allowed_bad_certs_, std::move(alternative_destination), origin_url_,
-          is_websocket_, enable_ip_based_pooling_, session_->net_log(),
+          is_websocket_, enable_ip_based_pooling_for_h2_, session_->net_log(),
           alternative_service_info_.protocol(), quic_version,
           management_config_);
     } else {
@@ -929,7 +930,7 @@
         preconnect_backup_job_ = job_factory_->CreateJob(
             this, PRECONNECT, session_, request_info_, IDLE, proxy_info_,
             allowed_bad_certs_, std::move(destination), origin_url_,
-            is_websocket_, enable_ip_based_pooling_, net_log_.net_log(),
+            is_websocket_, enable_ip_based_pooling_for_h2_, net_log_.net_log(),
             NextProto::kProtoUnknown, quic::ParsedQuicVersion::Unsupported(),
             management_config_);
       }
@@ -940,8 +941,9 @@
   main_job_ = job_factory_->CreateJob(
       this, MAIN, session_, request_info_, priority_, proxy_info_,
       allowed_bad_certs_, std::move(destination), origin_url_, is_websocket_,
-      enable_ip_based_pooling_, net_log_.net_log(), NextProto::kProtoUnknown,
-      quic::ParsedQuicVersion::Unsupported(), management_config_);
+      enable_ip_based_pooling_for_h2_, net_log_.net_log(),
+      NextProto::kProtoUnknown, quic::ParsedQuicVersion::Unsupported(),
+      management_config_);
 
   // Alternative Service can only be set for HTTPS requests while Alternative
   // Proxy is set for HTTP requests.
@@ -968,7 +970,7 @@
     alternative_job_ = job_factory_->CreateJob(
         this, ALTERNATIVE, session_, request_info_, priority_, proxy_info_,
         allowed_bad_certs_, std::move(alternative_destination), origin_url_,
-        is_websocket_, enable_ip_based_pooling_, net_log_.net_log(),
+        is_websocket_, enable_ip_based_pooling_for_h2_, net_log_.net_log(),
         alternative_service_info_.protocol(), quic_version, management_config_);
   }
 
@@ -979,7 +981,7 @@
     dns_alpn_h3_job_ = job_factory_->CreateJob(
         this, DNS_ALPN_H3, session_, request_info_, priority_, proxy_info_,
         allowed_bad_certs_, std::move(dns_alpn_h3_destination), origin_url_,
-        is_websocket_, enable_ip_based_pooling_, net_log_.net_log(),
+        is_websocket_, enable_ip_based_pooling_for_h2_, net_log_.net_log(),
         NextProto::kProtoUnknown, quic::ParsedQuicVersion::Unsupported(),
         management_config_);
   }
@@ -1542,7 +1544,7 @@
   session_->http_stream_pool()->HandleStreamRequest(
       std::exchange(request_, nullptr), std::exchange(delegate_, nullptr),
       std::move(pool_request_info), priority_, allowed_bad_certs_,
-      enable_ip_based_pooling_, enable_alternative_services_);
+      enable_ip_based_pooling_for_h2_, enable_alternative_services_);
 
   // Delete `this` later as this method is called while running DoLoop().
   TaskRunner(priority_)->PostTask(
diff --git a/net/http/http_stream_factory_job_controller.h b/net/http/http_stream_factory_job_controller.h
index d4e32b53f..d30290fc 100644
--- a/net/http/http_stream_factory_job_controller.h
+++ b/net/http/http_stream_factory_job_controller.h
@@ -42,7 +42,7 @@
                 const HttpRequestInfo& http_request_info,
                 bool is_preconnect,
                 bool is_websocket,
-                bool enable_ip_based_pooling,
+                bool enable_ip_based_pooling_for_h2,
                 bool enable_alternative_services,
                 bool delay_main_job_with_available_spdy_session,
                 const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs);
@@ -321,7 +321,8 @@
 
   // Enable pooling to a SpdySession with matching IP and certificate even if
   // the SpdySessionKey is different.
-  const bool enable_ip_based_pooling_;
+  // Note that this does nothing with QUIC.
+  const bool enable_ip_based_pooling_for_h2_;
 
   // Enable using alternative services for the request. If false, the
   // JobController will only create a |main_job_|.
diff --git a/net/http/http_stream_factory_job_controller_unittest.cc b/net/http/http_stream_factory_job_controller_unittest.cc
index da3b12e2..311cc07 100644
--- a/net/http/http_stream_factory_job_controller_unittest.cc
+++ b/net/http/http_stream_factory_job_controller_unittest.cc
@@ -352,9 +352,9 @@
     is_preconnect_ = true;
   }
 
-  void DisableIPBasedPooling() {
+  void DisableIPBasedPoolingForH2() {
     ASSERT_FALSE(session_deps_.proxy_delegate);
-    enable_ip_based_pooling_ = false;
+    enable_ip_based_pooling_for_h2_ = false;
   }
 
   void SetNotDelayMainJobWithAvailableSpdySession() {
@@ -408,7 +408,7 @@
       auto job_controller = std::make_unique<HttpStreamFactory::JobController>(
           factory_, &request_delegate_, session_.get(), &job_factory_,
           request_info, is_preconnect_, /*is_websocket=*/false,
-          enable_ip_based_pooling_, enable_alternative_services_,
+          enable_ip_based_pooling_for_h2_, enable_alternative_services_,
           delay_main_job_with_available_spdy_session_,
           /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
       job_controller_ = job_controller.get();
@@ -553,7 +553,7 @@
 
  protected:
   bool is_preconnect_ = false;
-  bool enable_ip_based_pooling_ = true;
+  bool enable_ip_based_pooling_for_h2_ = true;
   bool enable_alternative_services_ = true;
   bool delay_main_job_with_available_spdy_session_ = true;
   bool should_check_data_consumed_ = true;
@@ -791,7 +791,7 @@
     auto job_controller = std::make_unique<HttpStreamFactory::JobController>(
         factory_, &request_delegate_, session_.get(), &default_job_factory_,
         request_info, is_preconnect_, /*is_websocket=*/false,
-        enable_ip_based_pooling_, enable_alternative_services_,
+        enable_ip_based_pooling_for_h2_, enable_alternative_services_,
         delay_main_job_with_available_spdy_session_,
         /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
     auto* job_controller_ptr = job_controller.get();
@@ -2887,7 +2887,7 @@
                          request_info.network_anonymization_key,
                          request_info.secure_dns_policy,
                          /*disable_cert_verification_network_fetches=*/false),
-          /*enable_ip_based_pooling=*/false, /*is_websocket=*/false,
+          /*enable_ip_based_pooling_for_h2=*/false, /*is_websocket=*/false,
           NetLogWithSource());
   EXPECT_TRUE(spdy_session);
 
@@ -4137,7 +4137,7 @@
     auto job_controller = std::make_unique<HttpStreamFactory::JobController>(
         factory_, &request_delegate, session_.get(), &job_factory_,
         request_info, is_preconnect_, /*is_websocket=*/false,
-        enable_ip_based_pooling_, enable_alternative_services_,
+        enable_ip_based_pooling_for_h2_, enable_alternative_services_,
         delay_main_job_with_available_spdy_session_,
         /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
     auto* job_controller_ptr = job_controller.get();
@@ -4274,7 +4274,7 @@
   auto job_controller = std::make_unique<HttpStreamFactory::JobController>(
       factory_, &preconnect_request_delegate, session_.get(), &job_factory_,
       request_info, /*is_preconnect=*/true, /*is_websocket=*/false,
-      enable_ip_based_pooling_, enable_alternative_services_,
+      enable_ip_based_pooling_for_h2_, enable_alternative_services_,
       delay_main_job_with_available_spdy_session_,
       /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
   auto* job_controller_ptr = job_controller.get();
@@ -4303,7 +4303,7 @@
                          request_info.network_anonymization_key,
                          request_info.secure_dns_policy,
                          /*disable_cert_verification_network_fetches=*/false),
-          false /* enable_ip_based_pooling */, /*is_websocket=*/false,
+          false /* enable_ip_based_pooling_for_h2 */, /*is_websocket=*/false,
           NetLogWithSource());
   EXPECT_TRUE(spdy_session);
 }
@@ -4381,7 +4381,7 @@
                            request_info.network_anonymization_key,
                            request_info.secure_dns_policy,
                            /*disable_cert_verification_network_fetches=*/false),
-            /*enable_ip_based_pooling=*/false, /*is_websocket=*/false,
+            /*enable_ip_based_pooling_for_h2=*/false, /*is_websocket=*/false,
             NetLogWithSource());
     EXPECT_TRUE(spdy_session);
   }
@@ -4396,7 +4396,7 @@
       std::make_unique<HttpStreamFactory::JobController>(
           factory_, &preconnect_request_delegate, session_.get(), &job_factory_,
           other_request_info, /*is_preconnect=*/true,
-          /*is_websocket=*/false, /*enable_ip_based_pooling=*/true,
+          /*is_websocket=*/false, /*enable_ip_based_pooling_for_h2=*/true,
           enable_alternative_services_,
           delay_main_job_with_available_spdy_session_,
           /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
@@ -4417,10 +4417,10 @@
         other_request_info.secure_dns_policy,
         /*disable_cert_verification_network_fetches=*/false);
     EXPECT_FALSE(session_->spdy_session_pool()->FindAvailableSession(
-        spdy_session_key, /*enable_ip_based_pooling=*/false,
+        spdy_session_key, /*enable_ip_based_pooling_for_h2=*/false,
         /*is_websocket=*/false, NetLogWithSource()));
     EXPECT_TRUE(session_->spdy_session_pool()->FindAvailableSession(
-        spdy_session_key, /*enable_ip_based_pooling=*/true,
+        spdy_session_key, /*enable_ip_based_pooling_for_h2=*/true,
         /*is_websocket=*/false, NetLogWithSource()));
   }
 
@@ -4430,7 +4430,7 @@
     auto job_controller = std::make_unique<HttpStreamFactory::JobController>(
         factory_, &request_delegate, session_.get(), &job_factory_,
         other_request_info, /*is_preconnect=*/false,
-        /*is_websocket=*/false, /*enable_ip_based_pooling=*/true,
+        /*is_websocket=*/false, /*enable_ip_based_pooling_for_h2=*/true,
         enable_alternative_services_,
         delay_main_job_with_available_spdy_session_,
         /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
@@ -4499,7 +4499,7 @@
     auto job_controller = std::make_unique<HttpStreamFactory::JobController>(
         factory_, request_delegates[i].get(), session_.get(), &job_factory_,
         request_info, is_preconnect_, /*is_websocket=*/false,
-        enable_ip_based_pooling_, enable_alternative_services_,
+        enable_ip_based_pooling_for_h2_, enable_alternative_services_,
         delay_main_job_with_available_spdy_session_,
         /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
     auto* job_controller_ptr = job_controller.get();
@@ -4590,7 +4590,7 @@
       auto job_controller = std::make_unique<HttpStreamFactory::JobController>(
           factory_, request_delegates[i].get(), session_.get(), &job_factory_,
           request_info, is_preconnect_, /*is_websocket=*/false,
-          enable_ip_based_pooling_, enable_alternative_services_,
+          enable_ip_based_pooling_for_h2_, enable_alternative_services_,
           delay_main_job_with_available_spdy_session_,
           /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
       auto* job_controller_ptr = job_controller.get();
@@ -4671,7 +4671,7 @@
     auto job_controller = std::make_unique<HttpStreamFactory::JobController>(
         factory_, request_delegates[i].get(), session_.get(), &job_factory_,
         request_info, is_preconnect_, /*is_websocket=*/false,
-        enable_ip_based_pooling_, enable_alternative_services_,
+        enable_ip_based_pooling_for_h2_, enable_alternative_services_,
         delay_main_job_with_available_spdy_session_,
         /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
     auto* job_controller_ptr = job_controller.get();
@@ -4746,7 +4746,7 @@
     auto job_controller = std::make_unique<HttpStreamFactory::JobController>(
         factory_, request_delegates[i].get(), session_.get(), &job_factory_,
         request_info, is_preconnect_, /*is_websocket=*/false,
-        enable_ip_based_pooling_, enable_alternative_services_,
+        enable_ip_based_pooling_for_h2_, enable_alternative_services_,
         delay_main_job_with_available_spdy_session_,
         /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
     auto* job_controller_ptr = job_controller.get();
@@ -4803,7 +4803,7 @@
     auto job_controller = std::make_unique<HttpStreamFactory::JobController>(
         factory_, request_delegates[i].get(), session_.get(), &job_factory_,
         request_info, is_preconnect_, /*is_websocket=*/false,
-        enable_ip_based_pooling_, enable_alternative_services_,
+        enable_ip_based_pooling_for_h2_, enable_alternative_services_,
         delay_main_job_with_available_spdy_session_,
         /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
     auto* job_controller_ptr = job_controller.get();
@@ -4853,7 +4853,7 @@
     auto job_controller = std::make_unique<HttpStreamFactory::JobController>(
         factory_, request_delegates[i].get(), session_.get(), &job_factory_,
         request_info, is_preconnect_, /*is_websocket=*/false,
-        enable_ip_based_pooling_, enable_alternative_services_,
+        enable_ip_based_pooling_for_h2_, enable_alternative_services_,
         delay_main_job_with_available_spdy_session_,
         /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
     auto* job_controller_ptr = job_controller.get();
@@ -4918,7 +4918,7 @@
   auto job_controller = std::make_unique<HttpStreamFactory::JobController>(
       factory_, &request_delegate_, session_.get(), &default_job_factory,
       request_info, is_preconnect_, /*is_websocket=*/false,
-      enable_ip_based_pooling_, enable_alternative_services_,
+      enable_ip_based_pooling_for_h2_, enable_alternative_services_,
       delay_main_job_with_available_spdy_session_,
       /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
   auto* job_controller_ptr = job_controller.get();
@@ -4952,8 +4952,8 @@
                                             ::testing::Bool()));
 
 TEST_P(HttpStreamFactoryJobControllerMisdirectedRequestRetry,
-       DisableIPBasedPoolingAndAlternativeServices) {
-  const bool enable_ip_based_pooling = ::testing::get<0>(GetParam());
+       DisableIPBasedPoolingForH2AndAlternativeServices) {
+  const bool enable_ip_based_pooling_for_h2 = ::testing::get<0>(GetParam());
   const bool enable_alternative_services = ::testing::get<1>(GetParam());
   if (enable_alternative_services) {
     quic_data_ = std::make_unique<MockQuicData>(version_);
@@ -4971,8 +4971,8 @@
   request_info.method = "GET";
   request_info.url = GURL("https://www.google.com");
 
-  if (!enable_ip_based_pooling) {
-    DisableIPBasedPooling();
+  if (!enable_ip_based_pooling_for_h2) {
+    DisableIPBasedPoolingForH2();
   }
   if (!enable_alternative_services) {
     DisableAlternativeServices();
@@ -5027,7 +5027,7 @@
         factory_, &request_delegate_, session_.get(), &job_factory_,
         request_info_, /* is_preconnect = */ true,
         /* is_websocket = */ false,
-        /* enable_ip_based_pooling = */ true,
+        /* enable_ip_based_pooling_for_h2 = */ true,
         /* enable_alternative_services = */ true,
         /* delay_main_job_with_available_spdy_session = */ true,
         /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
@@ -5506,7 +5506,7 @@
     auto controller = std::make_unique<HttpStreamFactory::JobController>(
         factory_, request_delegate, session_.get(), &default_job_factory_,
         request_info, is_preconnect_, /*is_websocket=*/false,
-        enable_ip_based_pooling_, enable_alternative_services_,
+        enable_ip_based_pooling_for_h2_, enable_alternative_services_,
         delay_main_job_with_available_spdy_session_,
         /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
     *job_controller = controller.get();
diff --git a/net/http/http_stream_factory_test_util.cc b/net/http/http_stream_factory_test_util.cc
index c71bf614..2f12fb1 100644
--- a/net/http/http_stream_factory_test_util.cc
+++ b/net/http/http_stream_factory_test_util.cc
@@ -29,7 +29,7 @@
     NextProto alternative_protocol,
     quic::ParsedQuicVersion quic_version,
     bool is_websocket,
-    bool enable_ip_based_pooling,
+    bool enable_ip_based_pooling_for_h2,
     std::optional<ConnectionManagementConfig> management_config,
     NetLog* net_log)
     : HttpStreamFactory::Job(delegate,
@@ -44,7 +44,7 @@
                              alternative_protocol,
                              quic_version,
                              is_websocket,
-                             enable_ip_based_pooling,
+                             enable_ip_based_pooling_for_h2,
                              management_config,
                              net_log) {
   DCHECK(!is_waiting());
@@ -71,7 +71,7 @@
     url::SchemeHostPort destination,
     GURL origin_url,
     bool is_websocket,
-    bool enable_ip_based_pooling,
+    bool enable_ip_based_pooling_for_h2,
     NetLog* net_log,
     NextProto alternative_protocol = NextProto::kProtoUnknown,
     quic::ParsedQuicVersion quic_version =
@@ -81,8 +81,8 @@
   auto job = std::make_unique<MockHttpStreamFactoryJob>(
       delegate, job_type, session, request_info, priority, proxy_info,
       allowed_bad_certs, std::move(destination), origin_url,
-      alternative_protocol, quic_version, is_websocket, enable_ip_based_pooling,
-      management_config, net_log);
+      alternative_protocol, quic_version, is_websocket,
+      enable_ip_based_pooling_for_h2, management_config, net_log);
 
   // Keep raw pointer to Job but pass ownership.
   switch (job_type) {
diff --git a/net/http/http_stream_factory_test_util.h b/net/http/http_stream_factory_test_util.h
index bb4de0f..53d62f72 100644
--- a/net/http/http_stream_factory_test_util.h
+++ b/net/http/http_stream_factory_test_util.h
@@ -107,7 +107,7 @@
       NextProto alternative_protocol,
       quic::ParsedQuicVersion quic_version,
       bool is_websocket,
-      bool enable_ip_based_pooling,
+      bool enable_ip_based_pooling_for_h2,
       std::optional<ConnectionManagementConfig> management_config,
       NetLog* net_log);
 
@@ -137,7 +137,7 @@
       url::SchemeHostPort destination,
       GURL origin_url,
       bool is_websocket,
-      bool enable_ip_based_pooling,
+      bool enable_ip_based_pooling_for_h2,
       NetLog* net_log,
       NextProto alternative_protocol,
       quic::ParsedQuicVersion quic_version,
diff --git a/net/http/http_stream_factory_unittest.cc b/net/http/http_stream_factory_unittest.cc
index 01b0aa6..2857bda 100644
--- a/net/http/http_stream_factory_unittest.cc
+++ b/net/http/http_stream_factory_unittest.cc
@@ -242,18 +242,18 @@
       const HttpRequestInfo& request_info,
       RequestPriority priority,
       const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
-      bool enable_ip_based_pooling,
+      bool enable_ip_based_pooling_for_h2,
       bool enable_alternative_services) {
     CHECK(!request_);
 
     priority_ = priority;
     allowed_bad_certs_ = allowed_bad_certs;
-    enable_ip_based_pooling_ = enable_ip_based_pooling;
+    enable_ip_based_pooling_for_h2_ = enable_ip_based_pooling_for_h2;
     enable_alternative_services_ = enable_alternative_services;
 
     request_ =
         factory->RequestStream(request_info, priority, allowed_bad_certs, this,
-                               enable_ip_based_pooling,
+                               enable_ip_based_pooling_for_h2,
                                enable_alternative_services, NetLogWithSource());
   }
 
@@ -262,10 +262,10 @@
       const HttpRequestInfo& request_info,
       RequestPriority priority,
       const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
-      bool enable_ip_based_pooling,
+      bool enable_ip_based_pooling_for_h2,
       bool enable_alternative_services) {
     RequestStream(factory, request_info, priority, allowed_bad_certs,
-                  enable_ip_based_pooling, enable_alternative_services);
+                  enable_ip_based_pooling_for_h2, enable_alternative_services);
     WaitForStream();
   }
 
@@ -276,13 +276,14 @@
       const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
       WebSocketHandshakeStreamBase::CreateHelper*
           websocket_handshake_stream_create_helper,
-      bool enable_ip_based_pooling,
+      bool enable_ip_based_pooling_for_h2,
       bool enable_alternative_services) {
     CHECK(!request_);
     request_ = factory->RequestWebSocketHandshakeStream(
         request_info, priority, allowed_bad_certs, this,
-        websocket_handshake_stream_create_helper, enable_ip_based_pooling,
-        enable_alternative_services, NetLogWithSource());
+        websocket_handshake_stream_create_helper,
+        enable_ip_based_pooling_for_h2, enable_alternative_services,
+        NetLogWithSource());
   }
 
   void RequestBidirectionalStreamImpl(
@@ -290,12 +291,12 @@
       const HttpRequestInfo& request_info,
       RequestPriority priority,
       const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
-      bool enable_ip_based_pooling,
+      bool enable_ip_based_pooling_for_h2,
       bool enable_alternative_services) {
     CHECK(!request_);
     request_ = factory->RequestBidirectionalStreamImpl(
         request_info, priority, allowed_bad_certs, this,
-        enable_ip_based_pooling, enable_alternative_services,
+        enable_ip_based_pooling_for_h2, enable_alternative_services,
         NetLogWithSource());
   }
 
@@ -385,7 +386,7 @@
 
   RequestPriority priority_ = DEFAULT_PRIORITY;
   std::vector<SSLConfig::CertAndStatus> allowed_bad_certs_;
-  bool enable_ip_based_pooling_ = true;
+  bool enable_ip_based_pooling_for_h2_ = true;
   bool enable_alternative_services_ = true;
 
   bool stream_done_ = false;
@@ -1023,7 +1024,7 @@
   StreamRequester requester(session.get());
   requester.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                  DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                 /*enable_ip_based_pooling=*/true,
+                                 /*enable_ip_based_pooling_for_h2=*/true,
                                  /*enable_alternative_services=*/true);
 
   // The proxy that failed should now be known to the proxy_resolution_service
@@ -1076,7 +1077,7 @@
   StreamRequester requester(session.get());
   requester.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                  DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                 /*enable_ip_based_pooling=*/true,
+                                 /*enable_ip_based_pooling_for_h2=*/true,
                                  /*enable_alternative_services=*/true);
 
   // The stream should have failed, since the proxy server failed to
@@ -1170,7 +1171,7 @@
     StreamRequester requester(session.get());
     requester.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                    DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                   /*enable_ip_based_pooling=*/true,
+                                   /*enable_ip_based_pooling_for_h2=*/true,
                                    /*enable_alternative_services=*/true);
 
     // The proxy that failed should now be known to the
@@ -1420,7 +1421,7 @@
   StreamRequester requester1(session.get());
   requester1.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
 
   EXPECT_EQ(GetGroupCount(), 1);
@@ -1428,7 +1429,7 @@
   StreamRequester requester2(session.get());
   requester2.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
 
   EXPECT_EQ(GetGroupCount(), 1);
@@ -1437,7 +1438,7 @@
   StreamRequester requester3(session.get());
   requester3.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
 
   EXPECT_EQ(GetGroupCount(), 2);
@@ -1491,7 +1492,7 @@
   StreamRequester requester1(session.get());
   requester1.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
 
   EXPECT_EQ(SecureDnsPolicy::kAllow,
@@ -1501,7 +1502,7 @@
   StreamRequester requester2(session.get());
   requester2.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
 
   EXPECT_EQ(SecureDnsPolicy::kAllow,
@@ -1512,7 +1513,7 @@
   StreamRequester requester3(session.get());
   requester3.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
 
   EXPECT_EQ(SecureDnsPolicy::kDisable,
@@ -1540,7 +1541,7 @@
   StreamRequester requester(session.get());
   requester.RequestStream(session->http_stream_factory(), request_info,
                           DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                          /*enable_ip_based_pooling=*/true,
+                          /*enable_ip_based_pooling_for_h2=*/true,
                           /*enable_alternative_services=*/true);
 
   EXPECT_EQ(LOAD_STATE_RESOLVING_HOST, requester.request()->GetLoadState());
@@ -1571,7 +1572,7 @@
   StreamRequester requester(session.get());
   requester.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                  DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                 /*enable_ip_based_pooling=*/true,
+                                 /*enable_ip_based_pooling_for_h2=*/true,
                                  /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester.stream_done());
   ASSERT_TRUE(nullptr != requester.stream());
@@ -1617,7 +1618,7 @@
   EXPECT_EQ(0, GetSpdySessionCount(session.get()));
   requester.RequestStream(session->http_stream_factory(), request_info, LOWEST,
                           /*allowed_bad_certs=*/{},
-                          /*enable_ip_based_pooling=*/true,
+                          /*enable_ip_based_pooling_for_h2=*/true,
                           /*enable_alternative_services=*/true);
   EXPECT_FALSE(requester.stream_done());
 
@@ -1670,7 +1671,7 @@
   StreamRequester requester(session.get());
   requester.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                  DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                 /*enable_ip_based_pooling=*/true,
+                                 /*enable_ip_based_pooling_for_h2=*/true,
                                  /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester.stream_done());
   ASSERT_TRUE(nullptr != requester.stream());
@@ -1707,7 +1708,7 @@
   StreamRequester requester(session.get());
   requester.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                  DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                 /*enable_ip_based_pooling=*/true,
+                                 /*enable_ip_based_pooling_for_h2=*/true,
                                  /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester.stream_done());
   ASSERT_TRUE(nullptr != requester.stream());
@@ -1756,7 +1757,7 @@
   requester.RequestWebSocketHandshakeStream(
       session->http_stream_factory(), request_info, DEFAULT_PRIORITY,
       /*allowed_bad_certs=*/{}, &create_helper,
-      /*enable_ip_based_pooling=*/true,
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*enable_alternative_services=*/true);
   requester.WaitForStream();
   EXPECT_TRUE(requester.stream_done());
@@ -1799,7 +1800,7 @@
   requester.RequestWebSocketHandshakeStream(
       session->http_stream_factory(), request_info, DEFAULT_PRIORITY,
       /*allowed_bad_certs=*/{}, &create_helper,
-      /*enable_ip_based_pooling=*/true,
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*enable_alternative_services=*/true);
   requester.WaitForStream();
   EXPECT_TRUE(requester.stream_done());
@@ -1840,7 +1841,7 @@
   requester.RequestWebSocketHandshakeStream(
       session->http_stream_factory(), request_info, DEFAULT_PRIORITY,
       /*allowed_bad_certs=*/{}, &create_helper,
-      /*enable_ip_based_pooling=*/true,
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*enable_alternative_services=*/true);
   requester.WaitForStream();
   EXPECT_TRUE(requester.stream_done());
@@ -1891,7 +1892,7 @@
   StreamRequester requester(session.get());
   requester.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                  DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                 /*enable_ip_based_pooling=*/true,
+                                 /*enable_ip_based_pooling_for_h2=*/true,
                                  /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester.stream_done());
   EXPECT_TRUE(nullptr == requester.websocket_stream());
@@ -1943,7 +1944,7 @@
   StreamRequester requester(session.get());
   requester.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                  DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                 /*enable_ip_based_pooling=*/true,
+                                 /*enable_ip_based_pooling_for_h2=*/true,
                                  /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester.stream_done());
   EXPECT_TRUE(nullptr == requester.websocket_stream());
@@ -2016,7 +2017,7 @@
   StreamRequester requester(session.get());
   requester.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                  DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                 /*enable_ip_based_pooling=*/true,
+                                 /*enable_ip_based_pooling_for_h2=*/true,
                                  /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester.stream_done());
   EXPECT_TRUE(nullptr == requester.websocket_stream());
@@ -2112,11 +2113,11 @@
   StreamRequester requester2(session.get());
   requester1.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   requester2.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester1.stream_done());
   EXPECT_TRUE(requester2.stream_done());
@@ -2167,13 +2168,13 @@
   StreamRequester requester1(session.get());
   requester1.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
 
   StreamRequester requester2(session.get());
   requester2.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
 
   EXPECT_TRUE(requester1.stream_done());
@@ -2228,7 +2229,7 @@
   requester.RequestBidirectionalStreamImpl(
       session->http_stream_factory(), request_info, DEFAULT_PRIORITY,
       /*allowed_bad_certs=*/{},
-      /*enable_ip_based_pooling=*/true,
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*enable_alternative_services=*/true);
   requester.WaitForStream();
   EXPECT_TRUE(requester.stream_done());
@@ -2503,7 +2504,7 @@
   StreamRequester requester(session);
   requester.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                  DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                 /*enable_ip_based_pooling=*/true,
+                                 /*enable_ip_based_pooling_for_h2=*/true,
                                  /*enable_alternative_services=*/true);
 
   EXPECT_TRUE(requester.stream_done());
@@ -2650,7 +2651,7 @@
   StreamRequester requester(session);
   requester.RequestStreamAndWait(session->http_stream_factory(), request_info,
                                  DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                 /*enable_ip_based_pooling=*/true,
+                                 /*enable_ip_based_pooling_for_h2=*/true,
                                  /*enable_alternative_services=*/true);
 
   EXPECT_TRUE(requester.stream_done());
@@ -2857,7 +2858,7 @@
   requester.RequestBidirectionalStreamImpl(
       session()->http_stream_factory(), request_info, DEFAULT_PRIORITY,
       /*allowed_bad_certs=*/{},
-      /*enable_ip_based_pooling=*/true,
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*enable_alternative_services=*/true);
 
   requester.WaitForStream();
@@ -2955,7 +2956,7 @@
   requester.RequestBidirectionalStreamImpl(
       session()->http_stream_factory(), request_info, DEFAULT_PRIORITY,
       /*allowed_bad_certs=*/{},
-      /*enable_ip_based_pooling=*/true,
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*enable_alternative_services=*/true);
 
   requester.WaitForStream();
@@ -3027,7 +3028,7 @@
   requester.RequestBidirectionalStreamImpl(
       session->http_stream_factory(), request_info, DEFAULT_PRIORITY,
       /*allowed_bad_certs=*/{},
-      /*enable_ip_based_pooling=*/true,
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*enable_alternative_services=*/true);
   requester.WaitForStream();
   EXPECT_TRUE(requester.stream_done());
@@ -3100,7 +3101,7 @@
   StreamRequester requester1(session.get());
   requester1.RequestStreamAndWait(session->http_stream_factory(), request_info1,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester1.stream_done());
   EXPECT_TRUE(nullptr == requester1.websocket_stream());
@@ -3123,7 +3124,7 @@
   StreamRequester requester2(session.get());
   requester2.RequestStreamAndWait(session->http_stream_factory(), request_info2,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester2.stream_done());
   EXPECT_TRUE(nullptr == requester2.websocket_stream());
@@ -3146,7 +3147,7 @@
   StreamRequester requester3(session.get());
   requester3.RequestStreamAndWait(session->http_stream_factory(), request_info2,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester3.stream_done());
   EXPECT_TRUE(nullptr == requester3.websocket_stream());
@@ -3249,7 +3250,7 @@
   requester1.RequestStreamAndWait(session()->http_stream_factory(),
                                   request_info1, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester1.stream_done());
   EXPECT_TRUE(nullptr == requester1.websocket_stream());
@@ -3269,7 +3270,7 @@
   requester2.RequestStreamAndWait(session()->http_stream_factory(),
                                   request_info2, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester2.stream_done());
   EXPECT_TRUE(nullptr == requester2.websocket_stream());
@@ -3288,7 +3289,7 @@
   requester3.RequestStreamAndWait(session()->http_stream_factory(),
                                   request_info2, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester3.stream_done());
   EXPECT_TRUE(nullptr == requester3.websocket_stream());
@@ -3362,7 +3363,7 @@
   StreamRequester requester1(session.get());
   requester1.RequestStreamAndWait(session->http_stream_factory(), request_info1,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester1.stream_done());
   EXPECT_FALSE(requester1.websocket_stream());
@@ -3385,7 +3386,7 @@
   StreamRequester requester2(session.get());
   requester2.RequestStreamAndWait(session->http_stream_factory(), request_info2,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester2.stream_done());
   EXPECT_FALSE(requester2.websocket_stream());
@@ -3417,7 +3418,7 @@
   StreamRequester requester3(session.get());
   requester3.RequestStreamAndWait(session->http_stream_factory(), request_info3,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester3.stream_done());
   EXPECT_FALSE(requester3.websocket_stream());
@@ -3449,7 +3450,7 @@
   StreamRequester requester4(session.get());
   requester4.RequestStreamAndWait(session->http_stream_factory(), request_info2,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester4.stream_done());
   EXPECT_FALSE(requester4.websocket_stream());
@@ -3542,7 +3543,7 @@
   StreamRequester requester1(session.get());
   requester1.RequestStreamAndWait(session->http_stream_factory(), request_info1,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester1.stream_done());
   EXPECT_FALSE(requester1.websocket_stream());
@@ -3573,7 +3574,7 @@
   StreamRequester requester2(session.get());
   requester2.RequestStreamAndWait(session->http_stream_factory(), request_info2,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester2.stream_done());
   EXPECT_FALSE(requester2.websocket_stream());
@@ -3611,7 +3612,7 @@
   StreamRequester requester3(session.get());
   requester3.RequestStreamAndWait(session->http_stream_factory(), request_info3,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester3.stream_done());
   EXPECT_FALSE(requester3.websocket_stream());
@@ -3638,7 +3639,7 @@
   StreamRequester requester4(session.get());
   requester4.RequestStreamAndWait(session->http_stream_factory(), request_info4,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester4.stream_done());
   EXPECT_FALSE(requester4.websocket_stream());
@@ -3707,7 +3708,7 @@
   StreamRequester requester1(session.get());
   requester1.RequestStreamAndWait(session->http_stream_factory(), request_info1,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester1.stream_done());
   EXPECT_FALSE(requester1.websocket_stream());
@@ -3726,7 +3727,7 @@
   StreamRequester requester2(session.get());
   requester2.RequestStreamAndWait(session->http_stream_factory(), request_info2,
                                   DEFAULT_PRIORITY, /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester2.stream_done());
   EXPECT_FALSE(requester2.websocket_stream());
@@ -3746,7 +3747,7 @@
   requester3.RequestStreamAndWait(session->http_stream_factory(),
                                   request_info1_alias, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester3.stream_done());
   EXPECT_FALSE(requester3.websocket_stream());
@@ -3773,7 +3774,7 @@
   requester4.RequestStreamAndWait(session->http_stream_factory(),
                                   request_info2_alias, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester4.stream_done());
   EXPECT_FALSE(requester4.websocket_stream());
@@ -3841,7 +3842,7 @@
   requester1.RequestStreamAndWait(session->http_stream_factory(),
                                   request_info_a, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester1.stream_done());
   EXPECT_FALSE(requester1.websocket_stream());
@@ -3862,7 +3863,7 @@
   requester2.RequestStreamAndWait(session->http_stream_factory(),
                                   request_info_b, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester2.stream_done());
   EXPECT_FALSE(requester2.websocket_stream());
@@ -3890,7 +3891,7 @@
   requester3.RequestStreamAndWait(session->http_stream_factory(),
                                   request_info_c, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester3.stream_done());
   EXPECT_FALSE(requester3.websocket_stream());
@@ -3921,7 +3922,7 @@
   requester4.RequestStreamAndWait(session->http_stream_factory(),
                                   request_info_a, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester4.stream_done());
   EXPECT_FALSE(requester4.websocket_stream());
@@ -3947,7 +3948,7 @@
   requester5.RequestStreamAndWait(session->http_stream_factory(),
                                   request_info_b, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester5.stream_done());
   EXPECT_FALSE(requester5.websocket_stream());
@@ -3974,7 +3975,7 @@
   requester6.RequestStreamAndWait(session->http_stream_factory(),
                                   request_info_c, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester6.stream_done());
   EXPECT_FALSE(requester6.websocket_stream());
@@ -4068,7 +4069,7 @@
   requester1.RequestStreamAndWait(session()->http_stream_factory(),
                                   request_info_a, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester1.stream_done());
   EXPECT_FALSE(requester1.websocket_stream());
@@ -4084,7 +4085,7 @@
   requester2.RequestStreamAndWait(session()->http_stream_factory(),
                                   request_info_b, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester2.stream_done());
   EXPECT_FALSE(requester2.websocket_stream());
@@ -4102,7 +4103,7 @@
   requester3.RequestStreamAndWait(session()->http_stream_factory(),
                                   request_info_c, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester3.stream_done());
   EXPECT_FALSE(requester3.websocket_stream());
@@ -4123,7 +4124,7 @@
   requester4.RequestStreamAndWait(session()->http_stream_factory(),
                                   request_info_a, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester4.stream_done());
   EXPECT_FALSE(requester4.websocket_stream());
@@ -4140,7 +4141,7 @@
   requester5.RequestStreamAndWait(session()->http_stream_factory(),
                                   request_info_b, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester5.stream_done());
   EXPECT_FALSE(requester5.websocket_stream());
@@ -4158,7 +4159,7 @@
   requester6.RequestStreamAndWait(session()->http_stream_factory(),
                                   request_info_c, DEFAULT_PRIORITY,
                                   /*allowed_bad_certs=*/{},
-                                  /*enable_ip_based_pooling=*/true,
+                                  /*enable_ip_based_pooling_for_h2=*/true,
                                   /*enable_alternative_services=*/true);
   EXPECT_TRUE(requester6.stream_done());
   EXPECT_FALSE(requester6.websocket_stream());
diff --git a/net/http/http_stream_pool.cc b/net/http/http_stream_pool.cc
index 1f85cba..798e377 100644
--- a/net/http/http_stream_pool.cc
+++ b/net/http/http_stream_pool.cc
@@ -183,11 +183,11 @@
     HttpStreamPoolRequestInfo request_info,
     RequestPriority priority,
     const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
-    bool enable_ip_based_pooling,
+    bool enable_ip_based_pooling_for_h2,
     bool enable_alternative_services) {
   auto controller = std::make_unique<JobController>(
       this, std::move(request_info), priority, allowed_bad_certs,
-      enable_ip_based_pooling, enable_alternative_services);
+      enable_ip_based_pooling_for_h2, enable_alternative_services);
   JobController* controller_raw_ptr = controller.get();
   // Put `controller` into `job_controllers_` before calling HandleRequest() to
   // make sure `job_controllers_` always contains `controller` when
@@ -206,7 +206,7 @@
   auto controller = std::make_unique<JobController>(
       this, std::move(request_info), /*priority=*/RequestPriority::IDLE,
       /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>(),
-      /*enable_ip_based_pooling=*/true,
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*enable_alternative_services=*/true);
   JobController* controller_raw_ptr = controller.get();
   CHECK_EQ(controller_raw_ptr->respect_limits(), RespectLimits::kRespect);
@@ -529,7 +529,7 @@
 base::WeakPtr<SpdySession> HttpStreamPool::FindAvailableSpdySession(
     const HttpStreamKey& stream_key,
     const SpdySessionKey& spdy_session_key,
-    bool enable_ip_based_pooling,
+    bool enable_ip_based_pooling_for_h2,
     const NetLogWithSource& net_log) {
   if (!GURL::SchemeIsCryptographic(stream_key.destination().scheme())) {
     return nullptr;
@@ -537,8 +537,8 @@
 
   base::WeakPtr<SpdySession> spdy_session =
       http_network_session()->spdy_session_pool()->FindAvailableSession(
-          spdy_session_key, enable_ip_based_pooling, /*is_websocket=*/false,
-          net_log);
+          spdy_session_key, enable_ip_based_pooling_for_h2,
+          /*is_websocket=*/false, net_log);
   if (spdy_session) {
     CHECK(!RequiresHTTP11(stream_key.destination(),
                           stream_key.network_anonymization_key()));
diff --git a/net/http/http_stream_pool.h b/net/http/http_stream_pool.h
index 251fca2..798d999 100644
--- a/net/http/http_stream_pool.h
+++ b/net/http/http_stream_pool.h
@@ -194,7 +194,7 @@
       HttpStreamPoolRequestInfo request_info,
       RequestPriority priority,
       const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
-      bool enable_ip_based_pooling,
+      bool enable_ip_based_pooling_for_h2,
       bool enable_alternative_services);
 
   // Requests that enough connections/sessions for `num_streams` be opened.
@@ -362,7 +362,7 @@
   base::WeakPtr<SpdySession> FindAvailableSpdySession(
       const HttpStreamKey& stream_key,
       const SpdySessionKey& spdy_session_key,
-      bool enable_ip_based_pooling,
+      bool enable_ip_based_pooling_for_h2,
       const NetLogWithSource& net_log = NetLogWithSource());
 
   void OnPreconnectComplete(JobController* job_controller,
diff --git a/net/http/http_stream_pool_attempt_manager.cc b/net/http/http_stream_pool_attempt_manager.cc
index a62ce11..125eed9 100644
--- a/net/http/http_stream_pool_attempt_manager.cc
+++ b/net/http/http_stream_pool_attempt_manager.cc
@@ -221,7 +221,8 @@
               cert_and_status.cert->subject().GetDisplayName());
         }
         dict.Set("allowed_bad_certs", std::move(allowed_bad_certs_list));
-        dict.Set("enable_ip_based_pooling", job->enable_ip_based_pooling());
+        dict.Set("enable_ip_based_pooling_for_h2",
+                 job->enable_ip_based_pooling_for_h2());
         dict.Set("enable_alternative_services",
                  job->enable_alternative_services());
         dict.Set("quic_version",
@@ -563,7 +564,9 @@
   // socket count is less than or equal to the active stream socket count.
   // This behavior is for compatibility with the non-HEv3 code path. See
   // TransportClientSocketPool::RequestSockets().
-  if (num_streams <= group_->ActiveStreamSocketCount()) {
+  CHECK_GE(group_->ActiveStreamSocketCount(), slow_tcp_based_attempt_count_);
+  if (num_streams <=
+      group_->ActiveStreamSocketCount() - slow_tcp_based_attempt_count_) {
     return 0;
   }
   return PendingCountInternal(num_streams);
@@ -975,7 +978,7 @@
            static_cast<int>(tcp_based_attempts_.size()));
   dict.Set("num_slow_attempts",
            static_cast<int>(slow_tcp_based_attempt_count_));
-  dict.Set("enable_ip_based_pooling", IsIpBasedPoolingEnabled());
+  dict.Set("enable_ip_based_pooling_for_h2", IsIpBasedPoolingEnabledForH2());
   dict.Set("enable_alternative_services", IsAlternativeServiceEnabled());
   dict.Set("quic_attempt_alive", !!quic_attempt_);
   if (quic_attempt_result_.has_value()) {
@@ -1020,7 +1023,7 @@
     limit_ignoring_jobs_.emplace(job);
   }
 
-  if (!job->enable_ip_based_pooling()) {
+  if (!job->enable_ip_based_pooling_for_h2()) {
     ip_based_pooling_disabling_jobs_.emplace(job);
   }
 
@@ -1204,7 +1207,8 @@
 
 base::WeakPtr<SpdySession> HttpStreamPool::AttemptManager::
     CanUseExistingSpdySessionAfterEndpointChanges() {
-  if (!IsIpBasedPoolingEnabled() || !UsingTls() || !CanUseTcpBasedProtocols()) {
+  if (!IsIpBasedPoolingEnabledForH2() || !UsingTls() ||
+      !CanUseTcpBasedProtocols()) {
     return nullptr;
   }
 
@@ -1215,7 +1219,8 @@
 
   if (HasAvailableSpdySession()) {
     base::WeakPtr<SpdySession> spdy_session = pool()->FindAvailableSpdySession(
-        stream_key(), spdy_session_key(), IsIpBasedPoolingEnabled(), net_log());
+        stream_key(), spdy_session_key(), IsIpBasedPoolingEnabledForH2(),
+        net_log());
     CHECK(spdy_session);
     CHECK(spdy_session->IsAvailable());
     return spdy_session;
@@ -1352,7 +1357,17 @@
 }
 
 bool HttpStreamPool::AttemptManager::IsTcpBasedAttemptReady() {
-  switch (CanAttemptConnection()) {
+  CanAttemptResult can_attempt = CanAttemptConnection();
+  // TODO(crbug.com/383606724): Consider removing these trace and net log event
+  // once we figure out better endpoint selection algorithm.
+  TRACE_EVENT_INSTANT("net.stream", "AttemptManager::IsTcpBasedAttemptReady",
+                      track_, "can_attempt", can_attempt);
+  net_log_.AddEvent(
+      NetLogEventType::HTTP_STREAM_POOL_ATTEMPT_MANAGER_CAN_ATTEMPT_TCP, [&] {
+        return base::Value::Dict().Set("can_attempt",
+                                       static_cast<int>(can_attempt));
+      });
+  switch (can_attempt) {
     case CanAttemptResult::kAttempt:
       // If we ignore stream limits and the pool's limit has already reached,
       // try to close as much as possible.
@@ -1432,7 +1447,7 @@
   return limit_ignoring_jobs_.empty();
 }
 
-bool HttpStreamPool::AttemptManager::IsIpBasedPoolingEnabled() const {
+bool HttpStreamPool::AttemptManager::IsIpBasedPoolingEnabledForH2() const {
   return ip_based_pooling_disabling_jobs_.empty();
 }
 
@@ -1684,7 +1699,8 @@
 
 bool HttpStreamPool::AttemptManager::HasAvailableSpdySession() const {
   return spdy_session_pool()->HasAvailableSession(
-      spdy_session_key(), IsIpBasedPoolingEnabled(), /*is_websocket=*/false);
+      spdy_session_key(), IsIpBasedPoolingEnabledForH2(),
+      /*is_websocket=*/false);
 }
 
 void HttpStreamPool::AttemptManager::MaybeStartDraining() {
diff --git a/net/http/http_stream_pool_attempt_manager.h b/net/http/http_stream_pool_attempt_manager.h
index ebaa738..3f5fa4b4 100644
--- a/net/http/http_stream_pool_attempt_manager.h
+++ b/net/http/http_stream_pool_attempt_manager.h
@@ -368,8 +368,9 @@
   // limits.
   bool ShouldRespectLimits() const;
 
-  // Returns true only when there are no jobs that disable IP based pooling.
-  bool IsIpBasedPoolingEnabled() const;
+  // Returns true only when there are no jobs that disable IP based pooling for
+  // HTTP/2. Note that this does nothing with QUIC.
+  bool IsIpBasedPoolingEnabledForH2() const;
 
   // Returns true only when there are no jobs that disable alternative services.
   bool IsAlternativeServiceEnabled() const;
diff --git a/net/http/http_stream_pool_attempt_manager_unittest.cc b/net/http/http_stream_pool_attempt_manager_unittest.cc
index 2d9a887..936dba9 100644
--- a/net/http/http_stream_pool_attempt_manager_unittest.cc
+++ b/net/http/http_stream_pool_attempt_manager_unittest.cc
@@ -232,8 +232,9 @@
     return *this;
   }
 
-  StreamRequester& set_enable_ip_based_pooling(bool enable_ip_based_pooling) {
-    enable_ip_based_pooling_ = enable_ip_based_pooling;
+  StreamRequester& set_enable_ip_based_pooling_for_h2(
+      bool enable_ip_based_pooling_for_h2) {
+    enable_ip_based_pooling_for_h2_ = enable_ip_based_pooling_for_h2;
     return *this;
   }
 
@@ -300,7 +301,7 @@
             NetLogWithSource::Make(
                 pool.http_network_session()->net_log(),
                 NetLogSourceType::HTTP_STREAM_JOB_CONTROLLER)),
-        priority_, allowed_bad_certs_, enable_ip_based_pooling_,
+        priority_, allowed_bad_certs_, enable_ip_based_pooling_for_h2_,
         enable_alternative_services_);
     Group* group = pool.GetGroupForTesting(stream_key);
     AttemptManager* attempt_manager =
@@ -422,7 +423,7 @@
 
   std::vector<SSLConfig::CertAndStatus> allowed_bad_certs_;
 
-  bool enable_ip_based_pooling_ = true;
+  bool enable_ip_based_pooling_for_h2_ = true;
   bool enable_alternative_services_ = true;
   NextProtoSet allowed_alpns_ = NextProtoSet::All();
   int load_flags_ = 0;
@@ -547,7 +548,7 @@
     Group& group = pool().GetOrCreateGroupForTesting(stream_key);
     CHECK(!spdy_session_pool()->HasAvailableSession(
         group.spdy_session_key(),
-        /*enable_ip_based_pooling=*/true,
+        /*enable_ip_based_pooling_for_h2=*/true,
         /*is_websocket=*/false));
     auto socket = FakeStreamSocket::CreateForSpdy();
     socket->set_peer_addr(peer_addr);
@@ -2450,7 +2451,7 @@
 TEST_F(HttpStreamPoolAttemptManagerTest, SpdyAvailableSession) {
   StreamRequester requester;
   requester.set_destination("https://a.test")
-      .set_enable_ip_based_pooling(false);
+      .set_enable_ip_based_pooling_for_h2(false);
 
   CreateFakeSpdySession(requester.GetStreamKey());
   requester.RequestStream(pool());
@@ -2502,7 +2503,7 @@
     ssls.emplace_back(std::move(ssl));
 
     auto requester = std::make_unique<StreamRequester>(stream_key);
-    requester->set_enable_ip_based_pooling(false).RequestStream(pool());
+    requester->set_enable_ip_based_pooling_for_h2(false).RequestStream(pool());
     requesters.emplace_back(std::move(requester));
   }
 
@@ -2574,7 +2575,8 @@
   EXPECT_THAT(requester_https.result(), Optional(IsOk()));
   EXPECT_EQ(requester_https.negotiated_protocol(), NextProto::kProtoHTTP2);
   ASSERT_TRUE(spdy_session_pool()->HasAvailableSession(
-      stream_key.CalculateSpdySessionKey(), /*enable_ip_based_pooling=*/true,
+      stream_key.CalculateSpdySessionKey(),
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*is_websocket=*/false));
 
   // Request a stream for http (not https). The second request should use
@@ -2609,7 +2611,8 @@
       StreamKeyBuilder().set_destination(kDestinationA).Build();
   CreateFakeSpdySession(stream_key_a);
   ASSERT_TRUE(spdy_session_pool()->HasAvailableSession(
-      stream_key_a.CalculateSpdySessionKey(), /*enable_ip_based_pooling=*/true,
+      stream_key_a.CalculateSpdySessionKey(),
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*is_websocket=*/false));
 
   resolver()
@@ -2632,10 +2635,11 @@
   EXPECT_EQ(requester_b.negotiated_protocol(), NextProto::kProtoHTTP2);
   ASSERT_TRUE(spdy_session_pool()->HasAvailableSession(
       requester_b.GetStreamKey().CalculateSpdySessionKey(),
-      /*enable_ip_based_pooling=*/true,
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*is_websocket=*/false));
   ASSERT_FALSE(spdy_session_pool()->HasAvailableSession(
-      stream_key_a.CalculateSpdySessionKey(), /*enable_ip_based_pooling=*/true,
+      stream_key_a.CalculateSpdySessionKey(),
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*is_websocket=*/false));
 }
 
@@ -2897,7 +2901,7 @@
   // The session was already closed so it's not available.
   ASSERT_FALSE(spdy_session_pool()->FindAvailableSession(
       requester_b.GetStreamKey().CalculateSpdySessionKey(),
-      /*enable_ip_based_pooling=*/true,
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*is_websocket=*/false, NetLogWithSource()));
 }
 
@@ -3012,7 +3016,7 @@
 
   StreamRequester requester_b;
   requester_b.set_destination("https://example.test")
-      .set_enable_ip_based_pooling(false)
+      .set_enable_ip_based_pooling_for_h2(false)
       .RequestStream(pool());
 
   endpoint_request
@@ -3050,7 +3054,7 @@
 
   StreamRequester requester2;
   requester2.set_destination("https://example.test")
-      .set_enable_ip_based_pooling(false)
+      .set_enable_ip_based_pooling_for_h2(false)
       .RequestStream(pool());
   requester2.WaitForResult();
   EXPECT_THAT(requester2.result(), Optional(IsError(ERR_FAILED)));
@@ -3066,7 +3070,7 @@
 
   StreamRequester requester3;
   requester3.set_destination("https://example.test")
-      .set_enable_ip_based_pooling(true)
+      .set_enable_ip_based_pooling_for_h2(true)
       .RequestStream(pool());
   requester3.WaitForResult();
   EXPECT_THAT(requester3.result(), Optional(IsOk()));
@@ -3421,6 +3425,35 @@
   ASSERT_EQ(group.attempt_manager(), nullptr);
 }
 
+TEST_F(HttpStreamPoolAttemptManagerTest, PreconnectSlow) {
+  base::WeakPtr<FakeServiceEndpointRequest> endpoint_request =
+      resolver()->AddFakeRequest();
+
+  Preconnector preconnector("http://a.test");
+
+  // First attempt stalls forever.
+  SequencedSocketData data1;
+  data1.set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING));
+  socket_factory()->AddSocketDataProvider(&data1);
+  // Second attempt succeeds.
+  SequencedSocketData data2;
+  data2.set_connect_data(MockConnect(ASYNC, OK));
+  socket_factory()->AddSocketDataProvider(&data2);
+
+  int rv = preconnector.Preconnect(pool());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  endpoint_request
+      ->add_endpoint(ServiceEndpointBuilder()
+                         .add_v6("2001:db8::1")
+                         .add_v4("192.0.2.1")
+                         .endpoint())
+      .CallOnServiceEndpointRequestFinished(OK);
+
+  preconnector.WaitForResult();
+  EXPECT_THAT(*preconnector.result(), IsOk());
+}
+
 TEST_F(HttpStreamPoolAttemptManagerTest, PreconnectFail) {
   base::WeakPtr<FakeServiceEndpointRequest> endpoint_request =
       resolver()->AddFakeRequest();
@@ -3558,7 +3591,8 @@
   EXPECT_THAT(preconnector.result(), Optional(IsOk()));
   ASSERT_EQ(group.IdleStreamSocketCount(), 0u);
   ASSERT_TRUE(spdy_session_pool()->HasAvailableSession(
-      stream_key.CalculateSpdySessionKey(), /*enable_ip_based_pooling=*/true,
+      stream_key.CalculateSpdySessionKey(),
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*is_websocket=*/false));
 }
 
@@ -3601,7 +3635,8 @@
   EXPECT_THAT(preconnector.result(), Optional(IsOk()));
   ASSERT_EQ(group.IdleStreamSocketCount(), 2u);
   ASSERT_FALSE(spdy_session_pool()->HasAvailableSession(
-      stream_key.CalculateSpdySessionKey(), /*enable_ip_based_pooling=*/true,
+      stream_key.CalculateSpdySessionKey(),
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*is_websocket=*/false));
 }
 
@@ -5341,7 +5376,7 @@
 
   StreamRequester requester;
   requester.set_destination(kDefaultDestination)
-      .set_enable_ip_based_pooling(false)
+      .set_enable_ip_based_pooling_for_h2(false)
       .RequestStream(pool());
   requester.WaitForResult();
 
diff --git a/net/http/http_stream_pool_job.h b/net/http/http_stream_pool_job.h
index 8301ef6..de9867ff 100644
--- a/net/http/http_stream_pool_job.h
+++ b/net/http/http_stream_pool_job.h
@@ -50,7 +50,7 @@
         const = 0;
 
     // True when IP-based pooling is enabled.
-    virtual bool enable_ip_based_pooling() const = 0;
+    virtual bool enable_ip_based_pooling_for_h2() const = 0;
 
     // True when alternative services is enabled.
     virtual bool enable_alternative_services() const = 0;
@@ -139,8 +139,8 @@
 
   RespectLimits respect_limits() const { return delegate_->respect_limits(); }
 
-  bool enable_ip_based_pooling() const {
-    return delegate_->enable_ip_based_pooling();
+  bool enable_ip_based_pooling_for_h2() const {
+    return delegate_->enable_ip_based_pooling_for_h2();
   }
 
   bool enable_alternative_services() const {
diff --git a/net/http/http_stream_pool_job_controller.cc b/net/http/http_stream_pool_job_controller.cc
index f02d0d13..2d8c93a 100644
--- a/net/http/http_stream_pool_job_controller.cc
+++ b/net/http/http_stream_pool_job_controller.cc
@@ -103,12 +103,12 @@
     HttpStreamPoolRequestInfo request_info,
     RequestPriority priority,
     std::vector<SSLConfig::CertAndStatus> allowed_bad_certs,
-    bool enable_ip_based_pooling,
+    bool enable_ip_based_pooling_for_h2,
     bool enable_alternative_services)
     : pool_(pool),
       priority_(priority),
       allowed_bad_certs_(std::move(allowed_bad_certs)),
-      enable_ip_based_pooling_(enable_ip_based_pooling),
+      enable_ip_based_pooling_for_h2_(enable_ip_based_pooling_for_h2),
       enable_alternative_services_(enable_alternative_services),
       respect_limits_(request_info.load_flags & LOAD_IGNORE_LIMITS
                           ? RespectLimits::kIgnore
@@ -138,7 +138,8 @@
           dict.Set("alternative_destination",
                    alternative_->stream_key.destination().Serialize());
         }
-        dict.Set("enable_ip_based_pooling", enable_ip_based_pooling_);
+        dict.Set("enable_ip_based_pooling_for_h2",
+                 enable_ip_based_pooling_for_h2_);
         dict.Set("enable_alternative_services", enable_alternative_services_);
         dict.Set("respect_limits", respect_limits_ == RespectLimits::kRespect);
         return dict;
@@ -239,8 +240,9 @@
 
   SpdySessionKey spdy_session_key =
       origin_stream_key_.CalculateSpdySessionKey();
-  if (pool_->FindAvailableSpdySession(origin_stream_key_, spdy_session_key,
-                                      /*enable_ip_based_pooling=*/true)) {
+  if (pool_->FindAvailableSpdySession(
+          origin_stream_key_, spdy_session_key,
+          /*enable_ip_based_pooling_for_h2=*/true)) {
     net_log_.AddEvent(
         NetLogEventType::
             HTTP_STREAM_POOL_JOB_CONTROLLER_FOUND_EXISTING_SPDY_SESSION);
@@ -284,8 +286,8 @@
   return allowed_bad_certs_;
 }
 
-bool HttpStreamPool::JobController::enable_ip_based_pooling() const {
-  return enable_ip_based_pooling_;
+bool HttpStreamPool::JobController::enable_ip_based_pooling_for_h2() const {
+  return enable_ip_based_pooling_for_h2_;
 }
 
 bool HttpStreamPool::JobController::enable_alternative_services() const {
@@ -451,7 +453,7 @@
   SpdySessionKey spdy_session_key =
       origin_stream_key_.CalculateSpdySessionKey();
   base::WeakPtr<SpdySession> spdy_session = pool_->FindAvailableSpdySession(
-      origin_stream_key_, spdy_session_key, enable_ip_based_pooling_,
+      origin_stream_key_, spdy_session_key, enable_ip_based_pooling_for_h2_,
       stream_request_->net_log());
   if (spdy_session) {
     net_log_.AddEvent(
diff --git a/net/http/http_stream_pool_job_controller.h b/net/http/http_stream_pool_job_controller.h
index 25951b09..5a8d180 100644
--- a/net/http/http_stream_pool_job_controller.h
+++ b/net/http/http_stream_pool_job_controller.h
@@ -44,7 +44,7 @@
                 HttpStreamPoolRequestInfo request_info,
                 RequestPriority priority,
                 std::vector<SSLConfig::CertAndStatus> allowed_bad_certs,
-                bool enable_ip_based_pooling,
+                bool enable_ip_based_pooling_for_h2,
                 bool enable_alternative_services);
 
   JobController(const JobController&) = delete;
@@ -65,7 +65,7 @@
   RespectLimits respect_limits() const override;
   const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs()
       const override;
-  bool enable_ip_based_pooling() const override;
+  bool enable_ip_based_pooling_for_h2() const override;
   bool enable_alternative_services() const override;
   NextProtoSet allowed_alpns() const override;
   const ProxyInfo& proxy_info() const override;
@@ -181,7 +181,7 @@
   const raw_ptr<HttpStreamPool> pool_;
   RequestPriority priority_;
   const std::vector<SSLConfig::CertAndStatus> allowed_bad_certs_;
-  const bool enable_ip_based_pooling_;
+  const bool enable_ip_based_pooling_for_h2_;
   const bool enable_alternative_services_;
   const RespectLimits respect_limits_;
   NextProtoSet allowed_alpns_;
diff --git a/net/http/http_stream_pool_test_util.cc b/net/http/http_stream_pool_test_util.cc
index 9de9784..32b7d56 100644
--- a/net/http/http_stream_pool_test_util.cc
+++ b/net/http/http_stream_pool_test_util.cc
@@ -441,7 +441,7 @@
   return allowed_bad_certs_;
 }
 
-bool TestJobDelegate::enable_ip_based_pooling() const {
+bool TestJobDelegate::enable_ip_based_pooling_for_h2() const {
   return true;
 }
 
diff --git a/net/http/http_stream_pool_test_util.h b/net/http/http_stream_pool_test_util.h
index e5fedbc0..1f4fe94 100644
--- a/net/http/http_stream_pool_test_util.h
+++ b/net/http/http_stream_pool_test_util.h
@@ -327,7 +327,7 @@
   HttpStreamPool::RespectLimits respect_limits() const override;
   const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs()
       const override;
-  bool enable_ip_based_pooling() const override;
+  bool enable_ip_based_pooling_for_h2() const override;
   bool enable_alternative_services() const override;
   NextProtoSet allowed_alpns() const override;
   const ProxyInfo& proxy_info() const override;
diff --git a/net/http/http_stream_request_unittest.cc b/net/http/http_stream_request_unittest.cc
index d6af4db8..2010dda 100644
--- a/net/http/http_stream_request_unittest.cc
+++ b/net/http/http_stream_request_unittest.cc
@@ -52,7 +52,7 @@
       factory, &request_delegate, session.get(), &job_factory, request_info,
       /*is_preconnect=*/false,
       /*is_websocket=*/false,
-      /*enable_ip_based_pooling=*/true,
+      /*enable_ip_based_pooling_for_h2=*/true,
       /*enable_alternative_services=*/true,
       /*delay_main_job_with_available_spdy_session=*/true,
       /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h
index 3793858d..c7fe2e23 100644
--- a/net/log/net_log_event_type_list.h
+++ b/net/log/net_log_event_type_list.h
@@ -1662,6 +1662,14 @@
 //   }
 EVENT_TYPE(HTTP_STREAM_POOL_ATTEMPT_MANAGER_QUIC_ATTEMPT_COMPLETED)
 
+// Emitted when an HttpStreamPool::AttemptManager checks whether it can attempt
+// a TCP based connection. The event parameter is:
+//  {
+//     "can_attempt": <The reason why AttemptManager can or cannot make an
+//                     attempt>,
+//  }
+EVENT_TYPE(HTTP_STREAM_POOL_ATTEMPT_MANAGER_CAN_ATTEMPT_TCP)
+
 // Marks the start/end of a HttpStreamPool::AttemptManager::QuicAttempt.
 // For the BEGIN phase, the following parameters are attached:
 //   {
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index d1d991e..6960fd7d 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -477,7 +477,7 @@
     HttpNetworkSession* session = helper.session();
     base::WeakPtr<SpdySession> spdy_session =
         session->spdy_session_pool()->FindAvailableSession(
-            key, /* enable_ip_based_pooling = */ true,
+            key, /* enable_ip_based_pooling_for_h2 = */ true,
             /* is_websocket = */ false, log_);
     ASSERT_TRUE(spdy_session);
     EXPECT_EQ(0u, num_active_streams(spdy_session));
@@ -2551,8 +2551,8 @@
       /*disable_cert_verification_network_fetches=*/false);
   base::WeakPtr<SpdySession> session1 =
       helper.session()->spdy_session_pool()->FindAvailableSession(
-          key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
-          NetLogWithSource());
+          key1, true /* enable_ip_based_pooling_for_h2 */,
+          false /* is_websocket */, NetLogWithSource());
   ASSERT_TRUE(session1);
 
   // The second request uses a second connection.
@@ -2614,8 +2614,8 @@
                       /*disable_cert_verification_network_fetches=*/false);
   base::WeakPtr<SpdySession> session2 =
       helper.session()->spdy_session_pool()->FindAvailableSession(
-          key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
-          NetLogWithSource());
+          key2, true /* enable_ip_based_pooling_for_h2 */,
+          false /* is_websocket */, NetLogWithSource());
   ASSERT_TRUE(session2);
   ASSERT_TRUE(session1);
   EXPECT_NE(session1.get(), session2.get());
@@ -2657,7 +2657,7 @@
                       NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
                       /*disable_cert_verification_network_fetches=*/false);
   EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
-      key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
+      key1, true /* enable_ip_based_pooling_for_h2 */, false /* is_websocket */,
       NetLogWithSource()));
 
   // The second request uses a second connection.
@@ -2706,8 +2706,8 @@
                       /*disable_cert_verification_network_fetches=*/false);
   base::WeakPtr<SpdySession> session1 =
       helper.session()->spdy_session_pool()->FindAvailableSession(
-          key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
-          NetLogWithSource());
+          key2, true /* enable_ip_based_pooling_for_h2 */,
+          false /* is_websocket */, NetLogWithSource());
   ASSERT_TRUE(session1);
   EXPECT_EQ(key1, session1->spdy_session_key());
   // Remove the session before the second request can try to use it.
@@ -2730,8 +2730,8 @@
   // Inspect the new session.
   base::WeakPtr<SpdySession> session2 =
       helper.session()->spdy_session_pool()->FindAvailableSession(
-          key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
-          NetLogWithSource());
+          key2, true /* enable_ip_based_pooling_for_h2 */,
+          false /* is_websocket */, NetLogWithSource());
   ASSERT_TRUE(session2);
   EXPECT_EQ(key2, session2->spdy_session_key());
   helper.VerifyDataConsumed();
@@ -2772,7 +2772,7 @@
                       NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
                       /*disable_cert_verification_network_fetches=*/true);
   EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
-      key1, /*enable_ip_based_pooling=*/true, /*is_websocket=*/false,
+      key1, /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false,
       NetLogWithSource()));
 
   // There should be no session with the same key, except with
@@ -2783,7 +2783,7 @@
                       NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
                       /*disable_cert_verification_network_fetches=*/false);
   EXPECT_FALSE(helper.session()->spdy_session_pool()->FindAvailableSession(
-      key2, /*enable_ip_based_pooling=*/true, /*is_websocket=*/false,
+      key2, /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false,
       NetLogWithSource()));
 
   // Set up and run a second transaction without
@@ -2831,11 +2831,11 @@
   // There should now be two sessions, with different values of
   // `disable_cert_verification_network_fetches`.
   auto session1 = helper.session()->spdy_session_pool()->FindAvailableSession(
-      key1, /*enable_ip_based_pooling=*/true, /*is_websocket=*/false,
+      key1, /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false,
       NetLogWithSource());
   EXPECT_TRUE(session1);
   auto session2 = helper.session()->spdy_session_pool()->FindAvailableSession(
-      key2, /*enable_ip_based_pooling=*/true, /*is_websocket=*/false,
+      key2, /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false,
       NetLogWithSource());
   EXPECT_TRUE(session2);
   // Make sure the sessions are distinct.
@@ -2926,7 +2926,7 @@
                       NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
                       /*disable_cert_verification_network_fetches=*/false);
   EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
-      key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
+      key1, true /* enable_ip_based_pooling_for_h2 */, false /* is_websocket */,
       NetLogWithSource()));
 
   // Set on-demand mode for the next two requests.
@@ -3079,7 +3079,7 @@
                       SecureDnsPolicy::kAllow,
                       /*disable_cert_verification_network_fetches=*/false);
   EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
-      key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
+      key1, true /* enable_ip_based_pooling_for_h2 */, false /* is_websocket */,
       NetLogWithSource()));
   EXPECT_EQ(
       dns_aliases,
@@ -3114,14 +3114,14 @@
 
   EXPECT_EQ(1u, helper.GetSpdySessionCount());
   EXPECT_FALSE(helper.session()->spdy_session_pool()->FindAvailableSession(
-      key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
+      key1, true /* enable_ip_based_pooling_for_h2 */, false /* is_websocket */,
       NetLogWithSource()));
   EXPECT_TRUE(helper.session()
                   ->spdy_session_pool()
                   ->GetDnsAliasesForSessionKey(key1)
                   .empty());
   EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
-      key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
+      key2, true /* enable_ip_based_pooling_for_h2 */, false /* is_websocket */,
       NetLogWithSource()));
   EXPECT_EQ(
       dns_aliases,
@@ -3230,7 +3230,7 @@
                       SecureDnsPolicy::kAllow,
                       /*disable_cert_verification_network_fetches=*/false);
   EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
-      key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
+      key1, true /* enable_ip_based_pooling_for_h2 */, false /* is_websocket */,
       NetLogWithSource()));
   EXPECT_EQ(
       dns_aliases1,
@@ -3261,7 +3261,7 @@
 
   EXPECT_EQ(1u, helper.GetSpdySessionCount());
   EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
-      key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
+      key2, true /* enable_ip_based_pooling_for_h2 */, false /* is_websocket */,
       NetLogWithSource()));
   EXPECT_EQ(
       dns_aliases2,
@@ -3307,14 +3307,14 @@
 
   EXPECT_EQ(1u, helper.GetSpdySessionCount());
   EXPECT_FALSE(helper.session()->spdy_session_pool()->FindAvailableSession(
-      key2, true /* enable_ip_based_pooling */, false /* is_websocket */,
+      key2, true /* enable_ip_based_pooling_for_h2 */, false /* is_websocket */,
       NetLogWithSource()));
   EXPECT_TRUE(helper.session()
                   ->spdy_session_pool()
                   ->GetDnsAliasesForSessionKey(key2)
                   .empty());
   EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
-      key3, true /* enable_ip_based_pooling */, false /* is_websocket */,
+      key3, true /* enable_ip_based_pooling_for_h2 */, false /* is_websocket */,
       NetLogWithSource()));
   EXPECT_EQ(
       dns_aliases2,
@@ -3356,14 +3356,14 @@
 
   EXPECT_EQ(1u, helper.GetSpdySessionCount());
   EXPECT_FALSE(helper.session()->spdy_session_pool()->FindAvailableSession(
-      key1, true /* enable_ip_based_pooling */, false /* is_websocket */,
+      key1, true /* enable_ip_based_pooling_for_h2 */, false /* is_websocket */,
       NetLogWithSource()));
   EXPECT_TRUE(helper.session()
                   ->spdy_session_pool()
                   ->GetDnsAliasesForSessionKey(key1)
                   .empty());
   EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
-      key4, true /* enable_ip_based_pooling */, false /* is_websocket */,
+      key4, true /* enable_ip_based_pooling_for_h2 */, false /* is_websocket */,
       NetLogWithSource()));
   EXPECT_EQ(
       dns_aliases1,
@@ -4257,14 +4257,15 @@
                      SocketTag(), NetworkAnonymizationKey(),
                      SecureDnsPolicy::kAllow,
                      /*disable_cert_verification_network_fetches=*/false);
-  EXPECT_TRUE(
-      spdy_session_pool->HasAvailableSession(key,
-                                             /*enable_ip_based_pooling=*/true,
-                                             /*is_websocket=*/false));
+  EXPECT_TRUE(spdy_session_pool->HasAvailableSession(
+      key,
+      /*enable_ip_based_pooling_for_h2=*/true,
+      /*is_websocket=*/false));
   base::WeakPtr<SpdySession> spdy_session =
-      spdy_session_pool->FindAvailableSession(key,
-                                              /*enable_ip_based_pooling=*/true,
-                                              /*is_websocket=*/false, log_);
+      spdy_session_pool->FindAvailableSession(
+          key,
+          /*enable_ip_based_pooling_for_h2=*/true,
+          /*is_websocket=*/false, log_);
   EXPECT_TRUE(spdy_session);
 
   // Start second transaction.
@@ -4296,12 +4297,12 @@
   EXPECT_EQ("hello!", response_data);
 
   // Graceful GOAWAY was received, SpdySession should be unavailable.
-  EXPECT_FALSE(
-      spdy_session_pool->HasAvailableSession(key,
-                                             /*enable_ip_based_pooling=*/true,
-                                             /*is_websocket=*/false));
+  EXPECT_FALSE(spdy_session_pool->HasAvailableSession(
+      key,
+      /*enable_ip_based_pooling_for_h2=*/true,
+      /*is_websocket=*/false));
   spdy_session = spdy_session_pool->FindAvailableSession(
-      key, /* enable_ip_based_pooling = */ true,
+      key, /* enable_ip_based_pooling_for_h2 = */ true,
       /* is_websocket = */ false, log_);
   EXPECT_FALSE(spdy_session);
 
@@ -7043,7 +7044,7 @@
                      /*disable_cert_verification_network_fetches=*/false);
   base::WeakPtr<SpdySession> spdy_session =
       helper.session()->spdy_session_pool()->FindAvailableSession(
-          key, /* enable_ip_based_pooling = */ true,
+          key, /* enable_ip_based_pooling_for_h2 = */ true,
           /* is_websocket = */ false, log_);
   ASSERT_TRUE(spdy_session);
   EXPECT_FALSE(spdy_session->support_websocket());
@@ -7192,7 +7193,7 @@
 
   base::WeakPtr<SpdySession> spdy_session =
       helper.session()->spdy_session_pool()->FindAvailableSession(
-          key, /* enable_ip_based_pooling = */ true,
+          key, /* enable_ip_based_pooling_for_h2 = */ true,
           /* is_websocket = */ false, log_);
   ASSERT_TRUE(spdy_session);
   EXPECT_FALSE(spdy_session->support_websocket());
@@ -7272,7 +7273,7 @@
                      /*disable_cert_verification_network_fetches=*/false);
   base::WeakPtr<SpdySession> spdy_session =
       helper.session()->spdy_session_pool()->FindAvailableSession(
-          key, /* enable_ip_based_pooling = */ true,
+          key, /* enable_ip_based_pooling_for_h2 = */ true,
           /* is_websocket = */ true, log_);
   ASSERT_TRUE(spdy_session);
   EXPECT_TRUE(spdy_session->support_websocket());
@@ -7466,7 +7467,7 @@
 
   base::WeakPtr<SpdySession> spdy_session =
       helper.session()->spdy_session_pool()->FindAvailableSession(
-          key, /* enable_ip_based_pooling = */ true,
+          key, /* enable_ip_based_pooling_for_h2 = */ true,
           /* is_websocket = */ false, log_);
   ASSERT_TRUE(spdy_session);
   EXPECT_FALSE(spdy_session->support_websocket());
@@ -7580,10 +7581,10 @@
                       NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
                       /*disable_cert_verification_network_fetches=*/false);
   EXPECT_TRUE(helper.session()->spdy_session_pool()->HasAvailableSession(
-      key1, /*enable_ip_based_pooling=*/true, /*is_websocket=*/false));
+      key1, /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false));
   base::WeakPtr<SpdySession> spdy_session1 =
       helper.session()->spdy_session_pool()->FindAvailableSession(
-          key1, /* enable_ip_based_pooling = */ true,
+          key1, /* enable_ip_based_pooling_for_h2 = */ true,
           /* is_websocket = */ false, log_);
   ASSERT_TRUE(spdy_session1);
   EXPECT_TRUE(spdy_session1->support_websocket());
@@ -7598,12 +7599,12 @@
                       NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
                       /*disable_cert_verification_network_fetches=*/false);
   EXPECT_TRUE(helper.session()->spdy_session_pool()->HasAvailableSession(
-      key2, /*enable_ip_based_pooling=*/true, /*is_websocket=*/true));
+      key2, /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/true));
   EXPECT_FALSE(helper.session()->spdy_session_pool()->HasAvailableSession(
-      key2, /*enable_ip_based_pooling=*/false, /*is_websocket=*/false));
+      key2, /*enable_ip_based_pooling_for_h2=*/false, /*is_websocket=*/false));
   base::WeakPtr<SpdySession> spdy_session2 =
       helper.session()->spdy_session_pool()->FindAvailableSession(
-          key1, /* enable_ip_based_pooling = */ true,
+          key1, /* enable_ip_based_pooling_for_h2 = */ true,
           /* is_websocket = */ true, log_);
   ASSERT_TRUE(spdy_session2);
   EXPECT_EQ(spdy_session1.get(), spdy_session2.get());
@@ -7745,7 +7746,7 @@
                       /*disable_cert_verification_network_fetches=*/false);
   base::WeakPtr<SpdySession> spdy_session1 =
       helper.session()->spdy_session_pool()->FindAvailableSession(
-          key1, /* enable_ip_based_pooling = */ true,
+          key1, /* enable_ip_based_pooling_for_h2 = */ true,
           /* is_websocket = */ false, log_);
   ASSERT_TRUE(spdy_session1);
   EXPECT_TRUE(spdy_session1->support_websocket());
@@ -7762,7 +7763,7 @@
                       /*disable_cert_verification_network_fetches=*/false);
   base::WeakPtr<SpdySession> spdy_session2 =
       helper.session()->spdy_session_pool()->FindAvailableSession(
-          key1, /* enable_ip_based_pooling = */ true,
+          key1, /* enable_ip_based_pooling_for_h2 = */ true,
           /* is_websocket = */ true, log_);
   ASSERT_TRUE(spdy_session2);
   EXPECT_EQ(spdy_session1.get(), spdy_session2.get());
@@ -7910,7 +7911,7 @@
                      /*disable_cert_verification_network_fetches=*/false);
   base::WeakPtr<SpdySession> spdy_session =
       helper.session()->spdy_session_pool()->FindAvailableSession(
-          key, /* enable_ip_based_pooling = */ true,
+          key, /* enable_ip_based_pooling_for_h2 = */ true,
           /* is_websocket = */ true, log_);
   ASSERT_TRUE(spdy_session);
   EXPECT_TRUE(spdy_session->support_websocket());
@@ -8134,7 +8135,7 @@
       /*disable_cert_verification_network_fetches=*/false);
   base::WeakPtr<SpdySession> spdy_session =
       helper.session()->spdy_session_pool()->FindAvailableSession(
-          key, /* enable_ip_based_pooling = */ true,
+          key, /* enable_ip_based_pooling_for_h2 = */ true,
           /* is_websocket = */ true, log_);
   ASSERT_TRUE(spdy_session);
   EXPECT_TRUE(spdy_session->support_websocket());
diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc
index ca69150..0944e46 100644
--- a/net/spdy/spdy_proxy_client_socket_unittest.cc
+++ b/net/spdy/spdy_proxy_client_socket_unittest.cc
@@ -98,7 +98,7 @@
     const SpdySessionKey& key,
     const CommonConnectJobParams* common_connect_job_params) {
   EXPECT_FALSE(http_session->spdy_session_pool()->FindAvailableSession(
-      key, true /* enable_ip_based_pooling */, false /* is_websocket */,
+      key, true /* enable_ip_based_pooling_for_h2 */, false /* is_websocket */,
       NetLogWithSource()));
 
   auto transport_params = base::MakeRefCounted<TransportSocketParams>(
diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc
index 09afd94..c80a770 100644
--- a/net/spdy/spdy_session_pool.cc
+++ b/net/spdy/spdy_session_pool.cc
@@ -53,13 +53,13 @@
 
 SpdySessionPool::SpdySessionRequest::SpdySessionRequest(
     const SpdySessionKey& key,
-    bool enable_ip_based_pooling,
+    bool enable_ip_based_pooling_for_h2,
     bool is_websocket,
     bool is_blocking_request_for_session,
     Delegate* delegate,
     SpdySessionPool* spdy_session_pool)
     : key_(key),
-      enable_ip_based_pooling_(enable_ip_based_pooling),
+      enable_ip_based_pooling_for_h2_(enable_ip_based_pooling_for_h2),
       is_websocket_(is_websocket),
       is_blocking_request_for_session_(is_blocking_request_for_session),
       delegate_(delegate),
@@ -203,7 +203,7 @@
 
 base::WeakPtr<SpdySession> SpdySessionPool::FindAvailableSession(
     const SpdySessionKey& key,
-    bool enable_ip_based_pooling,
+    bool enable_ip_based_pooling_for_h2,
     bool is_websocket,
     const NetLogWithSource& net_log) {
   auto it = LookupAvailableSessionByKey(key);
@@ -221,7 +221,7 @@
     return it->second;
   }
 
-  if (enable_ip_based_pooling) {
+  if (enable_ip_based_pooling_for_h2) {
     UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionGet", FOUND_EXISTING_FROM_IP_POOL,
                               SPDY_SESSION_GET_MAX);
     net_log.AddEventReferencingSource(
@@ -238,7 +238,7 @@
     const SpdySessionKey& key,
     const ServiceEndpoint& service_endpoint,
     const std::set<std::string>& dns_aliases) {
-  CHECK(!HasAvailableSession(key, /*enable_ip_based_pooling=*/true,
+  CHECK(!HasAvailableSession(key, /*enable_ip_based_pooling_for_h2=*/true,
                              /*is_websocket=*/false));
   CHECK(key.socket_tag() == SocketTag());
 
@@ -252,7 +252,7 @@
 }
 
 bool SpdySessionPool::HasAvailableSession(const SpdySessionKey& key,
-                                          bool enable_ip_based_pooling,
+                                          bool enable_ip_based_pooling_for_h2,
                                           bool is_websocket) const {
   auto it = available_sessions_.find(key);
   if (it == available_sessions_.end() ||
@@ -260,12 +260,13 @@
     return false;
   }
 
-  return enable_ip_based_pooling ? true : key == it->second->spdy_session_key();
+  return enable_ip_based_pooling_for_h2 ? true
+                                        : key == it->second->spdy_session_key();
 }
 
 base::WeakPtr<SpdySession> SpdySessionPool::RequestSession(
     const SpdySessionKey& key,
-    bool enable_ip_based_pooling,
+    bool enable_ip_based_pooling_for_h2,
     bool is_websocket,
     const NetLogWithSource& net_log,
     base::RepeatingClosure on_blocking_request_destroyed_callback,
@@ -274,8 +275,8 @@
     bool* is_blocking_request_for_session) {
   DCHECK(delegate);
 
-  base::WeakPtr<SpdySession> spdy_session =
-      FindAvailableSession(key, enable_ip_based_pooling, is_websocket, net_log);
+  base::WeakPtr<SpdySession> spdy_session = FindAvailableSession(
+      key, enable_ip_based_pooling_for_h2, is_websocket, net_log);
   if (spdy_session) {
     // This value doesn't really matter, but best to always populate it, for
     // consistency.
@@ -286,7 +287,7 @@
   RequestInfoForKey* request_info = &spdy_session_request_map_[key];
   *is_blocking_request_for_session = !request_info->has_blocking_request;
   *spdy_session_request = std::make_unique<SpdySessionRequest>(
-      key, enable_ip_based_pooling, is_websocket,
+      key, enable_ip_based_pooling_for_h2, is_websocket,
       *is_blocking_request_for_session, delegate, this);
   request_info->request_set.insert(spdy_session_request->get());
 
@@ -817,8 +818,9 @@
         if ((*request)->is_websocket() && !new_session->support_websocket())
           continue;
         // Don't use IP pooled session if not allowed.
-        if (!(*request)->enable_ip_based_pooling() && is_pooled)
+        if (!(*request)->enable_ip_based_pooling_for_h2() && is_pooled) {
           continue;
+        }
         break;
       }
       if (request == request_set->end())
diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h
index 3a1f304..13aeb3f6 100644
--- a/net/spdy/spdy_session_pool.h
+++ b/net/spdy/spdy_session_pool.h
@@ -102,7 +102,7 @@
 
     // Constructor - this is called by the SpdySessionPool.
     SpdySessionRequest(const SpdySessionKey& key,
-                       bool enable_ip_based_pooling,
+                       bool enable_ip_based_pooling_for_h2,
                        bool is_websocket,
                        bool is_blocking_request_for_session,
                        Delegate* delegate,
@@ -118,7 +118,9 @@
     void OnRemovedFromPool();
 
     const SpdySessionKey& key() const { return key_; }
-    bool enable_ip_based_pooling() const { return enable_ip_based_pooling_; }
+    bool enable_ip_based_pooling_for_h2() const {
+      return enable_ip_based_pooling_for_h2_;
+    }
     bool is_websocket() const { return is_websocket_; }
     bool is_blocking_request_for_session() const {
       return is_blocking_request_for_session_;
@@ -131,7 +133,7 @@
 
    private:
     const SpdySessionKey key_;
-    const bool enable_ip_based_pooling_;
+    const bool enable_ip_based_pooling_for_h2_;
     const bool is_websocket_;
     const bool is_blocking_request_for_session_;
     const raw_ptr<Delegate> delegate_;
@@ -209,14 +211,14 @@
 
   // If there is an available session for |key|, return it.
   // Otherwise if there is a session to pool to based on IP address:
-  //   * if |enable_ip_based_pooling == true|,
+  //   * if |enable_ip_based_pooling_for_h2 == true|,
   //     then mark it as available for |key| and return it;
-  //   * if |enable_ip_based_pooling == false|,
+  //   * if |enable_ip_based_pooling_for_h2 == false|,
   //     then remove it from the available sessions, and return nullptr.
   // Otherwise return nullptr.
   base::WeakPtr<SpdySession> FindAvailableSession(
       const SpdySessionKey& key,
-      bool enable_ip_based_pooling,
+      bool enable_ip_based_pooling_for_h2,
       bool is_websocket,
       const NetLogWithSource& net_log);
 
@@ -230,9 +232,9 @@
 
   // Returns true if there is an available session for `key`. Otherwise, if
   // there is a session to pool to based on IP address, returns true if
-  // `enable_ip_based_pooling` is true. Otherwise returns false.
+  // `enable_ip_based_pooling_for_h2` is true. Otherwise returns false.
   bool HasAvailableSession(const SpdySessionKey& key,
-                           bool enable_ip_based_pooling,
+                           bool enable_ip_based_pooling_for_h2,
                            bool is_websocket) const;
 
   // Just like FindAvailableSession.
@@ -262,7 +264,7 @@
   // all requests for a session have been successfully responded to.
   base::WeakPtr<SpdySession> RequestSession(
       const SpdySessionKey& key,
-      bool enable_ip_based_pooling,
+      bool enable_ip_based_pooling_for_h2,
       bool is_websocket,
       const NetLogWithSource& net_log,
       base::RepeatingClosure on_blocking_request_destroyed_callback,
diff --git a/net/spdy/spdy_session_pool_unittest.cc b/net/spdy/spdy_session_pool_unittest.cc
index 5e56975..17dace5 100644
--- a/net/spdy/spdy_session_pool_unittest.cc
+++ b/net/spdy/spdy_session_pool_unittest.cc
@@ -132,10 +132,10 @@
     SpdySessionPool* pool,
     const SpdySessionKey& key,
     const std::vector<HostResolverEndpointResult>& endpoints,
-    bool enable_ip_based_pooling = true,
+    bool enable_ip_based_pooling_for_h2 = true,
     bool is_websocket = false) {
   // The requested session must not already exist.
-  EXPECT_FALSE(pool->FindAvailableSession(key, enable_ip_based_pooling,
+  EXPECT_FALSE(pool->FindAvailableSession(key, enable_ip_based_pooling_for_h2,
                                           is_websocket, NetLogWithSource()));
 
   // Create a request for the session. There should be no matching session
@@ -145,7 +145,7 @@
   bool is_blocking_request_for_session = false;
   SpdySessionRequestDelegate request_delegate;
   EXPECT_FALSE(pool->RequestSession(
-      key, enable_ip_based_pooling, is_websocket, NetLogWithSource(),
+      key, enable_ip_based_pooling_for_h2, is_websocket, NetLogWithSource(),
       /* on_blocking_request_destroyed_callback = */ base::RepeatingClosure(),
       &request_delegate, &request, &is_blocking_request_for_session));
   EXPECT_TRUE(request);
@@ -167,8 +167,8 @@
   // (i.e. the newly created session, if a session was created, or nullptr, if
   // one was not.)
   EXPECT_EQ(request_delegate.spdy_session(),
-            pool->RequestSession(key, enable_ip_based_pooling, is_websocket,
-                                 NetLogWithSource(),
+            pool->RequestSession(key, enable_ip_based_pooling_for_h2,
+                                 is_websocket, NetLogWithSource(),
                                  /* on_blocking_request_destroyed_callback = */
                                  base::RepeatingClosure(), &request_delegate,
                                  &request, &is_blocking_request_for_session)
@@ -183,7 +183,7 @@
 bool TryCreateAliasedSpdySession(SpdySessionPool* pool,
                                  const SpdySessionKey& key,
                                  const std::string& ip_address_list,
-                                 bool enable_ip_based_pooling = true,
+                                 bool enable_ip_based_pooling_for_h2 = true,
                                  bool is_websocket = false) {
   std::vector<IPEndPoint> ip_endpoints;
   EXPECT_THAT(ParseAddressList(ip_address_list, &ip_endpoints), IsOk());
@@ -191,8 +191,8 @@
   for (auto& ip_endpoint : ip_endpoints) {
     endpoint.ip_endpoints.emplace_back(ip_endpoint.address(), 443);
   }
-  return TryCreateAliasedSpdySession(pool, key, {endpoint},
-                                     enable_ip_based_pooling, is_websocket);
+  return TryCreateAliasedSpdySession(
+      pool, key, {endpoint}, enable_ip_based_pooling_for_h2, is_websocket);
 }
 
 // A delegate that opens a new session when it is closed.
@@ -601,7 +601,7 @@
   // |session| for the second host.
   base::WeakPtr<SpdySession> session1 =
       spdy_session_pool_->FindAvailableSession(
-          test_hosts[1].key, /* enable_ip_based_pooling = */ false,
+          test_hosts[1].key, /* enable_ip_based_pooling_for_h2 = */ false,
           /* is_websocket = */ false, NetLogWithSource());
   EXPECT_FALSE(session1);
 
@@ -648,7 +648,7 @@
   // Grab the session to host 1 and verify that it is the same session
   // we got with host 0, and that is a different from host 2's session.
   session1 = spdy_session_pool_->FindAvailableSession(
-      test_hosts[1].key, /* enable_ip_based_pooling = */ true,
+      test_hosts[1].key, /* enable_ip_based_pooling_for_h2 = */ true,
       /* is_websocket = */ false, NetLogWithSource());
   EXPECT_EQ(session.get(), session1.get());
   EXPECT_NE(session2.get(), session1.get());
@@ -772,7 +772,7 @@
       HasSpdySession(http_session_->spdy_session_pool(), test_hosts[0].key));
   EXPECT_FALSE(TryCreateAliasedSpdySession(
       spdy_session_pool_, test_hosts[1].key, test_hosts[1].iplist,
-      /* enable_ip_based_pooling = */ false));
+      /* enable_ip_based_pooling_for_h2 = */ false));
 
   http_session_->spdy_session_pool()->CloseAllSessions();
 }
@@ -839,7 +839,7 @@
 
   base::WeakPtr<SpdySession> session1 =
       spdy_session_pool_->FindAvailableSession(
-          test_hosts[1].key, /* enable_ip_based_pooling = */ true,
+          test_hosts[1].key, /* enable_ip_based_pooling_for_h2 = */ true,
           /* is_websocket = */ false,
           NetLogWithSource::Make(NetLogSourceType::NONE));
   EXPECT_EQ(session0.get(), session1.get());
@@ -939,7 +939,7 @@
                                           test_hosts[1].endpoints));
   base::WeakPtr<SpdySession> session1 =
       spdy_session_pool_->FindAvailableSession(
-          test_hosts[1].key, /*enable_ip_based_pooling=*/true,
+          test_hosts[1].key, /*enable_ip_based_pooling_for_h2=*/true,
           /*is_websocket=*/false,
           NetLogWithSource::Make(NetLogSourceType::NONE));
   EXPECT_EQ(session0.get(), session1.get());
@@ -949,7 +949,7 @@
                                           test_hosts[2].endpoints));
   base::WeakPtr<SpdySession> session2 =
       spdy_session_pool_->FindAvailableSession(
-          test_hosts[2].key, /*enable_ip_based_pooling=*/true,
+          test_hosts[2].key, /*enable_ip_based_pooling_for_h2=*/true,
           /*is_websocket=*/false,
           NetLogWithSource::Make(NetLogSourceType::NONE));
   EXPECT_EQ(session0.get(), session2.get());
@@ -1011,14 +1011,14 @@
                                           test_hosts[1].iplist));
   base::WeakPtr<SpdySession> session1 =
       spdy_session_pool_->FindAvailableSession(
-          test_hosts[1].key, /* enable_ip_based_pooling = */ true,
+          test_hosts[1].key, /* enable_ip_based_pooling_for_h2 = */ true,
           /* is_websocket = */ false, NetLogWithSource());
   EXPECT_EQ(session0.get(), session1.get());
 
   // A request to the second host should not pool to the existing connection if
   // IP based pooling is disabled.
   session1 = spdy_session_pool_->FindAvailableSession(
-      test_hosts[1].key, /* enable_ip_based_pooling = */ false,
+      test_hosts[1].key, /* enable_ip_based_pooling_for_h2 = */ false,
       /* is_websocket = */ false, NetLogWithSource());
   EXPECT_FALSE(session1);
 
@@ -1522,11 +1522,11 @@
   // SpdySessionKeys if |is_websocket| argument is set.
   EXPECT_FALSE(TryCreateAliasedSpdySession(
       spdy_session_pool_, test_hosts[0].key, test_hosts[0].iplist,
-      /* enable_ip_based_pooling = */ true,
+      /* enable_ip_based_pooling_for_h2 = */ true,
       /* is_websocket = */ true));
   EXPECT_FALSE(TryCreateAliasedSpdySession(
       spdy_session_pool_, test_hosts[1].key, test_hosts[1].iplist,
-      /* enable_ip_based_pooling = */ true,
+      /* enable_ip_based_pooling_for_h2 = */ true,
       /* is_websocket = */ true));
 
   // Start request that triggers reading the SETTINGS frame.
@@ -1549,33 +1549,33 @@
   // session with websockets enabled, and TryCreateAliasedSpdySession() should
   // now set up aliases for |session| for the second one.
   base::WeakPtr<SpdySession> result = spdy_session_pool_->FindAvailableSession(
-      test_hosts[0].key, /* enable_ip_based_pooling = */ true,
+      test_hosts[0].key, /* enable_ip_based_pooling_for_h2 = */ true,
       /* is_websocket = */ true, net_log_with_source);
   EXPECT_EQ(session.get(), result.get());
-  EXPECT_TRUE(TryCreateAliasedSpdySession(spdy_session_pool_, test_hosts[1].key,
-                                          test_hosts[1].iplist,
-                                          /* enable_ip_based_pooling = */ true,
-                                          /* is_websocket = */ true));
+  EXPECT_TRUE(TryCreateAliasedSpdySession(
+      spdy_session_pool_, test_hosts[1].key, test_hosts[1].iplist,
+      /* enable_ip_based_pooling_for_h2 = */ true,
+      /* is_websocket = */ true));
 
   // FindAvailableSession() should return |session| for either SpdySessionKeys
   // when IP based pooling is enabled.
   result = spdy_session_pool_->FindAvailableSession(
-      test_hosts[0].key, /* enable_ip_based_pooling = */ true,
+      test_hosts[0].key, /* enable_ip_based_pooling_for_h2 = */ true,
       /* is_websocket = */ true, net_log_with_source);
   EXPECT_EQ(session.get(), result.get());
   result = spdy_session_pool_->FindAvailableSession(
-      test_hosts[1].key, /* enable_ip_based_pooling = */ true,
+      test_hosts[1].key, /* enable_ip_based_pooling_for_h2 = */ true,
       /* is_websocket = */ true, net_log_with_source);
   EXPECT_EQ(session.get(), result.get());
 
   // FindAvailableSession() should only return |session| for the first
   // SpdySessionKey when IP based pooling is disabled.
   result = spdy_session_pool_->FindAvailableSession(
-      test_hosts[0].key, /* enable_ip_based_pooling = */ false,
+      test_hosts[0].key, /* enable_ip_based_pooling_for_h2 = */ false,
       /* is_websocket = */ true, net_log_with_source);
   EXPECT_EQ(session.get(), result.get());
   result = spdy_session_pool_->FindAvailableSession(
-      test_hosts[1].key, /* enable_ip_based_pooling = */ false,
+      test_hosts[1].key, /* enable_ip_based_pooling_for_h2 = */ false,
       /* is_websocket = */ true, net_log_with_source);
   EXPECT_FALSE(result);
 
@@ -1657,7 +1657,7 @@
   std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request1;
   bool is_first_request_for_session;
   EXPECT_FALSE(spdy_session_pool_->RequestSession(
-      kSessionKey, /* enable_ip_based_pooling = */ false,
+      kSessionKey, /* enable_ip_based_pooling_for_h2 = */ false,
       /* is_websocket = */ false, NetLogWithSource(),
       request_deleted_callback1.Callback(), &request_delegate1,
       &spdy_session_request1, &is_first_request_for_session));
@@ -1668,7 +1668,7 @@
   TestRequestDelegate request_delegate2;
   std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request2;
   EXPECT_FALSE(spdy_session_pool_->RequestSession(
-      kSessionKey, /* enable_ip_based_pooling = */ false,
+      kSessionKey, /* enable_ip_based_pooling_for_h2 = */ false,
       /* is_websocket = */ false, NetLogWithSource(),
       request_deleted_callback2.Callback(), &request_delegate2,
       &spdy_session_request2, &is_first_request_for_session));
@@ -1679,7 +1679,7 @@
   TestRequestDelegate request_delegate3;
   std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request3;
   EXPECT_FALSE(spdy_session_pool_->RequestSession(
-      kSessionKey, /* enable_ip_based_pooling = */ false,
+      kSessionKey, /* enable_ip_based_pooling_for_h2 = */ false,
       /* is_websocket = */ false, NetLogWithSource(),
       request_deleted_callback3.Callback(), &request_delegate3,
       &spdy_session_request3, &is_first_request_for_session));
@@ -1720,7 +1720,7 @@
   std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request1;
   bool is_first_request_for_session;
   EXPECT_FALSE(spdy_session_pool_->RequestSession(
-      kSessionKey, /* enable_ip_based_pooling = */ false,
+      kSessionKey, /* enable_ip_based_pooling_for_h2 = */ false,
       /* is_websocket = */ false, NetLogWithSource(),
       request_deleted_callback1.Callback(), &request_delegate1,
       &spdy_session_request1, &is_first_request_for_session));
@@ -1731,7 +1731,7 @@
   TestRequestDelegate request_delegate2;
   std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request2;
   EXPECT_FALSE(spdy_session_pool_->RequestSession(
-      kSessionKey, /* enable_ip_based_pooling = */ false,
+      kSessionKey, /* enable_ip_based_pooling_for_h2 = */ false,
       /* is_websocket = */ false, NetLogWithSource(),
       request_deleted_callback2.Callback(), &request_delegate2,
       &spdy_session_request2, &is_first_request_for_session));
@@ -1750,7 +1750,7 @@
         // removed.
         bool is_first_request_for_session;
         EXPECT_FALSE(spdy_session_pool_->RequestSession(
-            kSessionKey, /* enable_ip_based_pooling = */ false,
+            kSessionKey, /* enable_ip_based_pooling_for_h2 = */ false,
             /* is_websocket = */ false, NetLogWithSource(),
             request_deleted_callback3.Callback(), &request_delegate3,
             &spdy_session_request3, &is_first_request_for_session));
@@ -1758,7 +1758,7 @@
 
         // Fourth request.
         EXPECT_FALSE(spdy_session_pool_->RequestSession(
-            kSessionKey, /* enable_ip_based_pooling = */ false,
+            kSessionKey, /* enable_ip_based_pooling_for_h2 = */ false,
             /* is_websocket = */ false, NetLogWithSource(),
             request_deleted_callback4.Callback(), &request_delegate4,
             &spdy_session_request4, &is_first_request_for_session));
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
index aba34a2..08f31a5a 100644
--- a/net/spdy/spdy_session_unittest.cc
+++ b/net/spdy/spdy_session_unittest.cc
@@ -3396,18 +3396,18 @@
       ::net::CreateSpdySession(http_session_.get(), key1, NetLogWithSource());
   EXPECT_FALSE(pool->IsStalled());
   EXPECT_TRUE(http_session_->spdy_session_pool()->HasAvailableSession(
-      key1, /*enable_ip_based_pooling=*/true, /*is_websocket=*/false));
+      key1, /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false));
   EXPECT_FALSE(http_session_->spdy_session_pool()->HasAvailableSession(
-      key2, /*enable_ip_based_pooling=*/true, /*is_websocket=*/false));
+      key2, /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false));
   EXPECT_FALSE(http_session_->spdy_session_pool()->HasAvailableSession(
-      key2, /*enable_ip_based_pooling=*/false, /*is_websocket=*/false));
+      key2, /*enable_ip_based_pooling_for_h2=*/false, /*is_websocket=*/false));
 
   // Set up an alias for the idle SPDY session, increasing its ref count to 2.
   std::unique_ptr<SpdySessionPool::SpdySessionRequest> request;
   bool is_blocking_request_for_session = false;
   SpdySessionRequestDelegate request_delegate;
   EXPECT_FALSE(spdy_session_pool_->RequestSession(
-      key2, /* enable_ip_based_pooling = */ true,
+      key2, /* enable_ip_based_pooling_for_h2 = */ true,
       /* is_websocket = */ false, NetLogWithSource(),
       /* on_blocking_request_destroyed_callback = */ base::RepeatingClosure(),
       &request_delegate, &request, &is_blocking_request_for_session));
@@ -3424,17 +3424,17 @@
   // Get a session for |key2|, which should return the session created earlier.
   base::WeakPtr<SpdySession> session2 =
       spdy_session_pool_->FindAvailableSession(
-          key2, /* enable_ip_based_pooling = */ true,
+          key2, /* enable_ip_based_pooling_for_h2 = */ true,
           /* is_websocket = */ false, NetLogWithSource());
   EXPECT_TRUE(session2);
   ASSERT_EQ(session1.get(), session2.get());
   EXPECT_FALSE(pool->IsStalled());
   EXPECT_TRUE(http_session_->spdy_session_pool()->HasAvailableSession(
-      key1, /*enable_ip_based_pooling=*/true, /*is_websocket=*/false));
+      key1, /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false));
   EXPECT_TRUE(http_session_->spdy_session_pool()->HasAvailableSession(
-      key2, /*enable_ip_based_pooling=*/true, /*is_websocket=*/false));
+      key2, /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false));
   EXPECT_FALSE(http_session_->spdy_session_pool()->HasAvailableSession(
-      key2, /*enable_ip_based_pooling=*/false, /*is_websocket=*/false));
+      key2, /*enable_ip_based_pooling_for_h2=*/false, /*is_websocket=*/false));
 
   // Trying to create a new connection should cause the pool to be stalled, and
   // post a task asynchronously to try and close the session.
@@ -3462,11 +3462,11 @@
   EXPECT_FALSE(session1);
   EXPECT_FALSE(session2);
   EXPECT_FALSE(http_session_->spdy_session_pool()->HasAvailableSession(
-      key1, /*enable_ip_based_pooling=*/true, /*is_websocket=*/false));
+      key1, /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false));
   EXPECT_FALSE(http_session_->spdy_session_pool()->HasAvailableSession(
-      key2, /*enable_ip_based_pooling=*/true, /*is_websocket=*/false));
+      key2, /*enable_ip_based_pooling_for_h2=*/true, /*is_websocket=*/false));
   EXPECT_FALSE(http_session_->spdy_session_pool()->HasAvailableSession(
-      key2, /*enable_ip_based_pooling=*/false, /*is_websocket=*/false));
+      key2, /*enable_ip_based_pooling_for_h2=*/false, /*is_websocket=*/false));
 }
 
 // Tests that when a SPDY session becomes idle, it closes itself if there is
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc
index afc7ad2..b776eec3 100644
--- a/net/spdy/spdy_test_util_common.cc
+++ b/net/spdy/spdy_test_util_common.cc
@@ -433,7 +433,7 @@
 
 bool HasSpdySession(SpdySessionPool* pool, const SpdySessionKey& key) {
   return static_cast<bool>(pool->FindAvailableSession(
-      key, /* enable_ip_based_pooling = */ true,
+      key, /* enable_ip_based_pooling_for_h2 = */ true,
       /* is_websocket = */ false, NetLogWithSource()));
 }
 
@@ -443,9 +443,9 @@
     HttpNetworkSession* http_session,
     const SpdySessionKey& key,
     const NetLogWithSource& net_log,
-    bool enable_ip_based_pooling) {
+    bool enable_ip_based_pooling_for_h2) {
   EXPECT_FALSE(http_session->spdy_session_pool()->FindAvailableSession(
-      key, enable_ip_based_pooling,
+      key, enable_ip_based_pooling_for_h2,
       /*is_websocket=*/false, NetLogWithSource()));
 
   auto connection = std::make_unique<ClientSocketHandle>();
@@ -493,7 +493,7 @@
                                              const SpdySessionKey& key,
                                              const NetLogWithSource& net_log) {
   return CreateSpdySessionHelper(http_session, key, net_log,
-                                 /* enable_ip_based_pooling = */ true);
+                                 /* enable_ip_based_pooling_for_h2 = */ true);
 }
 
 base::WeakPtr<SpdySession> CreateSpdySessionWithIpBasedPoolingDisabled(
@@ -501,7 +501,7 @@
     const SpdySessionKey& key,
     const NetLogWithSource& net_log) {
   return CreateSpdySessionHelper(http_session, key, net_log,
-                                 /* enable_ip_based_pooling = */ false);
+                                 /* enable_ip_based_pooling_for_h2 = */ false);
 }
 
 namespace {
diff --git a/sandbox/policy/linux/bpf_ime_policy_linux.cc b/sandbox/policy/linux/bpf_ime_policy_linux.cc
index 6852c62..6a522ea 100644
--- a/sandbox/policy/linux/bpf_ime_policy_linux.cc
+++ b/sandbox/policy/linux/bpf_ime_policy_linux.cc
@@ -42,6 +42,10 @@
     case __NR_getrusage:
       return RestrictGetrusage();
 #endif
+#if defined(__NR_prlimit64)
+    case __NR_prlimit64:
+      return RestrictPrlimitToGetrlimit(GetPolicyPid());
+#endif
     default:
       auto* sandbox_linux = SandboxLinux::GetInstance();
       if (sandbox_linux->ShouldBrokerHandleSyscall(sysno))
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index b9152973..41debd7 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -17156,6 +17156,7 @@
                     },
                     "enable_features": [
                         "PartitionAllocSchedulerLoopQuarantine",
+                        "PartitionAllocSchedulerLoopQuarantineTaskObserverForBrowserUIThread",
                         "PartitionAllocWithAdvancedChecks",
                         "PartitionAllocZappingByFreeFlags"
                     ]
diff --git a/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc b/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc
index 0ced656..55f07b1 100644
--- a/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc
+++ b/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc
@@ -224,7 +224,6 @@
           WebSchedulerTrackedFeature::kRequestedVideoCapturePermission,
           WebSchedulerTrackedFeature::kRequestedBackForwardCacheBlockedSensors,
           WebSchedulerTrackedFeature::kRequestedBackgroundWorkPermission,
-          WebSchedulerTrackedFeature::kWebLocks,
           WebSchedulerTrackedFeature::kRequestedStorageAccessGrant,
           WebSchedulerTrackedFeature::kWebNfc,
           WebSchedulerTrackedFeature::kPrinting,
diff --git a/third_party/blink/renderer/core/scheduler_integration_tests/scheduler_affecting_features_test.cc b/third_party/blink/renderer/core/scheduler_integration_tests/scheduler_affecting_features_test.cc
index 0a56997..1e6d599 100644
--- a/third_party/blink/renderer/core/scheduler_integration_tests/scheduler_affecting_features_test.cc
+++ b/third_party/blink/renderer/core/scheduler_integration_tests/scheduler_affecting_features_test.cc
@@ -221,17 +221,4 @@
   }
 }
 
-TEST_F(SchedulingAffectingFeaturesTest, WebLocks) {
-  SimRequest main_resource("https://foo.com/", "text/html");
-  LoadURL("https://foo.com/");
-  main_resource.Complete(
-      "<script>"
-      " navigator.locks.request('my_resource', async lock => {}); "
-      "</script>");
-
-  EXPECT_THAT(
-      GetNonTrivialMainFrameFeatures(),
-      testing::UnorderedElementsAre(SchedulingPolicy::Feature::kWebLocks));
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/locks/lock.cc b/third_party/blink/renderer/modules/locks/lock.cc
index 249881f..d3ddefe 100644
--- a/third_party/blink/renderer/modules/locks/lock.cc
+++ b/third_party/blink/renderer/modules/locks/lock.cc
@@ -70,6 +70,12 @@
   lock_lifetime_.Bind(std::move(lock_lifetime), task_runner);
   handle_.set_disconnect_handler(
       WTF::BindOnce(&Lock::OnConnectionError, WrapWeakPersistent(this)));
+  feature_handle_for_scheduler_ =
+      ExecutionContext::From(script_state)
+          ->GetScheduler()
+          ->RegisterFeature(
+              blink::SchedulingPolicy::Feature::kWebLocks,
+              {blink::SchedulingPolicy::DisableBackForwardCache()});
 }
 
 Lock::~Lock() = default;
@@ -143,6 +149,8 @@
 
     // Let the lock manager know that this instance can be collected.
     manager_->OnLockReleased(this);
+
+    feature_handle_for_scheduler_.reset();
   }
 }
 
diff --git a/third_party/blink/renderer/modules/locks/lock.h b/third_party/blink/renderer/modules/locks/lock.h
index e2f4530..a5b7d5d 100644
--- a/third_party/blink/renderer/modules/locks/lock.h
+++ b/third_party/blink/renderer/modules/locks/lock.h
@@ -15,6 +15,7 @@
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
+#include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
@@ -74,6 +75,9 @@
   // stop artificially keeping this instance alive. It is necessary in the
   // case where the resolver's promise could potentially be GC'd.
   Member<LockManager> manager_;
+
+  FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle
+      feature_handle_for_scheduler_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/locks/lock_manager.cc b/third_party/blink/renderer/modules/locks/lock_manager.cc
index 0e7adeb..b76af0c 100644
--- a/third_party/blink/renderer/modules/locks/lock_manager.cc
+++ b/third_party/blink/renderer/modules/locks/lock_manager.cc
@@ -296,10 +296,6 @@
   ExecutionContext* context = ExecutionContext::From(script_state);
   DCHECK(context->IsContextThread());
 
-  context->GetScheduler()->RegisterStickyFeature(
-      blink::SchedulingPolicy::Feature::kWebLocks,
-      {blink::SchedulingPolicy::DisableBackForwardCache()});
-
   // 5. If origin is an opaque origin, then reject promise with a
   // "SecurityError" DOMException.
   //
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 4173c5bf8..146c1ee 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -7922,13 +7922,6 @@
 external/wpt/resource-timing/tentative/script-initiated.html [ Failure Timeout ]
 external/wpt/resource-timing/tentative/stylesheet-initiated.html [ Failure Timeout ]
 
-# Until ServiceWorkerStaticRouterTimingInfo is unflagged, the tests run in virtual tests.
-crbug.com/1371756 [ Debug ] external/wpt/service-workers/service-worker/tentative/static-router/* [ Failure ]
-crbug.com/1371756 [ Release ] external/wpt/service-workers/service-worker/tentative/static-router/* [ Failure ]
-crbug.com/1371756 virtual/static-routing-api/external/wpt/service-workers/service-worker/tentative/static-router/* [ Pass ]
-crbug.com/1371756 http/tests/inspector-protocol/service-worker/tentative/static-router/* [ Failure ]
-crbug.com/1371756 virtual/static-routing-api/http/tests/inspector-protocol/service-worker/tentative/static-router/* [ Pass ]
-
 # Sheriff 2023-07-13
 crbug.com/1404855 virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile.html [ Failure Pass ]
 
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index c0b8dc21..b44c3a6 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -4467,27 +4467,6 @@
     "expires": "never"
   },
   {
-    "prefix": "static-routing-api",
-    "platforms": [
-      "Linux",
-      "Mac",
-      "Win"
-    ],
-    "bases": [
-      "external/wpt/service-workers/service-worker/tentative/static-router",
-      "http/tests/inspector-protocol/service-worker/tentative/static-router"
-    ],
-    "args": [
-      "--enable-features=ServiceWorkerStaticRouterTimingInfo"
-    ],
-    "expires": "Dec 5, 2025",
-    "owners": [
-      "suzukikeita@chromium.org",
-      "yyanagisawa@chromium.org",
-      "sisidovski@chromium.org"
-    ]
-  },
-  {
     "prefix": "enable-shared-worker-bfcache",
     "owners": ["annasato@chromium.org"],
     "platforms": ["Mac", "Win", "Linux"],
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-lock.https.tentative.window.js b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-lock.https.tentative.window.js
index 46d8752..51a44db1 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-lock.https.tentative.window.js
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-lock.https.tentative.window.js
@@ -21,6 +21,7 @@
     return new Promise((resolve) => {
       navigator.locks.request('resource', () => {
         resolve(42);
+        return new Promise(() => {});
       });
     })
   });
diff --git a/third_party/blink/web_tests/external/wpt/web-locks/bfcache/abort.tentative.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-locks/bfcache/abort.tentative.https-expected.txt
deleted file mode 100644
index 403e845..0000000
--- a/third_party/blink/web_tests/external/wpt/web-locks/bfcache/abort.tentative.https-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This is a testharness.js-based test.
-[PRECONDITION_FAILED] An immediately aborted lock on main thread should not prevent bfcache
-  Could have been BFCached but actually wasn't
-[PRECONDITION_FAILED] An immediately aborted lock on a worker should not prevent bfcache
-  Could have been BFCached but actually wasn't
-[PRECONDITION_FAILED] An immediately aborted lock on a nested worker should not prevent bfcache
-  Could have been BFCached but actually wasn't
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/web-locks/bfcache/release.tentative.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-locks/bfcache/release.tentative.https-expected.txt
deleted file mode 100644
index e6c69c6..0000000
--- a/third_party/blink/web_tests/external/wpt/web-locks/bfcache/release.tentative.https-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This is a testharness.js-based test.
-[PRECONDITION_FAILED] A released lock on the main thread should not prevent bfcache
-  Could have been BFCached but actually wasn't
-[PRECONDITION_FAILED] A released lock on a worker should not prevent bfcache
-  Could have been BFCached but actually wasn't
-[PRECONDITION_FAILED] A released lock on a nested worker should not prevent bfcache
-  Could have been BFCached but actually wasn't
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/bfcache/report-back-forward-cache-status-details-captured-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/bfcache/report-back-forward-cache-status-details-captured-expected.txt
index e5f148f..eaca710 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/bfcache/report-back-forward-cache-status-details-captured-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/bfcache/report-back-forward-cache-status-details-captured-expected.txt
@@ -4,18 +4,6 @@
     loaderId : <string>
     notRestoredExplanations : [
         [0] : {
-            details : [
-                [0] : {
-                    columnNumber : 22
-                    lineNumber : 3
-                    url : https://devtools.test:8443/inspector-protocol/bfcache/resources/blocking-feature.js
-                }
-                [1] : {
-                    columnNumber : 22
-                    lineNumber : 3
-                    url : https://devtools.test:8443/inspector-protocol/bfcache/resources/blocking-feature.js
-                }
-            ]
             reason : WebLocks
             type : SupportPending
         }
@@ -25,18 +13,6 @@
         ]
         explanations : [
             [0] : {
-                details : [
-                    [0] : {
-                        columnNumber : 22
-                        lineNumber : 3
-                        url : https://devtools.test:8443/inspector-protocol/bfcache/resources/blocking-feature.js
-                    }
-                    [1] : {
-                        columnNumber : 22
-                        lineNumber : 3
-                        url : https://devtools.test:8443/inspector-protocol/bfcache/resources/blocking-feature.js
-                    }
-                ]
                 reason : WebLocks
                 type : SupportPending
             }
diff --git a/third_party/blink/web_tests/platform/mac/virtual/static-routing-api/external/wpt/service-workers/service-worker/tentative/static-router/static-router-resource-timing.https-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/static-routing-api/external/wpt/service-workers/service-worker/tentative/static-router/static-router-resource-timing.https-expected.txt
deleted file mode 100644
index 5b37deb..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/static-routing-api/external/wpt/service-workers/service-worker/tentative/static-router/static-router-resource-timing.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-All subtests passed and are omitted for brevity.
-See https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/writing_web_tests.md#Text-Test-Baselines for details.
-Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/virtual/static-routing-api/README.md b/third_party/blink/web_tests/virtual/static-routing-api/README.md
deleted file mode 100644
index de1b3db..0000000
--- a/third_party/blink/web_tests/virtual/static-routing-api/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-A virtual test suite for ServiceWorker Static Routing API.
-See crbug.com/1371756
diff --git a/third_party/dawn b/third_party/dawn
index 3de4294..0b09592 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit 3de4294640795796e47ab8e90dcb2c43dde62273
+Subproject commit 0b095928b31253ffc9684e460e08cc5710c2c21c
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index 138048f..41b0772 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit 138048fff68bb9b2f9cf114c3f3b282b789d46f1
+Subproject commit 41b0772c9f6c8fa7a57badb667e49126925806df
diff --git a/third_party/skia b/third_party/skia
index 64e37e1a..39c70f8 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 64e37e1ad12643dac64278b85b18d67ecb80642f
+Subproject commit 39c70f883c0eb62a51a0747d3dd0df4666014ea2
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps
index ce23c00..3678a87 160000
--- a/third_party/vulkan-deps
+++ b/third_party/vulkan-deps
@@ -1 +1 @@
-Subproject commit ce23c0071ce2cbf33c8eb1a4bcaebb548d6ecc3b
+Subproject commit 3678a87313f1434831df0ba2867c060388c2fbe2
diff --git a/third_party/vulkan-validation-layers/src b/third_party/vulkan-validation-layers/src
index 3493fc8..a11139a 160000
--- a/third_party/vulkan-validation-layers/src
+++ b/third_party/vulkan-validation-layers/src
@@ -1 +1 @@
-Subproject commit 3493fc8be4f99acf3b685bc2b9733b95d8f51a7b
+Subproject commit a11139aca558fdb4fe6332ffd4ba213d48317db6
diff --git a/third_party/webrtc b/third_party/webrtc
index 2fcc3b7..9bd6475 160000
--- a/third_party/webrtc
+++ b/third_party/webrtc
@@ -1 +1 @@
-Subproject commit 2fcc3b79ac702738ba22441d4a55c2e8f90c787c
+Subproject commit 9bd64751d9b3b35a820cb72c9029993e218146a1
diff --git a/tools/metrics/histograms/metadata/chromeos/histograms.xml b/tools/metrics/histograms/metadata/chromeos/histograms.xml
index 06a3949..b0e47a9 100644
--- a/tools/metrics/histograms/metadata/chromeos/histograms.xml
+++ b/tools/metrics/histograms/metadata/chromeos/histograms.xml
@@ -2608,7 +2608,7 @@
 </histogram>
 
 <histogram name="ChromeOS.LanguagePacks.GetPackState.LanguageCode"
-    enum="LanguagePackLanguageCodes" expires_after="2025-09-01">
+    enum="LanguagePackLanguageCodes" expires_after="2026-01-04">
   <owner>mlcui@google.com</owner>
   <owner>dvallet@chromium.org</owner>
   <owner>tranbaoduy@chromium.org</owner>
@@ -2621,7 +2621,7 @@
 </histogram>
 
 <histogram name="ChromeOS.LanguagePacks.InstallBasePack.FeatureId"
-    enum="LanguagePackFeatureIds" expires_after="2025-09-01">
+    enum="LanguagePackFeatureIds" expires_after="2026-01-04">
   <owner>mlcui@google.com</owner>
   <owner>dvallet@chromium.org</owner>
   <owner>tranbaoduy@chromium.org</owner>
@@ -2647,7 +2647,7 @@
 </histogram>
 
 <histogram name="ChromeOS.LanguagePacks.InstallError.Handwriting"
-    enum="LanguagePackDlcErrorType" expires_after="2025-09-01">
+    enum="LanguagePackDlcErrorType" expires_after="2026-01-04">
   <owner>mlcui@google.com</owner>
   <owner>dvallet@chromium.org</owner>
   <owner>tranbaoduy@chromium.org</owner>
@@ -2659,7 +2659,7 @@
 </histogram>
 
 <histogram name="ChromeOS.LanguagePacks.InstallError.Tts"
-    enum="LanguagePackDlcErrorType" expires_after="2025-09-01">
+    enum="LanguagePackDlcErrorType" expires_after="2026-01-04">
   <owner>mlcui@google.com</owner>
   <owner>dvallet@chromium.org</owner>
   <owner>tranbaoduy@chromium.org</owner>
@@ -2683,7 +2683,7 @@
 </histogram>
 
 <histogram name="ChromeOS.LanguagePacks.Oobe.ValidLocale" enum="BooleanSuccess"
-    expires_after="2025-09-01">
+    expires_after="2026-01-04">
   <owner>mlcui@google.com</owner>
   <owner>dvallet@chromium.org</owner>
   <owner>tranbaoduy@chromium.org</owner>
@@ -2694,7 +2694,7 @@
 </histogram>
 
 <histogram name="ChromeOS.LanguagePacks.UninstallComplete.Success"
-    enum="BooleanSuccess" expires_after="2025-09-01">
+    enum="BooleanSuccess" expires_after="2026-01-04">
   <owner>mlcui@google.com</owner>
   <owner>dvallet@chromium.org</owner>
   <owner>tranbaoduy@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/cros_ml/histograms.xml b/tools/metrics/histograms/metadata/cros_ml/histograms.xml
index c8d97a8..1e8eca5 100644
--- a/tools/metrics/histograms/metadata/cros_ml/histograms.xml
+++ b/tools/metrics/histograms/metadata/cros_ml/histograms.xml
@@ -106,7 +106,7 @@
 </histogram>
 
 <histogram name="MachineLearningService.HandwritingModel.Recognize.Event"
-    enum="Boolean" expires_after="2025-09-07">
+    enum="Boolean" expires_after="2026-02-01">
   <owner>amoylan@chromium.org</owner>
   <owner>alanlxl@chromium.org</owner>
   <summary>
@@ -163,7 +163,7 @@
 </histogram>
 
 <histogram name="MachineLearningService.MlCore.DlcBeginInstallDlcServiceError"
-    enum="MachineLearningServiceDlcErrorCode" expires_after="2025-09-09">
+    enum="MachineLearningServiceDlcErrorCode" expires_after="2026-02-01">
   <owner>amoylan@chromium.org</owner>
   <owner>chenjih@google.com</owner>
   <owner>nbowe@chromium.org</owner>
@@ -175,7 +175,7 @@
 
 <histogram name="MachineLearningService.MlCore.DlcBeginInstallResult"
     enum="MachineLearningServiceDlcBeginInstallResult"
-    expires_after="2025-09-09">
+    expires_after="2026-02-01">
   <owner>amoylan@chromium.org</owner>
   <owner>chenjih@google.com</owner>
   <owner>nbowe@chromium.org</owner>
@@ -187,7 +187,7 @@
 </histogram>
 
 <histogram name="MachineLearningService.MlCore.DlcFinalInstallDlcServiceError"
-    enum="MachineLearningServiceDlcErrorCode" expires_after="2025-09-09">
+    enum="MachineLearningServiceDlcErrorCode" expires_after="2026-02-01">
   <owner>amoylan@chromium.org</owner>
   <owner>chenjih@google.com</owner>
   <owner>nbowe@chromium.org</owner>
@@ -213,7 +213,7 @@
 </histogram>
 
 <histogram name="MachineLearningService.MlCore.DlcInstallAttemptCount"
-    units="attempts" expires_after="2025-09-09">
+    units="attempts" expires_after="2026-02-01">
   <owner>amoylan@chromium.org</owner>
   <owner>chenjih@google.com</owner>
   <owner>nbowe@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/navigation/enums.xml b/tools/metrics/histograms/metadata/navigation/enums.xml
index 38fe902..8f3f07e 100644
--- a/tools/metrics/histograms/metadata/navigation/enums.xml
+++ b/tools/metrics/histograms/metadata/navigation/enums.xml
@@ -516,6 +516,7 @@
   <int value="4" label="kNoRestart"/>
   <int value="5" label="kTooManyRestart"/>
   <int value="6" label="kSendingErrorAborted"/>
+  <int value="7" label="kDuringExclusiveTask"/>
 </enum>
 
 <!-- LINT.ThenChange(//content/browser/loader/navigation_url_loader_impl.cc:OnAcceptCHFrameReceivedReturnLocation) -->
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index d929708d..045060f 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -3544,11 +3544,14 @@
 
     Note that this metric only records where PreloadingTriggerType is
     SpeculationRule and SpeculationRuleFromIsolatedWorld.
+
+    See https://crbug.com/40287486 for the history of the histogram changes.
   </summary>
   <token key="PreloadingTriggerType" variants="PreloadingTriggerType"/>
   <token key="EagernessCategory">
     <variant name=".Conservative"/>
-    <variant name=".Immediate"/>
+    <variant name=".Eager2"/>
+    <variant name=".Immediate2"/>
     <variant name=".Moderate"/>
   </token>
 </histogram>