diff --git a/DEPS b/DEPS
index e7aa029..6ac9cfc 100644
--- a/DEPS
+++ b/DEPS
@@ -224,7 +224,7 @@
   # luci-go CIPD package version.
   # Make sure the revision is uploaded by infra-packagers builder.
   # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console
-  'luci_go': 'git_revision:dbbe363b4b1aa09520e53ccdd2d52cb661875e53',
+  'luci_go': 'git_revision:94ce62005f7d368ce9e36897e15bb570cf0d0027',
 
   # This can be overridden, e.g. with custom_vars, to build clang from HEAD
   # instead of downloading the prebuilt pinned revision.
@@ -276,19 +276,19 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'src_internal_revision': 'ef593bebcf9e5a9d111c4f12d0732bf1366ca4b7',
+  'src_internal_revision': 'f367c8fba0bcc44119ac34aa2e11dd2326780db6',
   # 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': '7fc6934b20348e6609552918b9d09da0d6f03457',
+  'skia_revision': '804042d752991d6753dd17f8585d6f8fe951492f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '27d5ca8ed62889fc9974afc2fd89c078582d5dd4',
+  'v8_revision': '99d615b4cef42ad9a32639547e8ac4bd7db462e5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'e72cc71b28a13ec0dcd9791bc2467f55482afa35',
+  'angle_revision': '1c096a8589802f2cdc12cd423a1b6f248fc930b0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -296,11 +296,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'bea10144d15d4f9f55d78095dcbf931c3d3b2813',
+  'pdfium_revision': 'b69783fd189976dd4625c7dcd9c07921b94d4a3c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': 'f49081b4ef4e99bae452e05170d8433807bd70e9',
+  'boringssl_revision': '59fc5189630ab1409555647f361ece64930a50ca',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
@@ -328,7 +328,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': '59320b2d3c2584ac01914ed0deff64bcc8fb23b2',
+  'freetype_revision': '38272bf85341348eb0a5162ba4e1c95d370f9bce',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -348,15 +348,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '452b85ea51998d34386f3b7f8bd711ba12e5d4b7',
+  'catapult_revision': 'abd0e1e8ccd7f38681b8c9503bbf4c14220c86f3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling chromium_variations
   # and whatever else without interference from each other.
-  'chromium_variations_revision': '57ea908f6afb7ef24fc1d28158837173a641617d',
+  'chromium_variations_revision': '75345f6fdba14f81b63ccf0530c6fb5adfc9a103',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
-  'crossbench_revision': 'ed3404ed0b31ef20837f60d2aef1e405284e9549',
+  'crossbench_revision': 'cdb37eabb31cf3b1723a1692b9762158f197730a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -372,7 +372,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': '6551e43966d7dd4d085ca6c0fc05a9ef2f3f4176',
+  'devtools_frontend_revision': '7d0851a8ce15f96e59c8c25fd2b5db32b0475d3d',
   # 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.
@@ -396,7 +396,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': 'afc9c139de7ea3a911171da83ac6922a0089fe34',
+  'dawn_revision': 'eaeba81b24c7b6e0af1b621c3a3479bfb52a1fab',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -468,7 +468,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.
-  'libcxxabi_revision':    '574b92bc1d7aa586ed30e4e9923041d1ec495017',
+  'libcxxabi_revision':    '77e59bec0fb93d9733378e1b6188bae0efdbc32e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -496,7 +496,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling llvm-libc
   # and whatever else without interference from each other.
-  'llvm_libc_revision':    'c8307c52cdf40133e725a3d0912e2fa60ef014b3',
+  'llvm_libc_revision':    '09341dae519a08cbb4b0c58f5409b722073d2eff',
 
   # If you change this, also update the libc++ revision in
   # //buildtools/deps_revisions.gni.
@@ -1304,16 +1304,16 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '5c28d3db4b56fc58531352e6cb59a7c8db2db9e3',
+    '94e9a17ca9d53b1cd11478b59a5185931ca5d547',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + 'ffa936be041b042d683f68b68ec4f141133530e2',
+    'url': Var('chromium_git') + '/website.git' + '@' + '31a2f432dc14e60054e2a361f4fa16ffff65e01b',
   },
 
   'src/ios/third_party/earl_grey2/src': {
-      'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + '598d8e856bc259d9632cd26e944d46d721c43071',
+      'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + '2add385c1c502920dd753dfb1fbd830b194f7809',
       'condition': 'checkout_ios',
   },
 
@@ -1567,7 +1567,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/manifest_merger',
-               'version': 'gsCtvMuqN-QovWEu4yfq_-E0wb0sL2kbuqtNEODHfFkC',
+               'version': 'X4iLz22sYpi8ovi3X8Iv6PXgOcy2934mOa16hL5-w2gC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -1799,7 +1799,7 @@
 
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'cbead190e5a4badb427fda83c7a57868b634511e',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'f548b21cd3554d013ac0bc53a6cb1ae0de79e2f8',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -2301,7 +2301,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '6361af291ce8ffd1f992fec3f44483c00bba124e',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '5bf4e2a65d76d5a603ff175222d1513f71d28a0b',
 
   'src/base/tracing/test/data': {
     'bucket': 'perfetto',
@@ -2483,7 +2483,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/r8',
-              'version': '4GP31XSTv8hw3F8OO6XHx00UfLiyEz2CDY9jcjJa9XUC',
+              'version': 'q_wvk54XItTBlBNQMHkS4NRMp-tapPW97M292KTXHrsC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -2604,7 +2604,7 @@
     Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + 'c036420683f672d685e27415de0a5f5e85bdc23f',
 
   'src/third_party/tflite/src':
-    Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + '3ed58a749e37e7e45f1771e9c60f0fffbf139d4c',
+    Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + 'b25df276c8e912c22f57263ffcae6ca8f4c64342',
 
   'src/third_party/turbine/cipd': {
       'packages': [
@@ -2669,7 +2669,7 @@
     Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'),
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '021cf5ac3ef6c5ffd8b65c7365d0f6d7ff456b9c',
+    Var('webrtc_git') + '/src.git' + '@' + '6ef206aa1a92ec09f936105bc19f50ece0ea297b',
 
   # 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.
@@ -2784,7 +2784,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/eche_app/app',
-        'version': 'qZm-7Wud-fUyBPomEkj7og51mxBNC6y4LN1irXirYgAC',
+        'version': 'LmlIDNgYeKOXhaOkrf0-yFz8fZLBqPf7FU5jLlEUTjQC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -2795,7 +2795,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/boca_app/app',
-        'version': 'qB1LRkPoZ0zFdHYSsEIRxoPCPPfdRGZmDCvkoroKAo4C',
+        'version': 'tN-mkAbmQKMdLFpJju9zZmLplu3YlIZ4lEpntY6yXPsC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -2850,7 +2850,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'cRbLg5Udg59tUE6QxvFlY96rPtmGmUbJQBPCiklZfJgC',
+        'version': 'ptGzYhmFxB58lMRbbSNUWnnNsZK0UO9kuJ3Nfjt0XIwC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -4173,7 +4173,7 @@
 
   'src/chromeos/assistant/internal': {
       'url': Var('chrome_git') + '/chrome/assistant.git' + '@' +
-        '4a629f07bb5192d38397131cbbec303d81ac1179',
+        '366dc486f8f18d097f22acb469b8eab41b14c9ad',
       'condition': 'checkout_src_internal and checkout_chromeos',
     },
 
@@ -4409,7 +4409,7 @@
 
   'src/components/optimization_guide/internal': {
       'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' +
-        'b1fb5d58cb230fb5d7e2a75cff00ab025d18a6fd',
+        '3260a04b709daada0fdf5039d580550c0ad96c9f',
       'condition': 'checkout_src_internal',
   },
 
@@ -4475,7 +4475,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        '0d766f3e5bd6d0a896a35d4e398d455f7888b805',
+        'a712b786ea4b03defe96cc34b36f4dbff9f91634',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_client_hints_controller_delegate.cc b/android_webview/browser/aw_client_hints_controller_delegate.cc
index 1415763..5fe5debf 100644
--- a/android_webview/browser/aw_client_hints_controller_delegate.cc
+++ b/android_webview/browser/aw_client_hints_controller_delegate.cc
@@ -58,15 +58,14 @@
   // Regenerate the brand version lists with Android WebView product name.
   metadata.brand_version_list = embedder_support::GenerateBrandVersionList(
       major_version_number, kAndroidWebViewProductName, major_version,
-      std::nullopt, std::nullopt, enable_updated_grease_by_policy,
+      enable_updated_grease_by_policy,
       blink::UserAgentBrandVersionType::kMajorVersion);
 
   if (!only_low_entropy_ch) {
     metadata.brand_full_version_list =
         embedder_support::GenerateBrandVersionList(
             major_version_number, kAndroidWebViewProductName,
-            metadata.full_version, std::nullopt, std::nullopt,
-            enable_updated_grease_by_policy,
+            metadata.full_version, enable_updated_grease_by_policy,
             blink::UserAgentBrandVersionType::kFullVersion);
   }
 
diff --git a/android_webview/browser/component_updater/trust_token_key_commitments_component_loader.cc b/android_webview/browser/component_updater/trust_token_key_commitments_component_loader.cc
index 122ee64..f266298 100644
--- a/android_webview/browser/component_updater/trust_token_key_commitments_component_loader.cc
+++ b/android_webview/browser/component_updater/trust_token_key_commitments_component_loader.cc
@@ -8,12 +8,10 @@
 #include <string>
 #include <vector>
 
-#include "base/feature_list.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
 #include "components/component_updater/android/loader_policies/trust_token_key_commitments_component_loader_policy.h"
 #include "content/public/browser/network_service_instance.h"
-#include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/network_service.mojom.h"
 
 namespace android_webview {
@@ -22,11 +20,6 @@
 // Tokens is enabled.
 void LoadTrustTokenKeyCommitmentsComponent(
     ComponentLoaderPolicyVector& policies) {
-  if (!base::FeatureList::IsEnabled(network::features::kPrivateStateTokens) &&
-      !base::FeatureList::IsEnabled(network::features::kFledgePst)) {
-    return;
-  }
-
   DVLOG(1)
       << "Registering Trust Token Key Commitments component for loading in "
          "embedded WebView.";
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
index 0e26f8b..87afcd1 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -332,9 +332,6 @@
                 "When enabled, merchant bound virtual cards will be offered in the keyboard "
                         + "accessory."),
         Flag.baseFeature(
-                NetworkServiceFeatures.PRIVATE_STATE_TOKENS,
-                "Enables the prototype Private State Tokens API."),
-        Flag.baseFeature(
                 NetworkServiceFeatures.MASKED_DOMAIN_LIST,
                 "When enabled, the masked domain list required for IP Protection is loaded."),
         Flag.commandLine(
@@ -760,8 +757,6 @@
                         + " to enable BFCache through AwSettings as well. If either of"
                         + " the flag / setting is enabled, BFCache will be enabled"),
         Flag.baseFeature(
-                ContentFeatures.WEBVIEW_SUPPRESS_TAP_DURING_FLING, "Supress tap during fling."),
-        Flag.baseFeature(
                 ContentFeatures.ACCESSIBILITY_MANAGE_BROADCAST_RECEIVER_ON_BACKGROUND,
                 "Register, un-register Accessibility broadcast receiver on a background thread."),
         Flag.baseFeature(
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/WebExposedTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/WebExposedTest.java
index c1769df17..cb655d7 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/WebExposedTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/WebExposedTest.java
@@ -31,7 +31,6 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.UrlUtils;
 
 import java.io.File;
@@ -161,7 +160,6 @@
         "enable-experimental-web-platform-features",
         "enable-blink-test-features",
     })
-    @DisabledTest(message = "crbug.com/381090604 - requires new baseline")
     public void testGlobalInterfaceListingUnstable() throws Exception {
         doTestGlobalInterfaceListing("");
     }
@@ -169,7 +167,6 @@
     @Test
     @LargeTest
     @CommandLineFlags.Add({"disable-field-trial-config"})
-    @DisabledTest(message = "crbug.com/381090604 - requires new baseline")
     public void testGlobalInterfaceListingStable() throws Exception {
         doTestGlobalInterfaceListing("virtual/stable/");
     }
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc
index df90eda..444f833 100644
--- a/android_webview/lib/aw_main_delegate.cc
+++ b/android_webview/lib/aw_main_delegate.cc
@@ -324,16 +324,6 @@
     InitIcuAndResourceBundleBrowserSide();
     aw_feature_list_creator_->CreateFeatureListAndFieldTrials();
     content::InitializeMojoCore();
-
-    // WebView apps can override WebView#computeScroll to achieve custom
-    // scroll/fling. As a result, fling animations may not be ticked,
-    // potentially
-    // confusing the tap suppression controller. Simply disable it for WebView
-    if (!base::FeatureList::IsEnabled(
-            ::features::kWebViewSuppressTapDuringFling)) {
-      ui::GestureConfiguration::GetInstance()
-          ->set_fling_touchscreen_tap_suppression_enabled(false);
-    }
   }
 
   InitializeMemorySystem(is_browser_process);
diff --git a/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 704a882..1bbc10a 100644
--- a/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1,5 +1,10 @@
 This test documents all interface attributes and methods on the global window object and element instances.
 [INTERFACES]
+interface AICreateMonitor : EventTarget
+    attribute @@toStringTag
+    getter ondownloadprogress
+    method constructor
+    setter ondownloadprogress
 interface AbortController
     attribute @@toStringTag
     getter signal
@@ -58,6 +63,7 @@
     getter oncancel
     getter onfinish
     getter onremove
+    getter overallProgress
     getter pending
     getter playState
     getter playbackRate
@@ -150,6 +156,7 @@
 interface AudioContext : BaseAudioContext
     attribute @@toStringTag
     getter baseLatency
+    getter onerror
     getter onsinkchange
     getter outputLatency
     getter sinkId
@@ -162,6 +169,7 @@
     method resume
     method setSinkId
     method suspend
+    setter onerror
     setter onsinkchange
 interface AudioData
     attribute @@toStringTag
@@ -394,6 +402,21 @@
 interface CDATASection : Text
     attribute @@toStringTag
     method constructor
+interface CSPViolationReportBody : ReportBody
+    attribute @@toStringTag
+    getter blockedURL
+    getter columnNumber
+    getter disposition
+    getter documentURL
+    getter effectiveDirective
+    getter lineNumber
+    getter originalPolicy
+    getter referrer
+    getter sample
+    getter sourceFile
+    getter statusCode
+    method constructor
+    method toJSON
 interface CSSAnimation : Animation
     attribute @@toStringTag
     getter animationName
@@ -492,6 +515,12 @@
     attribute @@toStringTag
     getter nameList
     method constructor
+interface CSSMarginRule : CSSRule
+    attribute @@toStringTag
+    getter name
+    getter style
+    method constructor
+    setter style
 interface CSSMathClamp : CSSMathValue
     attribute @@toStringTag
     getter lower
@@ -541,6 +570,11 @@
     getter namespaceURI
     getter prefix
     method constructor
+interface CSSNestedDeclarations : CSSRule
+    attribute @@toStringTag
+    getter style
+    method constructor
+    setter style
 interface CSSNumericArray
     attribute @@toStringTag
     getter length
@@ -563,7 +597,7 @@
     method to
     method toSum
     method type
-interface CSSPageRule : CSSRule
+interface CSSPageRule : CSSGroupingRule
     attribute @@toStringTag
     getter selectorText
     getter style
@@ -575,6 +609,155 @@
     getter length
     method constructor
     setter length
+interface CSSPositionTryDescriptors : CSSStyleDeclaration
+    attribute @@toStringTag
+    getter align-self
+    getter alignSelf
+    getter block-size
+    getter blockSize
+    getter bottom
+    getter height
+    getter inline-size
+    getter inlineSize
+    getter inset
+    getter inset-block
+    getter inset-block-end
+    getter inset-block-start
+    getter inset-inline
+    getter inset-inline-end
+    getter inset-inline-start
+    getter insetBlock
+    getter insetBlockEnd
+    getter insetBlockStart
+    getter insetInline
+    getter insetInlineEnd
+    getter insetInlineStart
+    getter justify-self
+    getter justifySelf
+    getter left
+    getter margin
+    getter margin-block
+    getter margin-block-end
+    getter margin-block-start
+    getter margin-bottom
+    getter margin-inline
+    getter margin-inline-end
+    getter margin-inline-start
+    getter margin-left
+    getter margin-right
+    getter margin-top
+    getter marginBlock
+    getter marginBlockEnd
+    getter marginBlockStart
+    getter marginBottom
+    getter marginInline
+    getter marginInlineEnd
+    getter marginInlineStart
+    getter marginLeft
+    getter marginRight
+    getter marginTop
+    getter max-block-size
+    getter max-height
+    getter max-inline-size
+    getter max-width
+    getter maxBlockSize
+    getter maxHeight
+    getter maxInlineSize
+    getter maxWidth
+    getter min-block-size
+    getter min-height
+    getter min-inline-size
+    getter min-width
+    getter minBlockSize
+    getter minHeight
+    getter minInlineSize
+    getter minWidth
+    getter place-self
+    getter placeSelf
+    getter position-anchor
+    getter position-area
+    getter positionAnchor
+    getter positionArea
+    getter right
+    getter top
+    getter width
+    method constructor
+    setter align-self
+    setter alignSelf
+    setter block-size
+    setter blockSize
+    setter bottom
+    setter height
+    setter inline-size
+    setter inlineSize
+    setter inset
+    setter inset-block
+    setter inset-block-end
+    setter inset-block-start
+    setter inset-inline
+    setter inset-inline-end
+    setter inset-inline-start
+    setter insetBlock
+    setter insetBlockEnd
+    setter insetBlockStart
+    setter insetInline
+    setter insetInlineEnd
+    setter insetInlineStart
+    setter justify-self
+    setter justifySelf
+    setter left
+    setter margin
+    setter margin-block
+    setter margin-block-end
+    setter margin-block-start
+    setter margin-bottom
+    setter margin-inline
+    setter margin-inline-end
+    setter margin-inline-start
+    setter margin-left
+    setter margin-right
+    setter margin-top
+    setter marginBlock
+    setter marginBlockEnd
+    setter marginBlockStart
+    setter marginBottom
+    setter marginInline
+    setter marginInlineEnd
+    setter marginInlineStart
+    setter marginLeft
+    setter marginRight
+    setter marginTop
+    setter max-block-size
+    setter max-height
+    setter max-inline-size
+    setter max-width
+    setter maxBlockSize
+    setter maxHeight
+    setter maxInlineSize
+    setter maxWidth
+    setter min-block-size
+    setter min-height
+    setter min-inline-size
+    setter min-width
+    setter minBlockSize
+    setter minHeight
+    setter minInlineSize
+    setter minWidth
+    setter place-self
+    setter placeSelf
+    setter position-anchor
+    setter position-area
+    setter positionAnchor
+    setter positionArea
+    setter right
+    setter top
+    setter width
+interface CSSPositionTryRule : CSSRule
+    attribute @@toStringTag
+    getter name
+    getter style
+    method constructor
+    setter style
 interface CSSPositionValue : CSSStyleValue
     attribute @@toStringTag
     getter x
@@ -609,6 +792,7 @@
     attribute IMPORT_RULE
     attribute KEYFRAMES_RULE
     attribute KEYFRAME_RULE
+    attribute MARGIN_RULE
     attribute MEDIA_RULE
     attribute NAMESPACE_RULE
     attribute PAGE_RULE
@@ -759,6 +943,11 @@
     getter variable
     method constructor
     setter variable
+interface CSSViewTransitionRule : CSSRule
+    attribute @@toStringTag
+    getter navigation
+    getter types
+    method constructor
 interface Cache
     attribute @@toStringTag
     method add
@@ -891,12 +1080,24 @@
     setter textBaseline
     setter textRendering
     setter wordSpacing
+interface CaretPosition
+    attribute @@toStringTag
+    getter offset
+    getter offsetNode
+    method constructor
+    method getClientRect
 interface ChannelMergerNode : AudioNode
     attribute @@toStringTag
     method constructor
 interface ChannelSplitterNode : AudioNode
     attribute @@toStringTag
     method constructor
+interface ChapterInformation
+    attribute @@toStringTag
+    getter artwork
+    getter startTime
+    getter title
+    method constructor
 interface CharacterBoundsUpdateEvent : Event
     attribute @@toStringTag
     getter rangeEnd
@@ -943,6 +1144,16 @@
     getter reason
     getter wasClean
     method constructor
+interface CloseWatcher : EventTarget
+    attribute @@toStringTag
+    getter oncancel
+    getter onclose
+    method close
+    method constructor
+    method destroy
+    method requestClose
+    setter oncancel
+    setter onclose
 interface Comment : CharacterData
     attribute @@toStringTag
     method constructor
@@ -1326,6 +1537,7 @@
     getter type
     method constructor
     method getAsFile
+    method getAsFileSystemHandle
     method getAsString
     method webkitGetAsEntry
 interface DataTransferItemList
@@ -1347,7 +1559,6 @@
     method constructor
 interface DelegatedInkTrailPresenter
     attribute @@toStringTag
-    getter expectedImprovement
     getter presentationArea
     method constructor
     method updateInkTrailStartPoint
@@ -1510,6 +1721,8 @@
     getter onresume
     getter onscroll
     getter onscrollend
+    getter onscrollsnapchange
+    getter onscrollsnapchanging
     getter onsearch
     getter onsecuritypolicyviolation
     getter onseeked
@@ -1568,7 +1781,9 @@
     getter xmlVersion
     method adoptNode
     method append
+    method browsingTopics
     method captureEvents
+    method caretPositionFromPoint
     method caretRangeFromPoint
     method clear
     method close
@@ -1725,6 +1940,8 @@
     setter onresume
     setter onscroll
     setter onscrollend
+    setter onscrollsnapchange
+    setter onscrollsnapchanging
     setter onsearch
     setter onsecuritypolicyviolation
     setter onseeked
@@ -1836,6 +2053,7 @@
     getter ariaChecked
     getter ariaColCount
     getter ariaColIndex
+    getter ariaColIndexText
     getter ariaColSpan
     getter ariaCurrent
     getter ariaDescription
@@ -1861,6 +2079,7 @@
     getter ariaRoleDescription
     getter ariaRowCount
     getter ariaRowIndex
+    getter ariaRowIndexText
     getter ariaRowSpan
     getter ariaSelected
     getter ariaSetSize
@@ -1879,6 +2098,7 @@
     getter clientLeft
     getter clientTop
     getter clientWidth
+    getter currentCSSZoom
     getter elementTiming
     getter firstElementChild
     getter id
@@ -1927,7 +2147,7 @@
     method getElementsByClassName
     method getElementsByTagName
     method getElementsByTagNameNS
-    method getInnerHTML
+    method getHTML
     method hasAttribute
     method hasAttributeNS
     method hasAttributes
@@ -1971,6 +2191,7 @@
     setter ariaChecked
     setter ariaColCount
     setter ariaColIndex
+    setter ariaColIndexText
     setter ariaColSpan
     setter ariaCurrent
     setter ariaDescription
@@ -1996,6 +2217,7 @@
     setter ariaRoleDescription
     setter ariaRowCount
     setter ariaRowIndex
+    setter ariaRowIndexText
     setter ariaRowSpan
     setter ariaSelected
     setter ariaSetSize
@@ -2033,6 +2255,7 @@
     getter ariaChecked
     getter ariaColCount
     getter ariaColIndex
+    getter ariaColIndexText
     getter ariaColSpan
     getter ariaCurrent
     getter ariaDescription
@@ -2058,6 +2281,7 @@
     getter ariaRoleDescription
     getter ariaRowCount
     getter ariaRowIndex
+    getter ariaRowIndexText
     getter ariaRowSpan
     getter ariaSelected
     getter ariaSetSize
@@ -2087,6 +2311,7 @@
     setter ariaChecked
     setter ariaColCount
     setter ariaColIndex
+    setter ariaColIndexText
     setter ariaColSpan
     setter ariaCurrent
     setter ariaDescription
@@ -2112,6 +2337,7 @@
     setter ariaRoleDescription
     setter ariaRowCount
     setter ariaRowIndex
+    setter ariaRowIndexText
     setter ariaRowSpan
     setter ariaSelected
     setter ariaSetSize
@@ -2402,6 +2628,7 @@
     getter canvas
     method configure
     method constructor
+    method getConfiguration
     method getCurrentTexture
     method unconfigure
 interface GPUCommandBuffer
@@ -2461,6 +2688,7 @@
     setter label
 interface GPUDevice : EventTarget
     attribute @@toStringTag
+    getter adapterInfo
     getter features
     getter label
     getter limits
@@ -2698,6 +2926,7 @@
     method constructor
 interface GamepadHapticActuator
     attribute @@toStringTag
+    getter effects
     getter type
     method constructor
     method playEffect
@@ -2807,6 +3036,7 @@
 interface HTMLAreaElement : HTMLElement
     attribute @@toStringTag
     getter alt
+    getter attributionSrc
     getter coords
     getter download
     getter hash
@@ -2830,6 +3060,7 @@
     method constructor
     method toString
     setter alt
+    setter attributionSrc
     setter coords
     setter download
     setter hash
@@ -3120,6 +3351,8 @@
     getter onresize
     getter onscroll
     getter onscrollend
+    getter onscrollsnapchange
+    getter onscrollsnapchanging
     getter onsecuritypolicyviolation
     getter onseeked
     getter onseeking
@@ -3253,6 +3486,8 @@
     setter onresize
     setter onscroll
     setter onscrollend
+    setter onscrollsnapchange
+    setter onscrollsnapchanging
     setter onsecuritypolicyviolation
     setter onseeked
     setter onseeking
@@ -3474,6 +3709,7 @@
     getter align
     getter allow
     getter allowFullscreen
+    getter browsingTopics
     getter contentDocument
     getter contentWindow
     getter credentialless
@@ -3499,6 +3735,7 @@
     setter align
     setter allow
     setter allowFullscreen
+    setter browsingTopics
     setter credentialless
     setter csp
     setter frameBorder
@@ -4265,10 +4502,12 @@
     getter shadowRootClonable
     getter shadowRootDelegatesFocus
     getter shadowRootMode
+    getter shadowRootSerializable
     method constructor
     setter shadowRootClonable
     setter shadowRootDelegatesFocus
     setter shadowRootMode
+    setter shadowRootSerializable
 interface HTMLTextAreaElement : HTMLElement
     attribute @@toStringTag
     getter autocomplete
@@ -4369,19 +4608,13 @@
     getter videoHeight
     getter videoWidth
     getter webkitDecodedFrameCount
-    getter webkitDisplayingFullscreen
     getter webkitDroppedFrameCount
-    getter webkitSupportsFullscreen
     getter width
     method cancelVideoFrameCallback
     method constructor
     method getVideoPlaybackQuality
     method requestPictureInPicture
     method requestVideoFrameCallback
-    method webkitEnterFullScreen
-    method webkitEnterFullscreen
-    method webkitExitFullScreen
-    method webkitExitFullscreen
     setter disablePictureInPicture
     setter height
     setter onenterpictureinpicture
@@ -4985,6 +5218,8 @@
     getter onresize
     getter onscroll
     getter onscrollend
+    getter onscrollsnapchange
+    getter onscrollsnapchanging
     getter onsecuritypolicyviolation
     getter onseeked
     getter onseeking
@@ -5094,6 +5329,8 @@
     setter onresize
     setter onscroll
     setter onscrollend
+    setter onscrollsnapchange
+    setter onscrollsnapchanging
     setter onsecuritypolicyviolation
     setter onseeked
     setter onseeking
@@ -5138,10 +5375,12 @@
     method toJSON
 interface MediaDevices : EventTarget
     attribute @@toStringTag
+    getter ondevicechange
     method constructor
     method enumerateDevices
     method getSupportedConstraints
     method getUserMedia
+    setter ondevicechange
 interface MediaElementAudioSourceNode : AudioNode
     attribute @@toStringTag
     getter mediaElement
@@ -5337,6 +5576,19 @@
     setter onended
     setter onmute
     setter onunmute
+interface MediaStreamTrackAudioStats
+    attribute @@toStringTag
+    getter averageLatency
+    getter deliveredFrames
+    getter deliveredFramesDuration
+    getter latency
+    getter maximumLatency
+    getter minimumLatency
+    getter totalFrames
+    getter totalFramesDuration
+    method constructor
+    method resetLatency
+    method toJSON
 interface MediaStreamTrackEvent : Event
     attribute @@toStringTag
     getter track
@@ -5423,18 +5675,6 @@
     method constructor
     method getModifierState
     method initMouseEvent
-interface MutationEvent : Event
-    attribute @@toStringTag
-    attribute ADDITION
-    attribute MODIFICATION
-    attribute REMOVAL
-    getter attrChange
-    getter attrName
-    getter newValue
-    getter prevValue
-    getter relatedNode
-    method constructor
-    method initMutationEvent
 interface MutationObserver
     attribute @@toStringTag
     method constructor
@@ -5604,6 +5844,7 @@
     getter mimeTypes
     getter onLine
     getter pdfViewerEnabled
+    getter permissions
     getter platform
     getter plugins
     getter product
@@ -5911,10 +6152,12 @@
     method constructor
 interface PageRevealEvent : Event
     attribute @@toStringTag
+    getter viewTransition
     method constructor
 interface PageSwapEvent : Event
     attribute @@toStringTag
     getter activation
+    getter viewTransition
     method constructor
 interface PageTransitionEvent : Event
     attribute @@toStringTag
@@ -6093,6 +6336,7 @@
     getter domainLookupStart
     getter encodedBodySize
     getter fetchStart
+    getter finalResponseHeadersStart
     getter firstInterimResponseStart
     getter initiatorType
     getter nextHopProtocol
@@ -6158,6 +6402,17 @@
 interface PeriodicWave
     attribute @@toStringTag
     method constructor
+interface PermissionStatus : EventTarget
+    attribute @@toStringTag
+    getter name
+    getter onchange
+    getter state
+    method constructor
+    setter onchange
+interface Permissions
+    attribute @@toStringTag
+    method constructor
+    method query
 interface PictureInPictureEvent : Event
     attribute @@toStringTag
     getter pictureInPictureWindow
@@ -6193,6 +6448,7 @@
     getter azimuthAngle
     getter height
     getter isPrimary
+    getter persistentDeviceId
     getter pointerId
     getter pointerType
     getter pressure
@@ -6209,21 +6465,6 @@
     getter hasUAVisualTransition
     getter state
     method constructor
-interface PressureObserver
-    static getter supportedSources
-    attribute @@toStringTag
-    method constructor
-    method disconnect
-    method observe
-    method takeRecords
-    method unobserve
-interface PressureRecord
-    attribute @@toStringTag
-    getter source
-    getter state
-    getter time
-    method constructor
-    method toJSON
 interface ProcessingInstruction : CharacterData
     attribute @@toStringTag
     getter sheet
@@ -6246,6 +6487,10 @@
     getter promise
     getter reason
     method constructor
+interface ProtectedAudience
+    attribute @@toStringTag
+    method constructor
+    method queryFeatureSupport
 interface RTCCertificate
     attribute @@toStringTag
     getter expires
@@ -6616,6 +6861,10 @@
 interface RelativeOrientationSensor : OrientationSensor
     attribute @@toStringTag
     method constructor
+interface ReportBody
+    attribute @@toStringTag
+    method constructor
+    method toJSON
 interface ReportingObserver
     attribute @@toStringTag
     method constructor
@@ -6629,6 +6878,7 @@
     getter cache
     getter credentials
     getter destination
+    getter duplex
     getter headers
     getter integrity
     getter isHistoryNavigation
@@ -6919,6 +7169,8 @@
     getter onresize
     getter onscroll
     getter onscrollend
+    getter onscrollsnapchange
+    getter onscrollsnapchanging
     getter onsecuritypolicyviolation
     getter onseeked
     getter onseeking
@@ -7030,6 +7282,8 @@
     setter onresize
     setter onscroll
     setter onscrollend
+    setter onscrollsnapchange
+    setter onscrollsnapchanging
     setter onsecuritypolicyviolation
     setter onseeked
     setter onseeking
@@ -7845,6 +8099,7 @@
     attribute @@toStringTag
     method constructor
     method postTask
+    method yield
 interface Scheduling
     attribute @@toStringTag
     method constructor
@@ -8019,19 +8274,25 @@
     getter onslotchange
     getter pictureInPictureElement
     getter pointerLockElement
+    getter serializable
     getter slotAssignment
     getter styleSheets
     method constructor
     method elementFromPoint
     method elementsFromPoint
     method getAnimations
-    method getInnerHTML
+    method getHTML
     method getSelection
     method setHTMLUnsafe
     setter adoptedStyleSheets
     setter fullscreenElement
     setter innerHTML
     setter onslotchange
+interface SnapEvent : Event
+    attribute @@toStringTag
+    getter snapTargetBlock
+    getter snapTargetInline
+    method constructor
 interface SourceBuffer : EventTarget
     attribute @@toStringTag
     getter appendWindowEnd
@@ -8111,7 +8372,7 @@
     getter url
     method constructor
     method initStorageEvent
-interface StorageManager : EventTarget
+interface StorageManager
     attribute @@toStringTag
     method constructor
     method estimate
@@ -8445,6 +8706,7 @@
 interface URL
     static method canParse
     static method createObjectURL
+    static method parse
     static method revokeObjectURL
     attribute @@toStringTag
     getter hash
@@ -8648,6 +8910,7 @@
     getter offsetTop
     getter onresize
     getter onscroll
+    getter onscrollend
     getter pageLeft
     getter pageTop
     getter scale
@@ -8655,6 +8918,7 @@
     method constructor
     setter onresize
     setter onscroll
+    setter onscrollend
 interface WGSLLanguageFeatures
     attribute @@toStringTag
     getter size
@@ -9485,23 +9749,26 @@
     getter size
     getter type
     method constructor
-interface WebGLBuffer
+interface WebGLBuffer : WebGLObject
     attribute @@toStringTag
     method constructor
 interface WebGLContextEvent : Event
     attribute @@toStringTag
     getter statusMessage
     method constructor
-interface WebGLFramebuffer
+interface WebGLFramebuffer : WebGLObject
     attribute @@toStringTag
     method constructor
-interface WebGLProgram
+interface WebGLObject
     attribute @@toStringTag
     method constructor
-interface WebGLQuery
+interface WebGLProgram : WebGLObject
     attribute @@toStringTag
     method constructor
-interface WebGLRenderbuffer
+interface WebGLQuery : WebGLObject
+    attribute @@toStringTag
+    method constructor
+interface WebGLRenderbuffer : WebGLObject
     attribute @@toStringTag
     method constructor
 interface WebGLRenderingContext
@@ -9950,10 +10217,10 @@
     method viewport
     setter drawingBufferColorSpace
     setter unpackColorSpace
-interface WebGLSampler
+interface WebGLSampler : WebGLObject
     attribute @@toStringTag
     method constructor
-interface WebGLShader
+interface WebGLShader : WebGLObject
     attribute @@toStringTag
     method constructor
 interface WebGLShaderPrecisionFormat
@@ -9962,19 +10229,19 @@
     getter rangeMax
     getter rangeMin
     method constructor
-interface WebGLSync
+interface WebGLSync : WebGLObject
     attribute @@toStringTag
     method constructor
-interface WebGLTexture
+interface WebGLTexture : WebGLObject
     attribute @@toStringTag
     method constructor
-interface WebGLTransformFeedback
+interface WebGLTransformFeedback : WebGLObject
     attribute @@toStringTag
     method constructor
 interface WebGLUniformLocation
     attribute @@toStringTag
     method constructor
-interface WebGLVertexArrayObject
+interface WebGLVertexArrayObject : WebGLObject
     attribute @@toStringTag
     method constructor
 interface WebKitCSSMatrix : DOMMatrixReadOnly
@@ -10420,6 +10687,7 @@
 interface webkitURL
     static method canParse
     static method createObjectURL
+    static method parse
     static method revokeObjectURL
     attribute @@toStringTag
     getter hash
@@ -10584,7 +10852,6 @@
     setter memory
 [GLOBAL OBJECT]
     attribute android
-    attribute android_webview_media_token_provider_listener
     attribute awConsole
     attribute globalThis
     attribute propertyNamesInGlobal
@@ -10709,6 +10976,8 @@
     getter onresize
     getter onscroll
     getter onscrollend
+    getter onscrollsnapchange
+    getter onscrollsnapchanging
     getter onsearch
     getter onsecuritypolicyviolation
     getter onseeked
@@ -10793,6 +11062,7 @@
     method moveBy
     method moveTo
     method open
+    method openDatabase
     method postMessage
     method print
     method prompt
@@ -10808,6 +11078,9 @@
     method scrollTo
     method setInterval
     method setTimeout
+    method showDirectoryPicker
+    method showOpenFilePicker
+    method showSaveFilePicker
     method stop
     method structuredClone
     method webkitCancelAnimationFrame
@@ -10919,6 +11192,8 @@
     setter onresize
     setter onscroll
     setter onscrollend
+    setter onscrollsnapchange
+    setter onscrollsnapchanging
     setter onsearch
     setter onsecuritypolicyviolation
     setter onseeked
diff --git a/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt b/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt
index 704a882..2dca07a0 100644
--- a/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt
@@ -1,5 +1,112 @@
 This test documents all interface attributes and methods on the global window object and element instances.
 [INTERFACES]
+interface AI
+    attribute @@toStringTag
+    getter languageModel
+    getter rewriter
+    getter summarizer
+    getter translator
+    getter writer
+    method constructor
+interface AICreateMonitor : EventTarget
+    attribute @@toStringTag
+    getter ondownloadprogress
+    method constructor
+    setter ondownloadprogress
+interface AILanguageModel : EventTarget
+    attribute @@toStringTag
+    getter maxTokens
+    getter oncontextoverflow
+    getter temperature
+    getter tokensLeft
+    getter tokensSoFar
+    getter topK
+    method clone
+    method constructor
+    method countPromptTokens
+    method destroy
+    method prompt
+    method promptStreaming
+    setter oncontextoverflow
+interface AILanguageModelCapabilities
+    attribute @@toStringTag
+    getter available
+    getter defaultTemperature
+    getter defaultTopK
+    getter maxTopK
+    method constructor
+    method languageAvailable
+interface AILanguageModelFactory
+    attribute @@toStringTag
+    method capabilities
+    method constructor
+    method create
+interface AIRewriter
+    attribute @@toStringTag
+    getter format
+    getter length
+    getter sharedContext
+    getter tone
+    method constructor
+    method destroy
+    method rewrite
+    method rewriteStreaming
+interface AIRewriterFactory
+    attribute @@toStringTag
+    method availability
+    method constructor
+    method create
+interface AISummarizer
+    attribute @@toStringTag
+    getter format
+    getter length
+    getter sharedContext
+    getter type
+    method constructor
+    method destroy
+    method summarize
+    method summarizeStreaming
+interface AISummarizerCapabilities
+    attribute @@toStringTag
+    getter available
+    method constructor
+    method createOptionsAvailable
+    method languageAvailable
+interface AISummarizerFactory
+    attribute @@toStringTag
+    method capabilities
+    method constructor
+    method create
+interface AITranslator
+    attribute @@toStringTag
+    method constructor
+    method destroy
+    method translate
+interface AITranslatorCapabilities
+    attribute @@toStringTag
+    getter available
+    method constructor
+    method languagePairAvailable
+interface AITranslatorFactory
+    attribute @@toStringTag
+    method capabilities
+    method constructor
+    method create
+interface AIWriter
+    attribute @@toStringTag
+    getter format
+    getter length
+    getter sharedContext
+    getter tone
+    method constructor
+    method destroy
+    method write
+    method writeStreaming
+interface AIWriterFactory
+    attribute @@toStringTag
+    method availability
+    method constructor
+    method create
 interface AbortController
     attribute @@toStringTag
     getter signal
@@ -33,6 +140,10 @@
     getter y
     getter z
     method constructor
+interface AmbientLightSensor : Sensor
+    attribute @@toStringTag
+    getter illuminance
+    method constructor
 interface AnalyserNode : AudioNode
     attribute @@toStringTag
     getter fftSize
@@ -58,6 +169,7 @@
     getter oncancel
     getter onfinish
     getter onremove
+    getter overallProgress
     getter pending
     getter playState
     getter playbackRate
@@ -109,6 +221,7 @@
     getter currentTime
     getter duration
     method constructor
+    method getCurrentTime
 interface Attr : Node
     attribute @@toStringTag
     getter localName
@@ -120,6 +233,10 @@
     getter value
     method constructor
     setter value
+interface AttributePart : NodePart
+    attribute @@toStringTag
+    getter localName
+    method constructor
 interface Audio
     attribute @@toStringTag
     method constructor
@@ -150,8 +267,10 @@
 interface AudioContext : BaseAudioContext
     attribute @@toStringTag
     getter baseLatency
+    getter onerror
     getter onsinkchange
     getter outputLatency
+    getter playoutStats
     getter sinkId
     method close
     method constructor
@@ -162,6 +281,7 @@
     method resume
     method setSinkId
     method suspend
+    setter onerror
     setter onsinkchange
 interface AudioData
     attribute @@toStringTag
@@ -262,6 +382,17 @@
     method has
     method keys
     method values
+interface AudioPlayoutStats
+    attribute @@toStringTag
+    getter averageLatency
+    getter fallbackFramesDuration
+    getter fallbackFramesEvents
+    getter maximumLatency
+    getter minimumLatency
+    getter totalFramesDuration
+    method constructor
+    method resetLatency
+    method toJSON
 interface AudioProcessingEvent : Event
     attribute @@toStringTag
     getter inputBuffer
@@ -279,6 +410,28 @@
     attribute @@toStringTag
     getter type
     method constructor
+interface AudioTrack
+    attribute @@toStringTag
+    getter enabled
+    getter id
+    getter kind
+    getter label
+    getter language
+    getter sourceBuffer
+    method constructor
+    setter enabled
+interface AudioTrackList : EventTarget
+    attribute @@toStringTag
+    getter length
+    getter onaddtrack
+    getter onchange
+    getter onremovetrack
+    method @@iterator
+    method constructor
+    method getTrackById
+    setter onaddtrack
+    setter onchange
+    setter onremovetrack
 interface AudioWorklet : Worklet
     attribute @@toStringTag
     method constructor
@@ -289,6 +442,12 @@
     getter port
     method constructor
     setter onprocessorerror
+interface BackForwardCacheRestoration : PerformanceEntry
+    attribute @@toStringTag
+    getter pageshowEventEnd
+    getter pageshowEventStart
+    method constructor
+    method toJSON
 interface BarProp
     attribute @@toStringTag
     getter visible
@@ -338,6 +497,11 @@
     setter onchargingtimechange
     setter ondischargingtimechange
     setter onlevelchange
+interface BeforeCreatePolicyEvent : Event
+    attribute @@toStringTag
+    getter policyName
+    method constructor
+    setter policyName
 interface BeforeInstallPromptEvent : Event
     attribute @@toStringTag
     getter platforms
@@ -373,6 +537,47 @@
     getter data
     getter timecode
     method constructor
+interface BluetoothAdvertisingEvent : Event
+    attribute @@toStringTag
+    getter appearance
+    getter device
+    getter manufacturerData
+    getter name
+    getter rssi
+    getter serviceData
+    getter txPower
+    getter uuids
+    method constructor
+interface BluetoothLEScan
+    attribute @@toStringTag
+    getter acceptAllAdvertisements
+    getter active
+    getter filters
+    getter keepRepeatedDevices
+    method constructor
+    method stop
+interface BluetoothManufacturerDataMap
+    attribute @@toStringTag
+    getter size
+    method @@iterator
+    method constructor
+    method entries
+    method forEach
+    method get
+    method has
+    method keys
+    method values
+interface BluetoothServiceDataMap
+    attribute @@toStringTag
+    getter size
+    method @@iterator
+    method constructor
+    method entries
+    method forEach
+    method get
+    method has
+    method keys
+    method values
 interface BroadcastChannel : EventTarget
     attribute @@toStringTag
     getter name
@@ -394,10 +599,32 @@
 interface CDATASection : Text
     attribute @@toStringTag
     method constructor
+interface CSPViolationReportBody : ReportBody
+    attribute @@toStringTag
+    getter blockedURL
+    getter columnNumber
+    getter disposition
+    getter documentURL
+    getter effectiveDirective
+    getter lineNumber
+    getter originalPolicy
+    getter referrer
+    getter sample
+    getter sourceFile
+    getter statusCode
+    method constructor
+    method toJSON
 interface CSSAnimation : Animation
     attribute @@toStringTag
     getter animationName
     method constructor
+interface CSSColorValue
+    static method parse
+    attribute @@toStringTag
+    method constructor
+    method toHSL
+    method toHWB
+    method toRGB
 interface CSSConditionRule : CSSGroupingRule
     attribute @@toStringTag
     getter conditionText
@@ -449,6 +676,28 @@
     method constructor
     method deleteRule
     method insertRule
+interface CSSHSL : CSSColorValue
+    attribute @@toStringTag
+    getter alpha
+    getter h
+    getter l
+    getter s
+    method constructor
+    setter alpha
+    setter h
+    setter l
+    setter s
+interface CSSHWB : CSSColorValue
+    attribute @@toStringTag
+    getter alpha
+    getter b
+    getter h
+    getter w
+    method constructor
+    setter alpha
+    setter b
+    setter h
+    setter w
 interface CSSImageValue : CSSStyleValue
     attribute @@toStringTag
     method constructor
@@ -492,6 +741,12 @@
     attribute @@toStringTag
     getter nameList
     method constructor
+interface CSSMarginRule : CSSRule
+    attribute @@toStringTag
+    getter name
+    getter style
+    method constructor
+    setter style
 interface CSSMathClamp : CSSMathValue
     attribute @@toStringTag
     getter lower
@@ -541,6 +796,11 @@
     getter namespaceURI
     getter prefix
     method constructor
+interface CSSNestedDeclarations : CSSRule
+    attribute @@toStringTag
+    getter style
+    method constructor
+    setter style
 interface CSSNumericArray
     attribute @@toStringTag
     getter length
@@ -563,7 +823,7 @@
     method to
     method toSum
     method type
-interface CSSPageRule : CSSRule
+interface CSSPageRule : CSSGroupingRule
     attribute @@toStringTag
     getter selectorText
     getter style
@@ -575,6 +835,155 @@
     getter length
     method constructor
     setter length
+interface CSSPositionTryDescriptors : CSSStyleDeclaration
+    attribute @@toStringTag
+    getter align-self
+    getter alignSelf
+    getter block-size
+    getter blockSize
+    getter bottom
+    getter height
+    getter inline-size
+    getter inlineSize
+    getter inset
+    getter inset-block
+    getter inset-block-end
+    getter inset-block-start
+    getter inset-inline
+    getter inset-inline-end
+    getter inset-inline-start
+    getter insetBlock
+    getter insetBlockEnd
+    getter insetBlockStart
+    getter insetInline
+    getter insetInlineEnd
+    getter insetInlineStart
+    getter justify-self
+    getter justifySelf
+    getter left
+    getter margin
+    getter margin-block
+    getter margin-block-end
+    getter margin-block-start
+    getter margin-bottom
+    getter margin-inline
+    getter margin-inline-end
+    getter margin-inline-start
+    getter margin-left
+    getter margin-right
+    getter margin-top
+    getter marginBlock
+    getter marginBlockEnd
+    getter marginBlockStart
+    getter marginBottom
+    getter marginInline
+    getter marginInlineEnd
+    getter marginInlineStart
+    getter marginLeft
+    getter marginRight
+    getter marginTop
+    getter max-block-size
+    getter max-height
+    getter max-inline-size
+    getter max-width
+    getter maxBlockSize
+    getter maxHeight
+    getter maxInlineSize
+    getter maxWidth
+    getter min-block-size
+    getter min-height
+    getter min-inline-size
+    getter min-width
+    getter minBlockSize
+    getter minHeight
+    getter minInlineSize
+    getter minWidth
+    getter place-self
+    getter placeSelf
+    getter position-anchor
+    getter position-area
+    getter positionAnchor
+    getter positionArea
+    getter right
+    getter top
+    getter width
+    method constructor
+    setter align-self
+    setter alignSelf
+    setter block-size
+    setter blockSize
+    setter bottom
+    setter height
+    setter inline-size
+    setter inlineSize
+    setter inset
+    setter inset-block
+    setter inset-block-end
+    setter inset-block-start
+    setter inset-inline
+    setter inset-inline-end
+    setter inset-inline-start
+    setter insetBlock
+    setter insetBlockEnd
+    setter insetBlockStart
+    setter insetInline
+    setter insetInlineEnd
+    setter insetInlineStart
+    setter justify-self
+    setter justifySelf
+    setter left
+    setter margin
+    setter margin-block
+    setter margin-block-end
+    setter margin-block-start
+    setter margin-bottom
+    setter margin-inline
+    setter margin-inline-end
+    setter margin-inline-start
+    setter margin-left
+    setter margin-right
+    setter margin-top
+    setter marginBlock
+    setter marginBlockEnd
+    setter marginBlockStart
+    setter marginBottom
+    setter marginInline
+    setter marginInlineEnd
+    setter marginInlineStart
+    setter marginLeft
+    setter marginRight
+    setter marginTop
+    setter max-block-size
+    setter max-height
+    setter max-inline-size
+    setter max-width
+    setter maxBlockSize
+    setter maxHeight
+    setter maxInlineSize
+    setter maxWidth
+    setter min-block-size
+    setter min-height
+    setter min-inline-size
+    setter min-width
+    setter minBlockSize
+    setter minHeight
+    setter minInlineSize
+    setter minWidth
+    setter place-self
+    setter placeSelf
+    setter position-anchor
+    setter position-area
+    setter positionAnchor
+    setter positionArea
+    setter right
+    setter top
+    setter width
+interface CSSPositionTryRule : CSSRule
+    attribute @@toStringTag
+    getter name
+    getter style
+    method constructor
+    setter style
 interface CSSPositionValue : CSSStyleValue
     attribute @@toStringTag
     getter x
@@ -589,6 +998,17 @@
     getter name
     getter syntax
     method constructor
+interface CSSRGB : CSSColorValue
+    attribute @@toStringTag
+    getter alpha
+    getter b
+    getter g
+    getter r
+    method constructor
+    setter alpha
+    setter b
+    setter g
+    setter r
 interface CSSRotate : CSSTransformComponent
     attribute @@toStringTag
     getter angle
@@ -609,6 +1029,7 @@
     attribute IMPORT_RULE
     attribute KEYFRAMES_RULE
     attribute KEYFRAME_RULE
+    attribute MARGIN_RULE
     attribute MEDIA_RULE
     attribute NAMESPACE_RULE
     attribute PAGE_RULE
@@ -759,6 +1180,11 @@
     getter variable
     method constructor
     setter variable
+interface CSSViewTransitionRule : CSSRule
+    attribute @@toStringTag
+    getter navigation
+    getter types
+    method constructor
 interface Cache
     attribute @@toStringTag
     method add
@@ -782,6 +1208,9 @@
     getter canvas
     method constructor
     method requestFrame
+interface CanvasFilter
+    attribute @@toStringTag
+    method constructor
 interface CanvasGradient
     attribute @@toStringTag
     method addColorStop
@@ -821,6 +1250,7 @@
     getter wordSpacing
     method arc
     method arcTo
+    method beginLayer
     method beginPath
     method bezierCurveTo
     method clearRect
@@ -830,17 +1260,24 @@
     method createConicGradient
     method createImageData
     method createLinearGradient
+    method createMesh2DIndexBuffer
+    method createMesh2DUVBuffer
+    method createMesh2DVertexBuffer
     method createPattern
     method createRadialGradient
     method drawFocusIfNeeded
     method drawImage
+    method drawMesh
     method ellipse
+    method endLayer
     method fill
     method fillRect
     method fillText
+    method fillTextCluster
     method getContextAttributes
     method getImageData
     method getLineDash
+    method getTextureFormat
     method getTransform
     method isContextLost
     method isPointInPath
@@ -848,6 +1285,7 @@
     method lineTo
     method measureText
     method moveTo
+    method placeElement
     method putImageData
     method quadraticCurveTo
     method rect
@@ -863,6 +1301,8 @@
     method stroke
     method strokeRect
     method strokeText
+    method transferBackFromGPUTexture
+    method transferToGPUTexture
     method transform
     method translate
     setter direction
@@ -891,12 +1331,24 @@
     setter textBaseline
     setter textRendering
     setter wordSpacing
+interface CaretPosition
+    attribute @@toStringTag
+    getter offset
+    getter offsetNode
+    method constructor
+    method getClientRect
 interface ChannelMergerNode : AudioNode
     attribute @@toStringTag
     method constructor
 interface ChannelSplitterNode : AudioNode
     attribute @@toStringTag
     method constructor
+interface ChapterInformation
+    attribute @@toStringTag
+    getter artwork
+    getter startTime
+    getter title
+    method constructor
 interface CharacterBoundsUpdateEvent : Event
     attribute @@toStringTag
     getter rangeEnd
@@ -920,6 +1372,16 @@
     method replaceWith
     method substringData
     setter data
+interface ChildNodePart : Part
+    attribute @@toStringTag
+    getter children
+    getter nextSibling
+    getter previousSibling
+    getter rootContainer
+    method clone
+    method constructor
+    method getParts
+    method replaceChildren
 interface Clipboard : EventTarget
     attribute @@toStringTag
     method constructor
@@ -943,6 +1405,21 @@
     getter reason
     getter wasClean
     method constructor
+interface CloseWatcher : EventTarget
+    attribute @@toStringTag
+    getter oncancel
+    getter onclose
+    method close
+    method constructor
+    method destroy
+    method requestClose
+    setter oncancel
+    setter onclose
+interface CommandEvent : Event
+    attribute @@toStringTag
+    getter command
+    getter source
+    method constructor
 interface Comment : CharacterData
     attribute @@toStringTag
     method constructor
@@ -1326,6 +1803,7 @@
     getter type
     method constructor
     method getAsFile
+    method getAsFileSystemHandle
     method getAsString
     method webkitGetAsEntry
 interface DataTransferItemList
@@ -1347,11 +1825,11 @@
     method constructor
 interface DelegatedInkTrailPresenter
     attribute @@toStringTag
-    getter expectedImprovement
     getter presentationArea
     method constructor
     method updateInkTrailStartPoint
 interface DeviceMotionEvent : Event
+    static method requestPermission
     attribute @@toStringTag
     getter acceleration
     getter accelerationIncludingGravity
@@ -1371,13 +1849,25 @@
     getter gamma
     method constructor
 interface DeviceOrientationEvent : Event
+    static method requestPermission
     attribute @@toStringTag
     getter absolute
     getter alpha
     getter beta
     getter gamma
     method constructor
+interface DigitalCredential : Credential
+    attribute @@toStringTag
+    getter data
+    getter protocol
+    method constructor
+interface Directive
+    attribute @@toStringTag
+    getter type
+    method constructor
+    method toString
 interface Document : Node
+    static method parseHTML
     static method parseHTMLUnsafe
     attribute @@toStringTag
     attribute @@unscopables
@@ -1486,6 +1976,7 @@
     getter onmouseover
     getter onmouseup
     getter onmousewheel
+    getter onoverscroll
     getter onpaste
     getter onpause
     getter onplay
@@ -1510,6 +2001,8 @@
     getter onresume
     getter onscroll
     getter onscrollend
+    getter onscrollsnapchange
+    getter onscrollsnapchanging
     getter onsearch
     getter onsecuritypolicyviolation
     getter onseeked
@@ -1551,6 +2044,7 @@
     getter rootElement
     getter scripts
     getter scrollingElement
+    getter softNavigations
     getter styleSheets
     getter timeline
     getter title
@@ -1568,7 +2062,10 @@
     getter xmlVersion
     method adoptNode
     method append
+    method ariaNotify
+    method browsingTopics
     method captureEvents
+    method caretPositionFromPoint
     method caretRangeFromPoint
     method clear
     method close
@@ -1601,6 +2098,7 @@
     method getElementsByName
     method getElementsByTagName
     method getElementsByTagNameNS
+    method getPartRoot
     method getSelection
     method hasFocus
     method hasPrivateToken
@@ -1608,6 +2106,7 @@
     method hasStorageAccess
     method hasUnpartitionedCookieAccess
     method importNode
+    method moveBefore
     method open
     method prepend
     method queryCommandEnabled
@@ -1621,6 +2120,7 @@
     method replaceChildren
     method requestStorageAccess
     method requestStorageAccessFor
+    method setSequentialFocusStartingPoint
     method startViewTransition
     method webkitCancelFullScreen
     method webkitExitFullscreen
@@ -1701,6 +2201,7 @@
     setter onmouseover
     setter onmouseup
     setter onmousewheel
+    setter onoverscroll
     setter onpaste
     setter onpause
     setter onplay
@@ -1725,6 +2226,8 @@
     setter onresume
     setter onscroll
     setter onscrollend
+    setter onscrollsnapchange
+    setter onscrollsnapchanging
     setter onsearch
     setter onsecuritypolicyviolation
     setter onseeked
@@ -1770,10 +2273,18 @@
     method append
     method constructor
     method getElementById
+    method getPartRoot
+    method moveBefore
     method prepend
     method querySelector
     method querySelectorAll
     method replaceChildren
+interface DocumentPartRoot
+    attribute @@toStringTag
+    getter rootContainer
+    method clone
+    method constructor
+    method getParts
 interface DocumentTimeline : AnimationTimeline
     attribute @@toStringTag
     method constructor
@@ -1828,6 +2339,8 @@
 interface Element : Node
     attribute @@toStringTag
     attribute @@unscopables
+    getter anchorElement
+    getter ariaActiveDescendantElement
     getter ariaAtomic
     getter ariaAutoComplete
     getter ariaBrailleLabel
@@ -1836,22 +2349,30 @@
     getter ariaChecked
     getter ariaColCount
     getter ariaColIndex
+    getter ariaColIndexText
     getter ariaColSpan
+    getter ariaControlsElements
     getter ariaCurrent
+    getter ariaDescribedByElements
     getter ariaDescription
+    getter ariaDetailsElements
     getter ariaDisabled
+    getter ariaErrorMessageElements
     getter ariaExpanded
+    getter ariaFlowToElements
     getter ariaHasPopup
     getter ariaHidden
     getter ariaInvalid
     getter ariaKeyShortcuts
     getter ariaLabel
+    getter ariaLabelledByElements
     getter ariaLevel
     getter ariaLive
     getter ariaModal
     getter ariaMultiLine
     getter ariaMultiSelectable
     getter ariaOrientation
+    getter ariaOwnsElements
     getter ariaPlaceholder
     getter ariaPosInSet
     getter ariaPressed
@@ -1861,6 +2382,7 @@
     getter ariaRoleDescription
     getter ariaRowCount
     getter ariaRowIndex
+    getter ariaRowIndexText
     getter ariaRowSpan
     getter ariaSelected
     getter ariaSetSize
@@ -1869,6 +2391,7 @@
     getter ariaValueMin
     getter ariaValueNow
     getter ariaValueText
+    getter ariaVirtualContent
     getter assignedSlot
     getter attributes
     getter childElementCount
@@ -1879,6 +2402,9 @@
     getter clientLeft
     getter clientTop
     getter clientWidth
+    getter computedName
+    getter computedRole
+    getter currentCSSZoom
     getter elementTiming
     getter firstElementChild
     getter id
@@ -1910,6 +2436,7 @@
     method after
     method animate
     method append
+    method ariaNotify
     method attachShadow
     method before
     method checkVisibility
@@ -1927,7 +2454,7 @@
     method getElementsByClassName
     method getElementsByTagName
     method getElementsByTagNameNS
-    method getInnerHTML
+    method getHTML
     method hasAttribute
     method hasAttributeNS
     method hasAttributes
@@ -1936,6 +2463,7 @@
     method insertAdjacentHTML
     method insertAdjacentText
     method matches
+    method moveBefore
     method prepend
     method querySelector
     method querySelectorAll
@@ -1957,12 +2485,15 @@
     method setAttributeNS
     method setAttributeNode
     method setAttributeNodeNS
+    method setHTML
     method setHTMLUnsafe
     method setPointerCapture
     method toggleAttribute
     method webkitMatchesSelector
     method webkitRequestFullScreen
     method webkitRequestFullscreen
+    setter anchorElement
+    setter ariaActiveDescendantElement
     setter ariaAtomic
     setter ariaAutoComplete
     setter ariaBrailleLabel
@@ -1971,22 +2502,30 @@
     setter ariaChecked
     setter ariaColCount
     setter ariaColIndex
+    setter ariaColIndexText
     setter ariaColSpan
+    setter ariaControlsElements
     setter ariaCurrent
+    setter ariaDescribedByElements
     setter ariaDescription
+    setter ariaDetailsElements
     setter ariaDisabled
+    setter ariaErrorMessageElements
     setter ariaExpanded
+    setter ariaFlowToElements
     setter ariaHasPopup
     setter ariaHidden
     setter ariaInvalid
     setter ariaKeyShortcuts
     setter ariaLabel
+    setter ariaLabelledByElements
     setter ariaLevel
     setter ariaLive
     setter ariaModal
     setter ariaMultiLine
     setter ariaMultiSelectable
     setter ariaOrientation
+    setter ariaOwnsElements
     setter ariaPlaceholder
     setter ariaPosInSet
     setter ariaPressed
@@ -1996,6 +2535,7 @@
     setter ariaRoleDescription
     setter ariaRowCount
     setter ariaRowIndex
+    setter ariaRowIndexText
     setter ariaRowSpan
     setter ariaSelected
     setter ariaSetSize
@@ -2004,6 +2544,7 @@
     setter ariaValueMin
     setter ariaValueNow
     setter ariaValueText
+    setter ariaVirtualContent
     setter classList
     setter className
     setter elementTiming
@@ -2025,6 +2566,7 @@
     setter slot
 interface ElementInternals
     attribute @@toStringTag
+    getter ariaActiveDescendantElement
     getter ariaAtomic
     getter ariaAutoComplete
     getter ariaBrailleLabel
@@ -2033,22 +2575,30 @@
     getter ariaChecked
     getter ariaColCount
     getter ariaColIndex
+    getter ariaColIndexText
     getter ariaColSpan
+    getter ariaControlsElements
     getter ariaCurrent
+    getter ariaDescribedByElements
     getter ariaDescription
+    getter ariaDetailsElements
     getter ariaDisabled
+    getter ariaErrorMessageElements
     getter ariaExpanded
+    getter ariaFlowToElements
     getter ariaHasPopup
     getter ariaHidden
     getter ariaInvalid
     getter ariaKeyShortcuts
     getter ariaLabel
+    getter ariaLabelledByElements
     getter ariaLevel
     getter ariaLive
     getter ariaModal
     getter ariaMultiLine
     getter ariaMultiSelectable
     getter ariaOrientation
+    getter ariaOwnsElements
     getter ariaPlaceholder
     getter ariaPosInSet
     getter ariaPressed
@@ -2058,6 +2608,7 @@
     getter ariaRoleDescription
     getter ariaRowCount
     getter ariaRowIndex
+    getter ariaRowIndexText
     getter ariaRowSpan
     getter ariaSelected
     getter ariaSetSize
@@ -2066,6 +2617,7 @@
     getter ariaValueMin
     getter ariaValueNow
     getter ariaValueText
+    getter ariaVirtualContent
     getter form
     getter labels
     getter role
@@ -2079,6 +2631,7 @@
     method reportValidity
     method setFormValue
     method setValidity
+    setter ariaActiveDescendantElement
     setter ariaAtomic
     setter ariaAutoComplete
     setter ariaBrailleLabel
@@ -2087,22 +2640,30 @@
     setter ariaChecked
     setter ariaColCount
     setter ariaColIndex
+    setter ariaColIndexText
     setter ariaColSpan
+    setter ariaControlsElements
     setter ariaCurrent
+    setter ariaDescribedByElements
     setter ariaDescription
+    setter ariaDetailsElements
     setter ariaDisabled
+    setter ariaErrorMessageElements
     setter ariaExpanded
+    setter ariaFlowToElements
     setter ariaHasPopup
     setter ariaHidden
     setter ariaInvalid
     setter ariaKeyShortcuts
     setter ariaLabel
+    setter ariaLabelledByElements
     setter ariaLevel
     setter ariaLive
     setter ariaModal
     setter ariaMultiLine
     setter ariaMultiSelectable
     setter ariaOrientation
+    setter ariaOwnsElements
     setter ariaPlaceholder
     setter ariaPosInSet
     setter ariaPressed
@@ -2112,6 +2673,7 @@
     setter ariaRoleDescription
     setter ariaRowCount
     setter ariaRowIndex
+    setter ariaRowIndexText
     setter ariaRowSpan
     setter ariaSelected
     setter ariaSetSize
@@ -2120,6 +2682,7 @@
     setter ariaValueMin
     setter ariaValueNow
     setter ariaValueText
+    setter ariaVirtualContent
     setter role
 interface EncodedAudioChunk
     attribute @@toStringTag
@@ -2204,11 +2767,16 @@
     method constructor
     method dispatchEvent
     method removeEventListener
+    method when
 interface External
     attribute @@toStringTag
     method AddSearchProvider
     method IsSearchProviderInstalled
     method constructor
+interface FaceDetector
+    attribute @@toStringTag
+    method constructor
+    method detect
 interface FeaturePolicy
     attribute @@toStringTag
     method allowedFeatures
@@ -2223,6 +2791,10 @@
     getter protocol
     getter provider
     method constructor
+interface FetchLaterResult
+    attribute @@toStringTag
+    getter activated
+    method constructor
 interface File : Blob
     attribute @@toStringTag
     getter lastModified
@@ -2262,6 +2834,14 @@
     setter onloadend
     setter onloadstart
     setter onprogress
+interface FileSystemChangeRecord
+    attribute @@toStringTag
+    getter changedHandle
+    getter relativePathComponents
+    getter relativePathMovedFrom
+    getter root
+    getter type
+    method constructor
 interface FileSystemDirectoryHandle : FileSystemHandle
     attribute @@toStringTag
     method @@asyncIterator
@@ -2284,10 +2864,18 @@
     getter kind
     getter name
     method constructor
+    method getUniqueId
     method isSameEntry
+    method move
     method queryPermission
     method remove
     method requestPermission
+interface FileSystemObserver
+    attribute @@toStringTag
+    method constructor
+    method disconnect
+    method observe
+    method unobserve
 interface FileSystemWritableFileStream : WritableStream
     attribute @@toStringTag
     getter mode
@@ -2353,7 +2941,9 @@
     method constructor
 interface FragmentDirective
     attribute @@toStringTag
+    getter items
     method constructor
+    method createSelectorDirective
 interface GPU
     attribute @@toStringTag
     getter wgslLanguageFeatures
@@ -2364,6 +2954,7 @@
     attribute @@toStringTag
     getter features
     getter info
+    getter isCompatibilityMode
     getter isFallbackAdapter
     getter limits
     method constructor
@@ -2402,6 +2993,7 @@
     getter canvas
     method configure
     method constructor
+    method getConfiguration
     method getCurrentTexture
     method unconfigure
 interface GPUCommandBuffer
@@ -2425,6 +3017,7 @@
     method popDebugGroup
     method pushDebugGroup
     method resolveQuerySet
+    method writeTimestamp
     setter label
 interface GPUCompilationInfo
     attribute @@toStringTag
@@ -2461,6 +3054,7 @@
     setter label
 interface GPUDevice : EventTarget
     attribute @@toStringTag
+    getter adapterInfo
     getter features
     getter label
     getter limits
@@ -2570,6 +3164,8 @@
     method endOcclusionQuery
     method executeBundles
     method insertDebugMarker
+    method multiDrawIndexedIndirect
+    method multiDrawIndirect
     method popDebugGroup
     method pushDebugGroup
     method setBindGroup
@@ -2632,6 +3228,7 @@
     getter maxStorageBufferBindingSize
     getter maxStorageBuffersPerShaderStage
     getter maxStorageTexturesPerShaderStage
+    getter maxSubgroupSize
     getter maxTextureArrayLayers
     getter maxTextureDimension1D
     getter maxTextureDimension2D
@@ -2642,6 +3239,7 @@
     getter maxVertexBufferArrayStride
     getter maxVertexBuffers
     getter minStorageBufferOffsetAlignment
+    getter minSubgroupSize
     getter minUniformBufferOffsetAlignment
     method constructor
 interface GPUTexture
@@ -2684,6 +3282,7 @@
     getter index
     getter mapping
     getter timestamp
+    getter touchEvents
     getter vibrationActuator
     method constructor
 interface GamepadButton
@@ -2698,10 +3297,18 @@
     method constructor
 interface GamepadHapticActuator
     attribute @@toStringTag
+    getter effects
     getter type
     method constructor
     method playEffect
     method reset
+interface GamepadTouch
+    attribute @@toStringTag
+    getter position
+    getter surfaceDimensions
+    getter surfaceId
+    getter touchId
+    method constructor
 interface Geolocation
     attribute @@toStringTag
     method clearWatch
@@ -2760,6 +3367,8 @@
     getter hostname
     getter href
     getter hreflang
+    getter interestAction
+    getter interestTargetElement
     getter name
     getter origin
     getter password
@@ -2788,6 +3397,8 @@
     setter hostname
     setter href
     setter hreflang
+    setter interestAction
+    setter interestTargetElement
     setter name
     setter password
     setter pathname
@@ -2807,12 +3418,15 @@
 interface HTMLAreaElement : HTMLElement
     attribute @@toStringTag
     getter alt
+    getter attributionSrc
     getter coords
     getter download
     getter hash
     getter host
     getter hostname
     getter href
+    getter interestAction
+    getter interestTargetElement
     getter noHref
     getter origin
     getter password
@@ -2830,12 +3444,15 @@
     method constructor
     method toString
     setter alt
+    setter attributionSrc
     setter coords
     setter download
     setter hash
     setter host
     setter hostname
     setter href
+    setter interestAction
+    setter interestTargetElement
     setter noHref
     setter password
     setter pathname
@@ -2881,6 +3498,7 @@
     getter onload
     getter onmessage
     getter onmessageerror
+    getter onmove
     getter onoffline
     getter ononline
     getter onorientationchange
@@ -2891,6 +3509,7 @@
     getter onresize
     getter onscroll
     getter onstorage
+    getter ontimezonechange
     getter onunhandledrejection
     getter onunload
     getter text
@@ -2911,6 +3530,7 @@
     setter onload
     setter onmessage
     setter onmessageerror
+    setter onmove
     setter onoffline
     setter ononline
     setter onorientationchange
@@ -2921,12 +3541,15 @@
     setter onresize
     setter onscroll
     setter onstorage
+    setter ontimezonechange
     setter onunhandledrejection
     setter onunload
     setter text
     setter vLink
 interface HTMLButtonElement : HTMLElement
     attribute @@toStringTag
+    getter command
+    getter commandForElement
     getter disabled
     getter form
     getter formAction
@@ -2934,6 +3557,8 @@
     getter formMethod
     getter formNoValidate
     getter formTarget
+    getter interestAction
+    getter interestTargetElement
     getter labels
     getter name
     getter popoverTargetAction
@@ -2947,12 +3572,16 @@
     method constructor
     method reportValidity
     method setCustomValidity
+    setter command
+    setter commandForElement
     setter disabled
     setter formAction
     setter formEnctype
     setter formMethod
     setter formNoValidate
     setter formTarget
+    setter interestAction
+    setter interestTargetElement
     setter name
     setter popoverTargetAction
     setter popoverTargetElement
@@ -2963,6 +3592,7 @@
     getter height
     getter width
     method captureStream
+    method configureHighDynamicRange
     method constructor
     method getContext
     method toBlob
@@ -3000,12 +3630,15 @@
     setter open
 interface HTMLDialogElement : HTMLElement
     attribute @@toStringTag
+    getter closedBy
     getter open
     getter returnValue
     method close
     method constructor
+    method requestClose
     method show
     method showModal
+    setter closedBy
     setter open
     setter returnValue
 interface HTMLDirectoryElement : HTMLElement
@@ -3033,6 +3666,7 @@
     getter draggable
     getter editContext
     getter enterKeyHint
+    getter focusgroup
     getter hidden
     getter inert
     getter innerText
@@ -3101,6 +3735,7 @@
     getter onmouseover
     getter onmouseup
     getter onmousewheel
+    getter onoverscroll
     getter onpaste
     getter onpause
     getter onplay
@@ -3120,6 +3755,8 @@
     getter onresize
     getter onscroll
     getter onscrollend
+    getter onscrollsnapchange
+    getter onscrollsnapchanging
     getter onsecuritypolicyviolation
     getter onseeked
     getter onseeking
@@ -3172,6 +3809,7 @@
     setter draggable
     setter editContext
     setter enterKeyHint
+    setter focusgroup
     setter hidden
     setter inert
     setter innerText
@@ -3234,6 +3872,7 @@
     setter onmouseover
     setter onmouseup
     setter onmousewheel
+    setter onoverscroll
     setter onpaste
     setter onpause
     setter onplay
@@ -3253,6 +3892,8 @@
     setter onresize
     setter onscroll
     setter onscrollend
+    setter onscrollsnapchange
+    setter onscrollsnapchanging
     setter onsecuritypolicyviolation
     setter onseeked
     setter onseeking
@@ -3403,6 +4044,7 @@
     getter onload
     getter onmessage
     getter onmessageerror
+    getter onmove
     getter onoffline
     getter ononline
     getter onorientationchange
@@ -3413,6 +4055,7 @@
     getter onresize
     getter onscroll
     getter onstorage
+    getter ontimezonechange
     getter onunhandledrejection
     getter onunload
     getter rows
@@ -3429,6 +4072,7 @@
     setter onload
     setter onmessage
     setter onmessageerror
+    setter onmove
     setter onoffline
     setter ononline
     setter onorientationchange
@@ -3439,6 +4083,7 @@
     setter onresize
     setter onscroll
     setter onstorage
+    setter ontimezonechange
     setter onunhandledrejection
     setter onunload
     setter rows
@@ -3474,6 +4119,7 @@
     getter align
     getter allow
     getter allowFullscreen
+    getter browsingTopics
     getter contentDocument
     getter contentWindow
     getter credentialless
@@ -3486,6 +4132,7 @@
     getter marginHeight
     getter marginWidth
     getter name
+    getter policy
     getter privateToken
     getter referrerPolicy
     getter sandbox
@@ -3499,6 +4146,7 @@
     setter align
     setter allow
     setter allowFullscreen
+    setter browsingTopics
     setter credentialless
     setter csp
     setter frameBorder
@@ -3508,6 +4156,7 @@
     setter marginHeight
     setter marginWidth
     setter name
+    setter policy
     setter privateToken
     setter referrerPolicy
     setter sandbox
@@ -3589,6 +4238,8 @@
     getter height
     getter incremental
     getter indeterminate
+    getter interestAction
+    getter interestTargetElement
     getter labels
     getter list
     getter max
@@ -3648,6 +4299,8 @@
     setter height
     setter incremental
     setter indeterminate
+    setter interestAction
+    setter interestTargetElement
     setter max
     setter maxLength
     setter min
@@ -3779,6 +4432,7 @@
     attribute NETWORK_IDLE
     attribute NETWORK_LOADING
     attribute NETWORK_NO_SOURCE
+    getter audioTracks
     getter autoplay
     getter buffered
     getter controls
@@ -3791,6 +4445,7 @@
     getter duration
     getter ended
     getter error
+    getter latencyHint
     getter loop
     getter mediaKeys
     getter muted
@@ -3808,6 +4463,7 @@
     getter src
     getter srcObject
     getter textTracks
+    getter videoTracks
     getter volume
     getter webkitAudioDecodedByteCount
     getter webkitVideoDecodedByteCount
@@ -3826,6 +4482,7 @@
     setter currentTime
     setter defaultMuted
     setter defaultPlaybackRate
+    setter latencyHint
     setter loop
     setter muted
     setter onencrypted
@@ -4070,6 +4727,7 @@
     getter name
     getter options
     getter required
+    getter selectedContentElement
     getter selectedIndex
     getter selectedOptions
     getter size
@@ -4094,9 +4752,13 @@
     setter multiple
     setter name
     setter required
+    setter selectedContentElement
     setter selectedIndex
     setter size
     setter value
+interface HTMLSelectedContentElement : HTMLElement
+    attribute @@toStringTag
+    method constructor
 interface HTMLSlotElement : HTMLElement
     attribute @@toStringTag
     getter name
@@ -4262,13 +4924,17 @@
 interface HTMLTemplateElement : HTMLElement
     attribute @@toStringTag
     getter content
+    getter parseparts
     getter shadowRootClonable
     getter shadowRootDelegatesFocus
     getter shadowRootMode
+    getter shadowRootSerializable
     method constructor
+    setter parseparts
     setter shadowRootClonable
     setter shadowRootDelegatesFocus
     setter shadowRootMode
+    setter shadowRootSerializable
 interface HTMLTextAreaElement : HTMLElement
     attribute @@toStringTag
     getter autocomplete
@@ -4369,19 +5035,13 @@
     getter videoHeight
     getter videoWidth
     getter webkitDecodedFrameCount
-    getter webkitDisplayingFullscreen
     getter webkitDroppedFrameCount
-    getter webkitSupportsFullscreen
     getter width
     method cancelVideoFrameCallback
     method constructor
     method getVideoPlaybackQuality
     method requestPictureInPicture
     method requestVideoFrameCallback
-    method webkitEnterFullScreen
-    method webkitEnterFullscreen
-    method webkitExitFullScreen
-    method webkitExitFullscreen
     setter disablePictureInPicture
     setter height
     setter onenterpictureinpicture
@@ -4389,6 +5049,12 @@
     setter playsInline
     setter poster
     setter width
+interface HandwritingStroke
+    attribute @@toStringTag
+    method addPoint
+    method clear
+    method constructor
+    method getPoints
 interface HashChangeEvent : Event
     attribute @@toStringTag
     getter newURL
@@ -4505,6 +5171,7 @@
     method get
     method getAll
     method getAllKeys
+    method getAllRecords
     method getKey
     method openCursor
     method openKeyCursor
@@ -4538,6 +5205,7 @@
     method get
     method getAll
     method getAllKeys
+    method getAllRecords
     method getKey
     method index
     method openCursor
@@ -4551,6 +5219,12 @@
     method constructor
     setter onblocked
     setter onupgradeneeded
+interface IDBRecord
+    attribute @@toStringTag
+    getter key
+    getter primaryKey
+    getter value
+    method constructor
 interface IDBRequest : EventTarget
     attribute @@toStringTag
     getter error
@@ -4681,6 +5355,7 @@
     getter colorSpace
     getter data
     getter height
+    getter storageFormat
     getter width
     method constructor
 interface ImageDecoder
@@ -4730,6 +5405,11 @@
     getter isComposing
     method constructor
     method getTargetRanges
+interface InterestEvent : Event
+    attribute @@toStringTag
+    getter action
+    getter invoker
+    method constructor
 interface IntersectionObserver
     attribute @@toStringTag
     getter delay
@@ -4802,16 +5482,32 @@
     setter composite
     setter pseudoElement
     setter target
+interface LanguageTranslator
+    attribute @@toStringTag
+    method constructor
+    method destroy
+    method translate
 interface LargestContentfulPaint : PerformanceEntry
     attribute @@toStringTag
     getter element
     getter id
     getter loadTime
+    getter paintTime
+    getter presentationTime
     getter renderTime
     getter size
     getter url
     method constructor
     method toJSON
+interface LaunchParams
+    attribute @@toStringTag
+    getter files
+    getter targetURL
+    method constructor
+interface LaunchQueue
+    attribute @@toStringTag
+    method constructor
+    method setConsumer
 interface LayoutShift : PerformanceEntry
     attribute @@toStringTag
     getter hadRecentInput
@@ -4904,11 +5600,18 @@
     method constructor
     method open
     setter onstatechange
+interface Magnetometer : Sensor
+    attribute @@toStringTag
+    getter x
+    getter y
+    getter z
+    method constructor
 interface MathMLElement : Element
     attribute @@toStringTag
     getter attributeStyleMap
     getter autofocus
     getter dataset
+    getter focusgroup
     getter nonce
     getter onabort
     getter onanimationend
@@ -4966,6 +5669,7 @@
     getter onmouseover
     getter onmouseup
     getter onmousewheel
+    getter onoverscroll
     getter onpaste
     getter onpause
     getter onplay
@@ -4985,6 +5689,8 @@
     getter onresize
     getter onscroll
     getter onscrollend
+    getter onscrollsnapchange
+    getter onscrollsnapchanging
     getter onsecuritypolicyviolation
     getter onseeked
     getter onseeking
@@ -5018,6 +5724,7 @@
     method constructor
     method focus
     setter autofocus
+    setter focusgroup
     setter nonce
     setter onabort
     setter onanimationend
@@ -5075,6 +5782,7 @@
     setter onmouseover
     setter onmouseup
     setter onmousewheel
+    setter onoverscroll
     setter onpaste
     setter onpause
     setter onplay
@@ -5094,6 +5802,8 @@
     setter onresize
     setter onscroll
     setter onscrollend
+    setter onscrollsnapchange
+    setter onscrollsnapchanging
     setter onsecuritypolicyviolation
     setter onseeked
     setter onseeking
@@ -5138,10 +5848,14 @@
     method toJSON
 interface MediaDevices : EventTarget
     attribute @@toStringTag
+    getter ondevicechange
     method constructor
     method enumerateDevices
+    method getDisplayMedia
     method getSupportedConstraints
     method getUserMedia
+    method setPreferredSinkId
+    setter ondevicechange
 interface MediaElementAudioSourceNode : AudioNode
     attribute @@toStringTag
     getter mediaElement
@@ -5320,6 +6034,7 @@
     getter kind
     getter label
     getter muted
+    getter onconfigurationchange
     getter onended
     getter onmute
     getter onunmute
@@ -5334,9 +6049,23 @@
     method stop
     setter contentHint
     setter enabled
+    setter onconfigurationchange
     setter onended
     setter onmute
     setter onunmute
+interface MediaStreamTrackAudioStats
+    attribute @@toStringTag
+    getter averageLatency
+    getter deliveredFrames
+    getter deliveredFramesDuration
+    getter latency
+    getter maximumLatency
+    getter minimumLatency
+    getter totalFrames
+    getter totalFramesDuration
+    method constructor
+    method resetLatency
+    method toJSON
 interface MediaStreamTrackEvent : Event
     attribute @@toStringTag
     getter track
@@ -5356,6 +6085,15 @@
     getter totalFrames
     method constructor
     method toJSON
+interface Mesh2DIndexBuffer
+    attribute @@toStringTag
+    method constructor
+interface Mesh2DUVBuffer
+    attribute @@toStringTag
+    method constructor
+interface Mesh2DVertexBuffer
+    attribute @@toStringTag
+    method constructor
 interface MessageChannel
     attribute @@toStringTag
     getter port1
@@ -5373,12 +6111,14 @@
     method initMessageEvent
 interface MessagePort : EventTarget
     attribute @@toStringTag
+    getter onclose
     getter onmessage
     getter onmessageerror
     method close
     method constructor
     method postMessage
     method start
+    setter onclose
     setter onmessage
     setter onmessageerror
 interface MimeType
@@ -5395,6 +6135,59 @@
     method constructor
     method item
     method namedItem
+interface Mojo
+    static method bindInterface
+    static method createDataPipe
+    static method createMessagePipe
+    static method createSharedBuffer
+    attribute @@toStringTag
+    attribute RESULT_ABORTED
+    attribute RESULT_ALREADY_EXISTS
+    attribute RESULT_BUSY
+    attribute RESULT_CANCELLED
+    attribute RESULT_DATA_LOSS
+    attribute RESULT_DEADLINE_EXCEEDED
+    attribute RESULT_FAILED_PRECONDITION
+    attribute RESULT_INTERNAL
+    attribute RESULT_INVALID_ARGUMENT
+    attribute RESULT_NOT_FOUND
+    attribute RESULT_OK
+    attribute RESULT_OUT_OF_RANGE
+    attribute RESULT_PERMISSION_DENIED
+    attribute RESULT_RESOURCE_EXHAUSTED
+    attribute RESULT_SHOULD_WAIT
+    attribute RESULT_UNAVAILABLE
+    attribute RESULT_UNIMPLEMENTED
+    attribute RESULT_UNKNOWN
+    method constructor
+interface MojoHandle
+    attribute @@toStringTag
+    method close
+    method constructor
+    method discardData
+    method duplicateBufferHandle
+    method mapBuffer
+    method queryData
+    method readData
+    method readMessage
+    method watch
+    method writeData
+    method writeMessage
+interface MojoInterfaceInterceptor : EventTarget
+    attribute @@toStringTag
+    getter oninterfacerequest
+    method constructor
+    method start
+    method stop
+    setter oninterfacerequest
+interface MojoInterfaceRequestEvent : Event
+    attribute @@toStringTag
+    getter handle
+    method constructor
+interface MojoWatcher
+    attribute @@toStringTag
+    method cancel
+    method constructor
 interface MouseEvent : UIEvent
     attribute @@toStringTag
     getter altKey
@@ -5423,18 +6216,6 @@
     method constructor
     method getModifierState
     method initMouseEvent
-interface MutationEvent : Event
-    attribute @@toStringTag
-    attribute ADDITION
-    attribute MODIFICATION
-    attribute REMOVAL
-    getter attrChange
-    getter attrName
-    getter newValue
-    getter prevValue
-    getter relatedNode
-    method constructor
-    method initMutationEvent
 interface MutationObserver
     attribute @@toStringTag
     method constructor
@@ -5506,7 +6287,9 @@
     getter info
     getter navigationType
     getter signal
+    getter sourceElement
     getter userInitiated
+    method commit
     method constructor
     method intercept
     method scroll
@@ -5592,10 +6375,12 @@
     getter geolocation
     getter gpu
     getter hardwareConcurrency
+    getter identity
     getter ink
     getter keyboard
     getter language
     getter languages
+    getter lockedMode
     getter locks
     getter managed
     getter maxTouchPoints
@@ -5604,8 +6389,10 @@
     getter mimeTypes
     getter onLine
     getter pdfViewerEnabled
+    getter permissions
     getter platform
     getter plugins
+    getter preferences
     getter product
     getter productSub
     getter scheduling
@@ -5622,23 +6409,33 @@
     getter webdriver
     getter webkitPersistentStorage
     getter webkitTemporaryStorage
+    method canShare
     method clearAppBadge
     method constructor
+    method createHandwritingRecognizer
     method getBattery
     method getGamepads
     method getUserMedia
+    method install
     method javaEnabled
+    method queryHandwritingRecognizer
     method requestMIDIAccess
     method requestMediaKeySystemAccess
     method sendBeacon
     method setAppBadge
+    method share
     method vibrate
     method webkitGetUserMedia
 interface NavigatorManagedData : EventTarget
     attribute @@toStringTag
     getter onmanagedconfigurationchange
     method constructor
+    method getAnnotatedAssetId
+    method getAnnotatedLocation
+    method getDirectoryId
+    method getHostname
     method getManagedConfiguration
+    method getSerialNumber
     setter onmanagedconfigurationchange
 interface NavigatorUAData
     attribute @@toStringTag
@@ -5734,6 +6531,10 @@
     method item
     method keys
     method values
+interface NodePart : Part
+    attribute @@toStringTag
+    getter node
+    method constructor
 interface NotRestoredReasonDetails
     attribute @@toStringTag
     getter reason
@@ -5749,6 +6550,28 @@
     getter url
     method constructor
     method toJSON
+interface Observable
+    static method from
+    attribute @@toStringTag
+    method catch
+    method constructor
+    method drop
+    method every
+    method filter
+    method find
+    method first
+    method flatMap
+    method forEach
+    method inspect
+    method last
+    method map
+    method reduce
+    method some
+    method subscribe
+    method switchMap
+    method take
+    method takeUntil
+    method toArray
 interface OfflineAudioCompletionEvent : Event
     attribute @@toStringTag
     getter renderedBuffer
@@ -5807,6 +6630,7 @@
     getter wordSpacing
     method arc
     method arcTo
+    method beginLayer
     method beginPath
     method bezierCurveTo
     method clearRect
@@ -5816,15 +6640,22 @@
     method createConicGradient
     method createImageData
     method createLinearGradient
+    method createMesh2DIndexBuffer
+    method createMesh2DUVBuffer
+    method createMesh2DVertexBuffer
     method createPattern
     method createRadialGradient
     method drawImage
+    method drawMesh
     method ellipse
+    method endLayer
     method fill
     method fillRect
     method fillText
+    method fillTextCluster
     method getImageData
     method getLineDash
+    method getTextureFormat
     method getTransform
     method isContextLost
     method isPointInPath
@@ -5847,6 +6678,8 @@
     method stroke
     method strokeRect
     method strokeText
+    method transferBackFromGPUTexture
+    method transferToGPUTexture
     method transform
     method translate
     setter direction
@@ -5909,12 +6742,19 @@
     attribute @@toStringTag
     getter constraint
     method constructor
+interface OverscrollEvent : Event
+    attribute @@toStringTag
+    getter deltaX
+    getter deltaY
+    method constructor
 interface PageRevealEvent : Event
     attribute @@toStringTag
+    getter viewTransition
     method constructor
 interface PageSwapEvent : Event
     attribute @@toStringTag
     getter activation
+    getter viewTransition
     method constructor
 interface PageTransitionEvent : Event
     attribute @@toStringTag
@@ -5947,6 +6787,12 @@
     setter panningModel
     setter refDistance
     setter rolloffFactor
+interface Part
+    attribute @@toStringTag
+    getter metadata
+    getter root
+    method constructor
+    method disconnect
 interface PasswordCredential : Credential
     attribute @@toStringTag
     getter iconURL
@@ -5970,11 +6816,13 @@
 interface Performance : EventTarget
     attribute @@toStringTag
     getter eventCounts
+    getter interactionCount
     getter memory
     getter navigation
     getter onresourcetimingbufferfull
     getter timeOrigin
     getter timing
+    method bind
     method clearMarks
     method clearMeasures
     method clearResourceTimings
@@ -5997,6 +6845,8 @@
     getter loadTime
     getter naturalHeight
     getter naturalWidth
+    getter paintTime
+    getter presentationTime
     getter renderTime
     getter url
     method constructor
@@ -6006,6 +6856,7 @@
     getter duration
     getter entryType
     getter name
+    getter navigationId
     getter startTime
     method constructor
     method toJSON
@@ -6022,6 +6873,8 @@
     attribute @@toStringTag
     getter blockingDuration
     getter firstUIEventTimestamp
+    getter paintTime
+    getter presentationTime
     getter renderStart
     getter scripts
     getter styleAndLayoutStart
@@ -6053,6 +6906,7 @@
 interface PerformanceNavigationTiming : PerformanceResourceTiming
     attribute @@toStringTag
     getter activationStart
+    getter confidence
     getter criticalCHRestart
     getter domComplete
     getter domContentLoadedEventEnd
@@ -6062,6 +6916,7 @@
     getter loadEventStart
     getter notRestoredReasons
     getter redirectCount
+    getter systemEntropy
     getter type
     getter unloadEventEnd
     getter unloadEventStart
@@ -6082,17 +6937,22 @@
     method getEntriesByType
 interface PerformancePaintTiming : PerformanceEntry
     attribute @@toStringTag
+    getter paintTime
+    getter presentationTime
     method constructor
+    method toJSON
 interface PerformanceResourceTiming : PerformanceEntry
     attribute @@toStringTag
     getter connectEnd
     getter connectStart
+    getter contentType
     getter decodedBodySize
     getter deliveryType
     getter domainLookupEnd
     getter domainLookupStart
     getter encodedBodySize
     getter fetchStart
+    getter finalResponseHeadersStart
     getter firstInterimResponseStart
     getter initiatorType
     getter nextHopProtocol
@@ -6155,9 +7015,29 @@
     getter unloadEventStart
     method constructor
     method toJSON
+interface PerformanceTimingConfidence
+    attribute @@toStringTag
+    getter randomizedTriggerRate
+    getter value
+    method constructor
+    method toJSON
 interface PeriodicWave
     attribute @@toStringTag
     method constructor
+interface PermissionStatus : EventTarget
+    attribute @@toStringTag
+    getter name
+    getter onchange
+    getter state
+    method constructor
+    setter onchange
+interface Permissions
+    attribute @@toStringTag
+    method constructor
+    method query
+    method request
+    method requestAll
+    method revoke
 interface PictureInPictureEvent : Event
     attribute @@toStringTag
     getter pictureInPictureWindow
@@ -6193,6 +7073,7 @@
     getter azimuthAngle
     getter height
     getter isPrimary
+    getter persistentDeviceId
     getter pointerId
     getter pointerType
     getter pressure
@@ -6209,21 +7090,29 @@
     getter hasUAVisualTransition
     getter state
     method constructor
-interface PressureObserver
-    static getter supportedSources
+interface PreferenceManager
+    attribute @@toStringTag
+    getter colorScheme
+    getter contrast
+    getter reducedData
+    getter reducedMotion
+    getter reducedTransparency
+    method constructor
+interface PreferenceObject : EventTarget
+    attribute @@toStringTag
+    getter onchange
+    getter override
+    getter validValues
+    getter value
+    method clearOverride
+    method constructor
+    method requestOverride
+    setter onchange
+interface PrivateAttribution
     attribute @@toStringTag
     method constructor
-    method disconnect
-    method observe
-    method takeRecords
-    method unobserve
-interface PressureRecord
-    attribute @@toStringTag
-    getter source
-    getter state
-    getter time
-    method constructor
-    method toJSON
+    method getEncryptedMatchKey
+    method getHelperNetworks
 interface ProcessingInstruction : CharacterData
     attribute @@toStringTag
     getter sheet
@@ -6246,6 +7135,10 @@
     getter promise
     getter reason
     method constructor
+interface ProtectedAudience
+    attribute @@toStringTag
+    method constructor
+    method queryFeatureSupport
 interface RTCCertificate
     attribute @@toStringTag
     getter expires
@@ -6280,6 +7173,7 @@
     getter onmessage
     getter onopen
     getter ordered
+    getter priority
     getter protocol
     getter readyState
     getter reliable
@@ -6314,6 +7208,7 @@
     getter timestamp
     method constructor
     method getMetadata
+    method setMetadata
     method toString
     setter data
 interface RTCEncodedVideoFrame
@@ -6323,6 +7218,7 @@
     getter type
     method constructor
     method getMetadata
+    method setMetadata
     method toString
     setter data
 interface RTCError : DOMException
@@ -6399,6 +7295,7 @@
     getter pendingLocalDescription
     getter pendingRemoteDescription
     getter remoteDescription
+    getter rtpTransport
     getter sctp
     getter signalingState
     method addIceCandidate
@@ -6448,6 +7345,13 @@
     attribute @@toStringTag
     getter candidate
     method constructor
+interface RTCRtpAcks
+    attribute @@toStringTag
+    getter explicitCongestionNotification
+    getter receivedTime
+    getter remoteSendTimestamp
+    method acks
+    method constructor
 interface RTCRtpReceiver
     static method getCapabilities
     attribute @@toStringTag
@@ -6455,6 +7359,7 @@
     getter playoutDelayHint
     getter rtcpTransport
     getter track
+    getter transform
     getter transport
     method constructor
     method createEncodedStreams
@@ -6464,20 +7369,42 @@
     method getSynchronizationSources
     setter jitterBufferTarget
     setter playoutDelayHint
+    setter transform
+interface RTCRtpScriptTransform
+    attribute @@toStringTag
+    method constructor
+interface RTCRtpSendResult
+    attribute @@toStringTag
+    getter sent
+    getter unsent
+    method constructor
+interface RTCRtpSendStream
+    attribute @@toStringTag
+    method constructor
+    method sendRtp
 interface RTCRtpSender
     static method getCapabilities
     attribute @@toStringTag
     getter dtmf
     getter rtcpTransport
     getter track
+    getter transform
     getter transport
     method constructor
     method createEncodedStreams
     method getParameters
     method getStats
+    method replaceSendStreams
     method replaceTrack
     method setParameters
     method setStreams
+    setter transform
+interface RTCRtpSent
+    attribute @@toStringTag
+    getter ackId
+    getter size
+    getter time
+    method constructor
 interface RTCRtpTransceiver
     attribute @@toStringTag
     getter currentDirection
@@ -6493,6 +7420,10 @@
     method setHeaderExtensionsToNegotiate
     method stop
     setter direction
+interface RTCRtpTransport
+    attribute @@toStringTag
+    method constructor
+    method createProcessor
 interface RTCSctpTransport : EventTarget
     attribute @@toStringTag
     getter maxChannels
@@ -6616,6 +7547,10 @@
 interface RelativeOrientationSensor : OrientationSensor
     attribute @@toStringTag
     method constructor
+interface ReportBody
+    attribute @@toStringTag
+    method constructor
+    method toJSON
 interface ReportingObserver
     attribute @@toStringTag
     method constructor
@@ -6629,6 +7564,7 @@
     getter cache
     getter credentials
     getter destination
+    getter duplex
     getter headers
     getter integrity
     getter isHistoryNavigation
@@ -6692,8 +7628,12 @@
 interface SVGAElement : SVGGraphicsElement
     attribute @@toStringTag
     getter href
+    getter interestAction
+    getter interestTargetElement
     getter target
     method constructor
+    setter interestAction
+    setter interestTargetElement
 interface SVGAngle
     attribute @@toStringTag
     attribute SVG_ANGLETYPE_DEG
@@ -6843,6 +7783,7 @@
     getter autofocus
     getter className
     getter dataset
+    getter focusgroup
     getter nonce
     getter onabort
     getter onanimationend
@@ -6900,6 +7841,7 @@
     getter onmouseover
     getter onmouseup
     getter onmousewheel
+    getter onoverscroll
     getter onpaste
     getter onpause
     getter onplay
@@ -6919,6 +7861,8 @@
     getter onresize
     getter onscroll
     getter onscrollend
+    getter onscrollsnapchange
+    getter onscrollsnapchanging
     getter onsecuritypolicyviolation
     getter onseeked
     getter onseeking
@@ -6954,6 +7898,7 @@
     method constructor
     method focus
     setter autofocus
+    setter focusgroup
     setter nonce
     setter onabort
     setter onanimationend
@@ -7011,6 +7956,7 @@
     setter onmouseover
     setter onmouseup
     setter onmousewheel
+    setter onoverscroll
     setter onpaste
     setter onpause
     setter onplay
@@ -7030,6 +7976,8 @@
     setter onresize
     setter onscroll
     setter onscrollend
+    setter onscrollsnapchange
+    setter onscrollsnapchanging
     setter onsecuritypolicyviolation
     setter onseeked
     setter onseeking
@@ -7841,10 +8789,23 @@
     getter zoomAndPan
     method constructor
     setter zoomAndPan
+interface Sanitizer
+    attribute @@toStringTag
+    method allowAttribute
+    method allowElement
+    method constructor
+    method get
+    method removeAttribute
+    method removeElement
+    method removeUnsafe
+    method replaceWithChildrenElement
+    method setComments
+    method setDataAttributes
 interface Scheduler
     attribute @@toStringTag
     method constructor
     method postTask
+    method yield
 interface Scheduling
     attribute @@toStringTag
     method constructor
@@ -7864,14 +8825,27 @@
     getter width
     method constructor
     setter onchange
+interface ScreenCaptureMediaStreamTrack : MediaStreamTrack
+    attribute @@toStringTag
+    method constructor
+    method screenDetailed
 interface ScreenDetailed : Screen
     attribute @@toStringTag
+    getter bluePrimaryX
+    getter bluePrimaryY
     getter devicePixelRatio
+    getter greenPrimaryX
+    getter greenPrimaryY
+    getter highDynamicRangeHeadroom
     getter isInternal
     getter isPrimary
     getter label
     getter left
+    getter redPrimaryX
+    getter redPrimaryY
     getter top
+    getter whitePointX
+    getter whitePointY
     method constructor
 interface ScreenDetails : EventTarget
     attribute @@toStringTag
@@ -7923,6 +8897,7 @@
     getter anchorOffset
     getter baseNode
     getter baseOffset
+    getter direction
     getter extentNode
     getter extentOffset
     getter focusNode
@@ -7939,6 +8914,7 @@
     method deleteFromDocument
     method empty
     method extend
+    method getComposedRanges
     method getRangeAt
     method modify
     method removeAllRanges
@@ -7947,6 +8923,10 @@
     method setBaseAndExtent
     method setPosition
     method toString
+interface SelectorDirective : Directive
+    attribute @@toStringTag
+    method constructor
+    method getMatchingRange
 interface Sensor : EventTarget
     attribute @@toStringTag
     getter activated
@@ -8019,23 +8999,39 @@
     getter onslotchange
     getter pictureInPictureElement
     getter pointerLockElement
+    getter referenceTarget
+    getter registry
+    getter serializable
     getter slotAssignment
     getter styleSheets
     method constructor
+    method createElement
+    method createElementNS
     method elementFromPoint
     method elementsFromPoint
     method getAnimations
-    method getInnerHTML
+    method getHTML
     method getSelection
+    method setHTML
     method setHTMLUnsafe
     setter adoptedStyleSheets
     setter fullscreenElement
     setter innerHTML
     setter onslotchange
+    setter referenceTarget
+interface SnapEvent : Event
+    attribute @@toStringTag
+    getter snapTargetBlock
+    getter snapTargetInline
+    method constructor
+interface SoftNavigationEntry : PerformanceEntry
+    attribute @@toStringTag
+    method constructor
 interface SourceBuffer : EventTarget
     attribute @@toStringTag
     getter appendWindowEnd
     getter appendWindowStart
+    getter audioTracks
     getter buffered
     getter mode
     getter onabort
@@ -8044,9 +9040,12 @@
     getter onupdateend
     getter onupdatestart
     getter timestampOffset
+    getter trackDefaults
     getter updating
+    getter videoTracks
     method abort
     method appendBuffer
+    method appendEncodedChunks
     method changeType
     method constructor
     method remove
@@ -8059,6 +9058,7 @@
     setter onupdateend
     setter onupdatestart
     setter timestampOffset
+    setter trackDefaults
 interface SourceBufferList : EventTarget
     attribute @@toStringTag
     getter length
@@ -8088,8 +9088,10 @@
     attribute @@toStringTag
     getter caches
     getter indexedDB
+    getter locks
     getter name
     method constructor
+    method durability
     method estimate
     method expires
     method getDirectory
@@ -8111,7 +9113,7 @@
     getter url
     method constructor
     method initStorageEvent
-interface StorageManager : EventTarget
+interface StorageManager
     attribute @@toStringTag
     method constructor
     method estimate
@@ -8159,6 +9161,15 @@
     attribute @@toStringTag
     getter submitter
     method constructor
+interface Subscriber
+    attribute @@toStringTag
+    getter active
+    getter signal
+    method addTeardown
+    method complete
+    method constructor
+    method error
+    method next
 interface SubtleCrypto
     attribute @@toStringTag
     method constructor
@@ -8207,6 +9218,15 @@
     getter wholeText
     method constructor
     method splitText
+interface TextCluster
+    attribute @@toStringTag
+    getter align
+    getter baseline
+    getter begin
+    getter end
+    getter x
+    getter y
+    method constructor
 interface TextDecoder
     attribute @@toStringTag
     getter encoding
@@ -8222,6 +9242,17 @@
     getter readable
     getter writable
     method constructor
+interface TextDetector
+    attribute @@toStringTag
+    method constructor
+    method detect
+interface TextDirective : SelectorDirective
+    attribute @@toStringTag
+    getter prefix
+    getter suffix
+    getter textEnd
+    getter textStart
+    method constructor
 interface TextEncoder
     attribute @@toStringTag
     getter encoding
@@ -8257,12 +9288,18 @@
     getter actualBoundingBoxLeft
     getter actualBoundingBoxRight
     getter alphabeticBaseline
+    getter emHeightAscent
+    getter emHeightDescent
     getter fontBoundingBoxAscent
     getter fontBoundingBoxDescent
     getter hangingBaseline
     getter ideographicBaseline
     getter width
     method constructor
+    method getActualBoundingBox
+    method getIndexFromOffset
+    method getSelectionRects
+    method getTextClusters
 interface TextTrack : EventTarget
     attribute @@toStringTag
     getter activeCues
@@ -8326,6 +9363,10 @@
     method constructor
     method end
     method start
+interface TimestampTrigger
+    attribute @@toStringTag
+    getter timestamp
+    method constructor
 interface ToggleEvent : Event
     attribute @@toStringTag
     getter newState
@@ -8362,6 +9403,19 @@
     method @@iterator
     method constructor
     method item
+interface TrackDefault
+    attribute @@toStringTag
+    getter byteStreamTrackID
+    getter kinds
+    getter label
+    getter language
+    getter type
+    method constructor
+interface TrackDefaultList
+    attribute @@toStringTag
+    getter length
+    method @@iterator
+    method constructor
 interface TrackEvent : Event
     attribute @@toStringTag
     getter track
@@ -8384,6 +9438,11 @@
     getter propertyName
     getter pseudoElement
     method constructor
+interface Translation
+    attribute @@toStringTag
+    method canTranslate
+    method constructor
+    method createTranslator
 interface TreeWalker
     attribute @@toStringTag
     getter currentNode
@@ -8400,16 +9459,19 @@
     method previousSibling
     setter currentNode
 interface TrustedHTML
+    static method fromLiteral
     attribute @@toStringTag
     method constructor
     method toJSON
     method toString
 interface TrustedScript
+    static method fromLiteral
     attribute @@toStringTag
     method constructor
     method toJSON
     method toString
 interface TrustedScriptURL
+    static method fromLiteral
     attribute @@toStringTag
     method constructor
     method toJSON
@@ -8426,6 +9488,7 @@
     getter defaultPolicy
     getter emptyHTML
     getter emptyScript
+    getter onbeforecreatepolicy
     method constructor
     method createPolicy
     method getAttributeType
@@ -8434,6 +9497,7 @@
     method isHTML
     method isScript
     method isScriptURL
+    setter onbeforecreatepolicy
 interface UIEvent : Event
     attribute @@toStringTag
     getter detail
@@ -8445,6 +9509,7 @@
 interface URL
     static method canParse
     static method createObjectURL
+    static method parse
     static method revokeObjectURL
     attribute @@toStringTag
     getter hash
@@ -8473,6 +9538,7 @@
     setter search
     setter username
 interface URLPattern
+    static method compareComponent
     attribute @@toStringTag
     getter hasRegExpGroups
     getter hash
@@ -8513,6 +9579,7 @@
     getter align
     getter line
     getter position
+    getter region
     getter size
     getter snapToLines
     getter text
@@ -8522,10 +9589,30 @@
     setter align
     setter line
     setter position
+    setter region
     setter size
     setter snapToLines
     setter text
     setter vertical
+interface VTTRegion
+    attribute @@toStringTag
+    getter id
+    getter lines
+    getter regionAnchorX
+    getter regionAnchorY
+    getter scroll
+    getter viewportAnchorX
+    getter viewportAnchorY
+    getter width
+    method constructor
+    setter id
+    setter lines
+    setter regionAnchorX
+    setter regionAnchorY
+    setter scroll
+    setter viewportAnchorX
+    setter viewportAnchorY
+    setter width
 interface ValidityState
     attribute @@toStringTag
     getter badInput
@@ -8572,8 +9659,13 @@
     method constructor
     method encode
     method flush
+    method getAllFrameBuffers
     method reset
     setter ondequeue
+interface VideoEncoderBuffer
+    attribute @@toStringTag
+    getter id
+    method constructor
 interface VideoFrame
     attribute @@toStringTag
     getter codedHeight
@@ -8583,7 +9675,9 @@
     getter displayHeight
     getter displayWidth
     getter duration
+    getter flip
     getter format
+    getter rotation
     getter timestamp
     getter visibleRect
     method allocationSize
@@ -8591,6 +9685,7 @@
     method close
     method constructor
     method copyTo
+    method metadata
 interface VideoPlaybackQuality
     attribute @@toStringTag
     getter corruptedVideoFrames
@@ -8598,6 +9693,36 @@
     getter droppedVideoFrames
     getter totalVideoFrames
     method constructor
+interface VideoTrack
+    attribute @@toStringTag
+    getter id
+    getter kind
+    getter label
+    getter language
+    getter selected
+    getter sourceBuffer
+    method constructor
+    setter selected
+interface VideoTrackGenerator
+    attribute @@toStringTag
+    getter muted
+    getter track
+    getter writable
+    method constructor
+    setter muted
+interface VideoTrackList : EventTarget
+    attribute @@toStringTag
+    getter length
+    getter onaddtrack
+    getter onchange
+    getter onremovetrack
+    getter selectedIndex
+    method @@iterator
+    method constructor
+    method getTrackById
+    setter onaddtrack
+    setter onchange
+    setter onremovetrack
 interface ViewTimeline : ScrollTimeline
     attribute @@toStringTag
     getter endOffset
@@ -8648,6 +9773,7 @@
     getter offsetTop
     getter onresize
     getter onscroll
+    getter onscrollend
     getter pageLeft
     getter pageTop
     getter scale
@@ -8655,6 +9781,7 @@
     method constructor
     setter onresize
     setter onscroll
+    setter onscrollend
 interface WGSLLanguageFeatures
     attribute @@toStringTag
     getter size
@@ -9284,6 +10411,7 @@
     method clearStencil
     method clientWaitSync
     method colorMask
+    method commit
     method compileShader
     method compressedTexImage2D
     method compressedTexImage3D
@@ -9485,23 +10613,26 @@
     getter size
     getter type
     method constructor
-interface WebGLBuffer
+interface WebGLBuffer : WebGLObject
     attribute @@toStringTag
     method constructor
 interface WebGLContextEvent : Event
     attribute @@toStringTag
     getter statusMessage
     method constructor
-interface WebGLFramebuffer
+interface WebGLFramebuffer : WebGLObject
     attribute @@toStringTag
     method constructor
-interface WebGLProgram
+interface WebGLObject
     attribute @@toStringTag
     method constructor
-interface WebGLQuery
+interface WebGLProgram : WebGLObject
     attribute @@toStringTag
     method constructor
-interface WebGLRenderbuffer
+interface WebGLQuery : WebGLObject
+    attribute @@toStringTag
+    method constructor
+interface WebGLRenderbuffer : WebGLObject
     attribute @@toStringTag
     method constructor
 interface WebGLRenderingContext
@@ -9830,6 +10961,7 @@
     method clearDepth
     method clearStencil
     method colorMask
+    method commit
     method compileShader
     method compressedTexImage2D
     method compressedTexSubImage2D
@@ -9950,10 +11082,10 @@
     method viewport
     setter drawingBufferColorSpace
     setter unpackColorSpace
-interface WebGLSampler
+interface WebGLSampler : WebGLObject
     attribute @@toStringTag
     method constructor
-interface WebGLShader
+interface WebGLShader : WebGLObject
     attribute @@toStringTag
     method constructor
 interface WebGLShaderPrecisionFormat
@@ -9962,19 +11094,19 @@
     getter rangeMax
     getter rangeMin
     method constructor
-interface WebGLSync
+interface WebGLSync : WebGLObject
     attribute @@toStringTag
     method constructor
-interface WebGLTexture
+interface WebGLTexture : WebGLObject
     attribute @@toStringTag
     method constructor
-interface WebGLTransformFeedback
+interface WebGLTransformFeedback : WebGLObject
     attribute @@toStringTag
     method constructor
 interface WebGLUniformLocation
     attribute @@toStringTag
     method constructor
-interface WebGLVertexArrayObject
+interface WebGLVertexArrayObject : WebGLObject
     attribute @@toStringTag
     method constructor
 interface WebKitCSSMatrix : DOMMatrixReadOnly
@@ -10089,6 +11221,7 @@
     method constructor
     method createBidirectionalStream
     method createUnidirectionalStream
+    method getStats
 interface WebTransportBidirectionalStream
     attribute @@toStringTag
     getter readable
@@ -10258,6 +11391,21 @@
     method constructor
     method iterateNext
     method snapshotItem
+interface XRCompositionLayer : XRLayer
+    attribute @@toStringTag
+    getter blendTextureSourceAlpha
+    getter chromaticAberrationCorrection
+    getter forceMonoPresentation
+    getter layout
+    getter mipLevels
+    getter needsRedraw
+    getter opacity
+    method constructor
+    method destroy
+    setter blendTextureSourceAlpha
+    setter chromaticAberrationCorrection
+    setter forceMonoPresentation
+    setter opacity
 interface XRDOMOverlayState
     attribute @@toStringTag
     getter type
@@ -10265,6 +11413,17 @@
 interface XRLayer : EventTarget
     attribute @@toStringTag
     method constructor
+interface XRProjectionLayer : XRCompositionLayer
+    attribute @@toStringTag
+    getter deltaPose
+    getter fixedFoveation
+    getter ignoreDepthValues
+    getter textureArrayLength
+    getter textureHeight
+    getter textureWidth
+    method constructor
+    setter deltaPose
+    setter fixedFoveation
 interface XRWebGLBinding
     attribute @@toStringTag
     method constructor
@@ -10323,6 +11482,7 @@
     getter pendingLocalDescription
     getter pendingRemoteDescription
     getter remoteDescription
+    getter rtpTransport
     getter sctp
     getter signalingState
     method addIceCandidate
@@ -10420,6 +11580,7 @@
 interface webkitURL
     static method canParse
     static method createObjectURL
+    static method parse
     static method revokeObjectURL
     attribute @@toStringTag
     getter hash
@@ -10451,6 +11612,7 @@
 namespace CSS
     attribute @@toStringTag
     getter highlights
+    getter layoutWorklet
     getter paintWorklet
     method Hz
     method Q
@@ -10584,15 +11746,16 @@
     setter memory
 [GLOBAL OBJECT]
     attribute android
-    attribute android_webview_media_token_provider_listener
     attribute awConsole
     attribute globalThis
     attribute propertyNamesInGlobal
+    getter ai
     getter caches
     getter clientInformation
     getter closed
     getter cookieStore
     getter credentialless
+    getter crossOriginEmbedderPolicy
     getter crossOriginIsolated
     getter crypto
     getter customElements
@@ -10607,6 +11770,7 @@
     getter innerHeight
     getter innerWidth
     getter isSecureContext
+    getter launchQueue
     getter length
     getter localStorage
     getter location
@@ -10682,9 +11846,11 @@
     getter onmouseover
     getter onmouseup
     getter onmousewheel
+    getter onmove
     getter onoffline
     getter ononline
     getter onorientationchange
+    getter onoverscroll
     getter onpagehide
     getter onpagereveal
     getter onpageshow
@@ -10709,6 +11875,8 @@
     getter onresize
     getter onscroll
     getter onscrollend
+    getter onscrollsnapchange
+    getter onscrollsnapchanging
     getter onsearch
     getter onsecuritypolicyviolation
     getter onseeked
@@ -10722,6 +11890,7 @@
     getter onsubmit
     getter onsuspend
     getter ontimeupdate
+    getter ontimezonechange
     getter ontoggle
     getter ontouchcancel
     getter ontouchend
@@ -10751,6 +11920,7 @@
     getter parent
     getter performance
     getter personalbar
+    getter privateAttribution
     getter scheduler
     getter screen
     getter screenLeft
@@ -10767,6 +11937,7 @@
     getter styleMedia
     getter toolbar
     getter top
+    getter translation
     getter trustedTypes
     getter visualViewport
     getter window
@@ -10784,15 +11955,21 @@
     method confirm
     method createImageBitmap
     method fetch
+    method fetchLater
     method find
     method focus
     method getComputedStyle
     method getScreenDetails
     method getSelection
     method matchMedia
+    method maximize
+    method minimize
     method moveBy
     method moveTo
     method open
+    method openDatabase
+    method popinContextType
+    method popinContextTypesSupported
     method postMessage
     method print
     method prompt
@@ -10803,15 +11980,21 @@
     method requestIdleCallback
     method resizeBy
     method resizeTo
+    method restore
     method scroll
     method scrollBy
     method scrollTo
     method setInterval
+    method setResizable
     method setTimeout
+    method showDirectoryPicker
+    method showOpenFilePicker
+    method showSaveFilePicker
     method stop
     method structuredClone
     method webkitCancelAnimationFrame
     method webkitRequestAnimationFrame
+    setter ai
     setter clientInformation
     setter devicePixelRatio
     setter event
@@ -10892,9 +12075,11 @@
     setter onmouseover
     setter onmouseup
     setter onmousewheel
+    setter onmove
     setter onoffline
     setter ononline
     setter onorientationchange
+    setter onoverscroll
     setter onpagehide
     setter onpagereveal
     setter onpageshow
@@ -10919,6 +12104,8 @@
     setter onresize
     setter onscroll
     setter onscrollend
+    setter onscrollsnapchange
+    setter onscrollsnapchanging
     setter onsearch
     setter onsecuritypolicyviolation
     setter onseeked
@@ -10932,6 +12119,7 @@
     setter onsubmit
     setter onsuspend
     setter ontimeupdate
+    setter ontimezonechange
     setter ontoggle
     setter ontouchcancel
     setter ontouchend
@@ -10959,6 +12147,7 @@
     setter parent
     setter performance
     setter personalbar
+    setter privateAttribution
     setter scheduler
     setter screen
     setter screenLeft
@@ -10972,5 +12161,6 @@
     setter status
     setter statusbar
     setter toolbar
+    setter translation
     setter visualViewport
 TEST FINISHED
diff --git a/ash/capture_mode/capture_mode_controller.cc b/ash/capture_mode/capture_mode_controller.cc
index c877bbb..14660cc3 100644
--- a/ash/capture_mode/capture_mode_controller.cc
+++ b/ash/capture_mode/capture_mode_controller.cc
@@ -356,6 +356,14 @@
       kCaptureModeIcon);
 }
 
+// Shows a toast informing the user that text has been copied to clipboard.
+void ShowTextCopiedToast() {
+  // TODO(crbug.com/375967525): Finalize and translate the toast string.
+  ToastManager::Get()->Show(ToastData(kCaptureModeTextCopiedToastId,
+                                      ToastCatalogName::kCaptureModeTextCopied,
+                                      u"Text copied to clipboard"));
+}
+
 // Copies the bitmap representation of the given |image| to the clipboard.
 void CopyImageToClipboard(const gfx::Image& image) {
   ui::ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste)
@@ -672,14 +680,6 @@
                                 /*default_value=*/false);
 }
 
-// static
-void CaptureModeController::ShowTextCopiedToast() {
-  // TODO(crbug.com/375967525): Finalize and translate the toast string.
-  ToastManager::Get()->Show(ToastData(kCaptureModeTextCopiedToastId,
-                                      ToastCatalogName::kCaptureModeTextCopied,
-                                      u"Text copied to clipboard"));
-}
-
 SearchResultsPanel* CaptureModeController::GetSearchResultsPanel() const {
   return search_results_panel_widget_
              ? views::AsViewClass<SearchResultsPanel>(
diff --git a/ash/capture_mode/capture_mode_controller.h b/ash/capture_mode/capture_mode_controller.h
index c3d8e7a..47323d5 100644
--- a/ash/capture_mode/capture_mode_controller.h
+++ b/ash/capture_mode/capture_mode_controller.h
@@ -100,9 +100,6 @@
 
   static void RegisterProfilePrefs(PrefRegistrySimple* registry);
 
-  // Shows a toast informing the user that text has been copied to clipboard.
-  static void ShowTextCopiedToast();
-
   CaptureModeCameraController* camera_controller() {
     return camera_controller_.get();
   }
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 7d79e629..91538d36 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -1067,7 +1067,7 @@
 BASE_FEATURE(kFocusMode, "FocusMode", base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Enables or disables Focus Mode YTM integration on ChromeOS.
-BASE_FEATURE(kFocusModeYTM, "FocusModeYTM", base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kFocusModeYTM, "FocusModeYTM", base::FEATURE_ENABLED_BY_DEFAULT);
 
 // If enabled, makes the Projector app use server side speech
 // recognition instead of on-device speech recognition.
@@ -2462,6 +2462,12 @@
 // controls whether the projector app uses updated styles and ui components.
 BASE_FEATURE(kProjectorGm3, "ProjectorGm3", base::FEATURE_ENABLED_BY_DEFAULT);
 
+// Controls whether the projector app uses the latest endpoint for retrieving
+// playback urls.
+BASE_FEATURE(kProjectorUseDVSPlaybackEndpoint,
+             "ProjectorUseDVSPlaybackEndpoint",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Controls whether to show promise icons during app installations.
 BASE_FEATURE(kPromiseIcons, "PromiseIcons", base::FEATURE_ENABLED_BY_DEFAULT);
 
@@ -4365,6 +4371,10 @@
   return base::FeatureList::IsEnabled(kProjectorGm3);
 }
 
+bool IsProjectorUseDVSPlaybackEndpointEnabled() {
+  return base::FeatureList::IsEnabled(kProjectorUseDVSPlaybackEndpoint);
+}
+
 bool IsQuickDimEnabled() {
   return base::FeatureList::IsEnabled(kQuickDim) && switches::HasHps();
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index bc292bad..465568c 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -794,6 +794,8 @@
 BASE_DECLARE_FEATURE(kProjectorUseUSMForS3);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kProjectorDynamicColors);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kProjectorGm3);
+COMPONENT_EXPORT(ASH_CONSTANTS)
+BASE_DECLARE_FEATURE(kProjectorUseDVSPlaybackEndpoint);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kPromiseIcons);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kPromiseIconsWebApps);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kQuickDim);
@@ -1316,6 +1318,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorUseUSMForS3Enabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorDynamicColorsEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorGm3Enabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorUseDVSPlaybackEndpointEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsQuickDimEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsRenderArcNotificationsByChromeEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS)
diff --git a/ash/constants/ash_switches.cc b/ash/constants/ash_switches.cc
index b08de80..59fbb8f3 100644
--- a/ash/constants/ash_switches.cc
+++ b/ash/constants/ash_switches.cc
@@ -777,9 +777,6 @@
 const char kKioskSplashScreenMinTimeSeconds[] =
     "kiosk-splash-screen-min-time-seconds";
 
-// When this flag is set, the lacros-availability policy is ignored.
-const char kLacrosAvailabilityIgnore[] = "lacros-availability-ignore";
-
 // If this switch is set, then ash-chrome will exec the lacros-chrome binary
 // from the indicated path rather than from component updater. Note that the
 // path should be to a directory that contains a binary named 'chrome'.
diff --git a/ash/constants/ash_switches.h b/ash/constants/ash_switches.h
index 63e51d1..788d56d 100644
--- a/ash/constants/ash_switches.h
+++ b/ash/constants/ash_switches.h
@@ -251,7 +251,6 @@
 extern const char kInstallLogFastUploadForTests[];
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const char kKioskSplashScreenMinTimeSeconds[];
-COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kLacrosAvailabilityIgnore[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kLacrosChromePath[];
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const char kLacrosSelectionPolicyIgnore[];
diff --git a/ash/constants/notifier_catalogs.h b/ash/constants/notifier_catalogs.h
index 329b653..3763151 100644
--- a/ash/constants/notifier_catalogs.h
+++ b/ash/constants/notifier_catalogs.h
@@ -328,7 +328,9 @@
   kCopyImageToClipboardAction = 56,
   kCaptureModeTextCopied = 57,
   kCoralSavedGroupLimitMax = 58,
-  kMaxValue = kCoralSavedGroupLimitMax
+  kScannerActionSuccess = 59,
+  kScannerActionFailure = 60,
+  kMaxValue = kScannerActionFailure
 };
 
 }  // namespace ash
diff --git a/ash/frame_sink/frame_sink_holder.cc b/ash/frame_sink/frame_sink_holder.cc
index ee905a1..577cfb5 100644
--- a/ash/frame_sink/frame_sink_holder.cc
+++ b/ash/frame_sink/frame_sink_holder.cc
@@ -29,12 +29,14 @@
 
 FrameSinkHolder::FrameSinkHolder(
     std::unique_ptr<cc::LayerTreeFrameSink> frame_sink,
-    const GetCompositorFrameCallback get_compositor_frame_callback,
-    const OnFirstFrameRequestedCallback on_first_frame_requested_callback)
+    GetCompositorFrameCallback get_compositor_frame_callback,
+    OnFirstFrameRequestedCallback on_first_frame_requested_callback,
+    OnFrameSinkLost on_frame_sink_lost_callback)
     : frame_sink_(std::move(frame_sink)),
       get_compositor_frame_callback_(std::move(get_compositor_frame_callback)),
       on_first_frame_requested_callback_(
-          std::move(on_first_frame_requested_callback)) {
+          std::move(on_first_frame_requested_callback)),
+      on_frame_sink_lost_callback_(std::move(on_frame_sink_lost_callback)) {
   frame_sink_->BindToClient(this);
 }
 
@@ -291,6 +293,8 @@
   resource_manager().LostExportedResources();
   if (WaitingToScheduleDelete()) {
     ScheduleDelete();
+  } else {
+    std::move(on_frame_sink_lost_callback_).Run();
   }
 }
 
diff --git a/ash/frame_sink/frame_sink_holder.h b/ash/frame_sink/frame_sink_holder.h
index 9fac44b..3d996c3d 100644
--- a/ash/frame_sink/frame_sink_holder.h
+++ b/ash/frame_sink/frame_sink_holder.h
@@ -51,14 +51,20 @@
           bool auto_update,
           const gfx::Size& last_submitted_frame_size,
           float last_submitted_frame_dsf)>;
+
   // Refer to declaration of `FrameSinkHost::OnFirstFrameRequested` for a
   // detailed comment.
   using OnFirstFrameRequestedCallback = base::RepeatingCallback<void()>;
 
+  // Refer to declaration of `FrameSinkHost::OnFrameSinkLost` for a detailed
+  // comment.
+  using OnFrameSinkLost = base::OnceCallback<void()>;
+
   FrameSinkHolder(
       std::unique_ptr<cc::LayerTreeFrameSink> frame_sink,
       GetCompositorFrameCallback get_compositor_frame_callback,
-      OnFirstFrameRequestedCallback on_first_frame_requested_callback);
+      OnFirstFrameRequestedCallback on_first_frame_requested_callback,
+      OnFrameSinkLost on_frame_sink_lost_callback);
 
   FrameSinkHolder(const FrameSinkHolder&) = delete;
   FrameSinkHolder& operator=(const FrameSinkHolder&) = delete;
@@ -202,6 +208,9 @@
   // frame for the first time.
   OnFirstFrameRequestedCallback on_first_frame_requested_callback_;
 
+  // The callback invoked when the connection to `frame_sink_` is lost.
+  OnFrameSinkLost on_frame_sink_lost_callback_;
+
   // Observation of the root window to which this holder becomes an observer to
   // extend its lifespan till all the in-flight resource to display compositor
   // are reclaimed.
diff --git a/ash/frame_sink/frame_sink_holder_unittest.cc b/ash/frame_sink/frame_sink_holder_unittest.cc
index 9a8d12d..f287132 100644
--- a/ash/frame_sink/frame_sink_holder_unittest.cc
+++ b/ash/frame_sink/frame_sink_holder_unittest.cc
@@ -79,8 +79,6 @@
     return frame;
   }
 
-  void OnFirstFrameRequested() {}
-
   void SetFrameResources(std::vector<viz::ResourceId> frame_resource) {
     latest_frame_resources_ = std::move(frame_resource);
   }
@@ -126,8 +124,8 @@
         std::move(layer_tree_frame_sink),
         base::BindRepeating(&TestFrameFactory::CreateCompositorFrame,
                             base::Unretained(frame_factory_.get())),
-        base::BindRepeating(&TestFrameFactory::OnFirstFrameRequested,
-                            base::Unretained(frame_factory_.get())));
+        /*on_first_frame_requested_callback=*/base::DoNothing(),
+        /*on_frame_sink_lost_callback=*/base::DoNothing());
 
     holder_weak_ptr_ = frame_sink_holder_->GetWeakPtr();
   }
diff --git a/ash/frame_sink/frame_sink_host.cc b/ash/frame_sink/frame_sink_host.cc
index 9d88eb7..1b12bc8b 100644
--- a/ash/frame_sink/frame_sink_host.cc
+++ b/ash/frame_sink/frame_sink_host.cc
@@ -58,7 +58,8 @@
       base::BindRepeating(&FrameSinkHost::CreateCompositorFrame,
                           base::Unretained(this)),
       base::BindRepeating(&FrameSinkHost::OnFirstFrameRequested,
-                          base::Unretained(this)));
+                          base::Unretained(this)),
+      base::BindOnce(&FrameSinkHost::OnFrameSinkLost, base::Unretained(this)));
 }
 
 void FrameSinkHost::SetHostWindow(aura::Window* host_window) {
@@ -123,4 +124,16 @@
 
 void FrameSinkHost::OnFirstFrameRequested() {}
 
+void FrameSinkHost::OnFrameSinkLost() {
+  frame_sink_holder_.reset();
+  InitFrameSinkHolder(host_window(), host_window()->CreateLayerTreeFrameSink());
+
+  // Since some implementations of FrameSinkHost rarely update the surface,
+  // submit a compositor frame in order to update the surface. Otherwise,
+  // host_window will show a white surface instead.
+  const gfx::Rect& content_rect = host_window_->bounds();
+  const gfx::Rect& damage_rect = content_rect;
+  UpdateSurface(content_rect, damage_rect, /*synchronous_draw=*/true);
+}
+
 }  // namespace ash
diff --git a/ash/frame_sink/frame_sink_host.h b/ash/frame_sink/frame_sink_host.h
index d48406e..2af88a4 100644
--- a/ash/frame_sink/frame_sink_host.h
+++ b/ash/frame_sink/frame_sink_host.h
@@ -124,6 +124,10 @@
       aura::Window* host_window,
       std::unique_ptr<cc::LayerTreeFrameSink> layer_tree_frame_sink);
 
+  // Callback invoked when the connection to `LayerTreeFrameSink` is lost. (i.e
+  // gpu crashed, host_window closes etc)
+  void OnFrameSinkLost();
+
   // Observation to track the lifetime of `host_window_`.
   base::ScopedObservation<aura::Window, aura::WindowObserver>
       host_window_observation_{this};
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index 9b992b0..3d5c251 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -308,6 +308,8 @@
     "scanner/scanner_action.h",
     "scanner/scanner_delegate.h",
     "scanner/scanner_enums.h",
+    "scanner/scanner_feedback_info.cc",
+    "scanner/scanner_feedback_info.h",
     "scanner/scanner_profile_scoped_delegate.h",
     "scanner/scanner_system_state.cc",
     "scanner/scanner_system_state.h",
diff --git a/ash/public/cpp/ash_web_view.h b/ash/public/cpp/ash_web_view.h
index 518fcd1..0a80bd6 100644
--- a/ash/public/cpp/ash_web_view.h
+++ b/ash/public/cpp/ash_web_view.h
@@ -11,9 +11,9 @@
 #include "base/observer_list_types.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/gfx/geometry/rounded_corners_f.h"
-#include "url/gurl.h"
 #include "ui/views/view.h"
 
+class GURL;
 enum class WindowOpenDisposition;
 
 namespace ash {
@@ -74,10 +74,6 @@
     // Used to override the Media Controls source title. Empty strings will
     // trigger default parent behavior.
     std::string source_title;
-
-    // URL to open when AshWebView contents are activated but the widget is not
-    // activatable. Empty GURLs will trigger default parent behavior.
-    GURL activation_url;
   };
 
   // An observer which receives AshWebView events.
diff --git a/ash/public/cpp/scanner/scanner_delegate.h b/ash/public/cpp/scanner/scanner_delegate.h
index 6bf7c46..0f82b4e 100644
--- a/ash/public/cpp/scanner/scanner_delegate.h
+++ b/ash/public/cpp/scanner/scanner_delegate.h
@@ -9,6 +9,7 @@
 
 namespace ash {
 
+struct ScannerFeedbackInfo;
 class ScannerProfileScopedDelegate;
 
 // Provides access to the browser from //ash/scanner.
@@ -22,7 +23,7 @@
   //
   // TODO: b/382562555 - Consider taking in a `context::BrowserContext*` here
   // to ensure that the dialog is opened for the correct user.
-  virtual void OpenFeedbackDialog() = 0;
+  virtual void OpenFeedbackDialog(ScannerFeedbackInfo feedback_info) = 0;
 };
 
 }  // namespace ash
diff --git a/ash/public/cpp/scanner/scanner_feedback_info.cc b/ash/public/cpp/scanner/scanner_feedback_info.cc
new file mode 100644
index 0000000..ed097d2
--- /dev/null
+++ b/ash/public/cpp/scanner/scanner_feedback_info.cc
@@ -0,0 +1,30 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/public/cpp/scanner/scanner_feedback_info.h"
+
+#include <string>
+#include <utility>
+
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+
+namespace ash {
+
+ScannerFeedbackInfo::ScannerFeedbackInfo(
+    std::string action_details,
+    scoped_refptr<base::RefCountedMemory> screenshot)
+    : action_details(std::move(action_details)),
+      screenshot(std::move(screenshot)) {}
+
+ScannerFeedbackInfo::ScannerFeedbackInfo(const ScannerFeedbackInfo&) = default;
+ScannerFeedbackInfo& ScannerFeedbackInfo::operator=(
+    const ScannerFeedbackInfo&) = default;
+ScannerFeedbackInfo::ScannerFeedbackInfo(ScannerFeedbackInfo&&) = default;
+ScannerFeedbackInfo& ScannerFeedbackInfo::operator=(ScannerFeedbackInfo&&) =
+    default;
+
+ScannerFeedbackInfo::~ScannerFeedbackInfo() = default;
+
+}  // namespace ash
diff --git a/ash/public/cpp/scanner/scanner_feedback_info.h b/ash/public/cpp/scanner/scanner_feedback_info.h
new file mode 100644
index 0000000..8516266f
--- /dev/null
+++ b/ash/public/cpp/scanner/scanner_feedback_info.h
@@ -0,0 +1,33 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_PUBLIC_CPP_SCANNER_SCANNER_FEEDBACK_INFO_H_
+#define ASH_PUBLIC_CPP_SCANNER_SCANNER_FEEDBACK_INFO_H_
+
+#include <string>
+
+#include "ash/public/cpp/ash_public_export.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+
+namespace ash {
+
+struct ASH_PUBLIC_EXPORT ScannerFeedbackInfo {
+  std::string action_details;
+  scoped_refptr<base::RefCountedMemory> screenshot;
+
+  ScannerFeedbackInfo(std::string action_details,
+                      scoped_refptr<base::RefCountedMemory> screenshot);
+
+  ScannerFeedbackInfo(const ScannerFeedbackInfo&);
+  ScannerFeedbackInfo& operator=(const ScannerFeedbackInfo&);
+  ScannerFeedbackInfo(ScannerFeedbackInfo&&);
+  ScannerFeedbackInfo& operator=(ScannerFeedbackInfo&&);
+
+  ~ScannerFeedbackInfo();
+};
+
+}  // namespace ash
+
+#endif  // ASH_PUBLIC_CPP_SCANNER_SCANNER_FEEDBACK_INFO_H_
diff --git a/ash/quick_insert/search/quick_insert_search_request.cc b/ash/quick_insert/search/quick_insert_search_request.cc
index c909e50..d74aa0b 100644
--- a/ash/quick_insert/search/quick_insert_search_request.cc
+++ b/ash/quick_insert/search/quick_insert_search_request.cc
@@ -59,7 +59,7 @@
 constexpr auto kGoogleCorpGotoHosts = base::MakeFixedFlatSet<std::string_view>(
     {"goto2.corp.google.com", "goto.corp.google.com", "goto.google.com", "go"});
 
-constexpr int kMaxGifsToSearch = 50;
+constexpr int kMaxGifsToSearch = 25;
 
 const char* SearchSourceToHistogram(QuickInsertSearchSource source) {
   switch (source) {
diff --git a/ash/scanner/fake_scanner_delegate.h b/ash/scanner/fake_scanner_delegate.h
index 1190cf9..733da3e 100644
--- a/ash/scanner/fake_scanner_delegate.h
+++ b/ash/scanner/fake_scanner_delegate.h
@@ -6,6 +6,7 @@
 #define ASH_SCANNER_FAKE_SCANNER_DELEGATE_H_
 
 #include "ash/public/cpp/scanner/scanner_delegate.h"
+#include "ash/public/cpp/scanner/scanner_feedback_info.h"
 #include "ash/scanner/fake_scanner_profile_scoped_delegate.h"
 
 namespace ash {
@@ -20,7 +21,7 @@
 
   // ScannerDelegate:
   ScannerProfileScopedDelegate* GetProfileScopedDelegate() override;
-  void OpenFeedbackDialog() override {}
+  void OpenFeedbackDialog(ScannerFeedbackInfo feedback_info) override {}
 
  private:
   FakeScannerProfileScopedDelegate fake_scanner_profile_scoped_delegate_;
diff --git a/ash/scanner/scanner_command_delegate_impl.cc b/ash/scanner/scanner_command_delegate_impl.cc
index 505190c7..c9eed39 100644
--- a/ash/scanner/scanner_command_delegate_impl.cc
+++ b/ash/scanner/scanner_command_delegate_impl.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include <utility>
 
-#include "ash/capture_mode/capture_mode_controller.h"
 #include "ash/public/cpp/new_window_delegate.h"
 #include "ash/public/cpp/scanner/scanner_profile_scoped_delegate.h"
 #include "base/check_deref.h"
@@ -43,10 +42,6 @@
     std::unique_ptr<ui::ClipboardData> data) {
   CHECK_DEREF(ui::ClipboardNonBacked::GetForCurrentThread())
       .WriteClipboardData(std::move(data));
-
-  // TODO: crbug.com/382182688 - Use a Scanner action toast instead of the
-  // capture mode copy text toast.
-  CaptureModeController::ShowTextCopiedToast();
 }
 
 base::WeakPtr<ScannerCommandDelegate> ScannerCommandDelegateImpl::GetWeakPtr() {
diff --git a/ash/scanner/scanner_controller.cc b/ash/scanner/scanner_controller.cc
index 3417434..a04bbdbd 100644
--- a/ash/scanner/scanner_controller.cc
+++ b/ash/scanner/scanner_controller.cc
@@ -13,6 +13,8 @@
 #include "ash/public/cpp/scanner/scanner_delegate.h"
 #include "ash/public/cpp/scanner/scanner_enums.h"
 #include "ash/public/cpp/scanner/scanner_profile_scoped_delegate.h"
+#include "ash/public/cpp/system/toast_data.h"
+#include "ash/public/cpp/system/toast_manager.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/scanner/scanner_command_delegate_impl.h"
 #include "ash/scanner/scanner_session.h"
@@ -30,6 +32,9 @@
 constexpr char kScannerActionNotificationId[] = "scanner_action_notification";
 constexpr char kScannerNotifierId[] = "ash.scanner";
 
+constexpr char kScannerActionSuccessToastId[] = "scanner_action_success";
+constexpr char kScannerActionFailureToastId[] = "scanner_action_failure";
+
 // Shows an action progress notification. Note that this will remove the
 // previous action notification if there is one.
 void ShowActionProgressNotification() {
@@ -58,11 +63,27 @@
 
 // Should be called when an action finishes execution.
 void OnActionFinished(bool success) {
+  // Remove the action progress notification.
   message_center::MessageCenter::Get()->RemoveNotification(
       kScannerActionNotificationId,
       /*by_user=*/false);
-  // TODO: crbug.com/382182688 - Show an error message if the action was not
-  // successful.
+
+  if (success) {
+    // TODO: crbug.com/382182688 - The action success text should depend on the
+    // type of action executed.
+    constexpr char16_t kPlaceholderActionSuccessText[] = u"Action Finished";
+    // TODO: crbug.com/383925780 - Add feedback mechanism to the toast.
+    ToastManager::Get()->Show(ToastData(kScannerActionSuccessToastId,
+                                        ToastCatalogName::kScannerActionSuccess,
+                                        kPlaceholderActionSuccessText));
+  } else {
+    // TODO: crbug.com/378582420 - The action failure text should depend on the
+    // type of action attempted.
+    constexpr char16_t kPlaceholderActionFailureText[] = u"Action Failed";
+    ToastManager::Get()->Show(ToastData(kScannerActionFailureToastId,
+                                        ToastCatalogName::kScannerActionFailure,
+                                        kPlaceholderActionFailureText));
+  }
 }
 
 }  // namespace
diff --git a/ash/scanner/scanner_controller_unittest.cc b/ash/scanner/scanner_controller_unittest.cc
index f93fe25..c112ff9 100644
--- a/ash/scanner/scanner_controller_unittest.cc
+++ b/ash/scanner/scanner_controller_unittest.cc
@@ -13,6 +13,7 @@
 #include "ash/public/cpp/scanner/scanner_delegate.h"
 #include "ash/public/cpp/scanner/scanner_enums.h"
 #include "ash/public/cpp/scanner/scanner_system_state.h"
+#include "ash/public/cpp/system/toast_manager.h"
 #include "ash/scanner/fake_scanner_profile_scoped_delegate.h"
 #include "ash/scanner/scanner_action_view_model.h"
 #include "ash/shell.h"
@@ -39,6 +40,9 @@
 using ::testing::SizeIs;
 using ::testing::WithArg;
 
+constexpr char kScannerActionSuccessToastId[] = "scanner_action_success";
+constexpr char kScannerActionFailureToastId[] = "scanner_action_failure";
+
 FakeScannerProfileScopedDelegate* GetFakeScannerProfileScopedDelegate(
     ScannerController& scanner_controller) {
   return static_cast<FakeScannerProfileScopedDelegate*>(
@@ -162,6 +166,65 @@
               IsEmpty());
 }
 
+TEST_F(ScannerControllerTest, ShowsToastAfterActionSuccess) {
+  base::test::TestFuture<std::vector<ScannerActionViewModel>> actions_future;
+  ScannerController* scanner_controller = Shell::Get()->scanner_controller();
+  ASSERT_TRUE(scanner_controller);
+  EXPECT_TRUE(scanner_controller->StartNewSession());
+  manta::proto::ScannerOutput output;
+  output.add_objects()->add_actions()->mutable_new_event()->set_title(
+      "Event title");
+  FakeScannerProfileScopedDelegate& fake_profile_scoped_delegate =
+      *GetFakeScannerProfileScopedDelegate(*scanner_controller);
+  // Mock a successful action.
+  EXPECT_CALL(fake_profile_scoped_delegate, FetchActionsForImage)
+      .WillOnce(RunOnceCallback<1>(
+          std::make_unique<manta::proto::ScannerOutput>(output),
+          manta::MantaStatus()));
+  EXPECT_CALL(fake_profile_scoped_delegate, FetchActionDetailsForImage)
+      .WillOnce(RunOnceCallback<2>(
+          std::make_unique<manta::proto::ScannerOutput>(output),
+          manta::MantaStatus{.status_code = manta::MantaStatusCode::kOk}));
+
+  // Fetch an action and execute it.
+  scanner_controller->FetchActionsForImage(/*jpeg_bytes=*/nullptr,
+                                           actions_future.GetCallback());
+  std::vector<ScannerActionViewModel> actions = actions_future.Take();
+  ASSERT_THAT(actions, SizeIs(1));
+  scanner_controller->ExecuteAction(actions[0]);
+
+  EXPECT_TRUE(ToastManager::Get()->IsToastShown(kScannerActionSuccessToastId));
+}
+
+TEST_F(ScannerControllerTest, ShowsToastAfterActionFailure) {
+  base::test::TestFuture<std::vector<ScannerActionViewModel>> actions_future;
+  ScannerController* scanner_controller = Shell::Get()->scanner_controller();
+  ASSERT_TRUE(scanner_controller);
+  EXPECT_TRUE(scanner_controller->StartNewSession());
+  auto output = std::make_unique<manta::proto::ScannerOutput>();
+  output->add_objects()->add_actions()->mutable_new_event()->set_title(
+      "Event title");
+  FakeScannerProfileScopedDelegate& fake_profile_scoped_delegate =
+      *GetFakeScannerProfileScopedDelegate(*scanner_controller);
+  EXPECT_CALL(fake_profile_scoped_delegate, FetchActionsForImage)
+      .WillOnce(RunOnceCallback<1>(std::move(output), manta::MantaStatus()));
+  // Mock a failure to fetch action details.
+  EXPECT_CALL(fake_profile_scoped_delegate, FetchActionDetailsForImage)
+      .WillOnce(RunOnceCallback<2>(
+          /*output=*/nullptr,
+          manta::MantaStatus{.status_code =
+                                 manta::MantaStatusCode::kBackendFailure}));
+
+  // Fetch an action and try to execute it.
+  scanner_controller->FetchActionsForImage(/*jpeg_bytes=*/nullptr,
+                                           actions_future.GetCallback());
+  std::vector<ScannerActionViewModel> actions = actions_future.Take();
+  ASSERT_THAT(actions, SizeIs(1));
+  scanner_controller->ExecuteAction(actions[0]);
+
+  EXPECT_TRUE(ToastManager::Get()->IsToastShown(kScannerActionFailureToastId));
+}
+
 }  // namespace
 
 }  // namespace ash
diff --git a/ash/system/audio/audio_effects_controller.cc b/ash/system/audio/audio_effects_controller.cc
index 53324ca6..1469408 100644
--- a/ash/system/audio/audio_effects_controller.cc
+++ b/ash/system/audio/audio_effects_controller.cc
@@ -29,8 +29,7 @@
   if (CrasAudioHandler::Get()->GetAudioEffectDlcs() == std::nullopt) {
     return false;
   }
-  return CrasAudioHandler::Get()->IsStyleTransferSupportedForDevice(
-      CrasAudioHandler::Get()->GetPrimaryActiveInputNode());
+  return CrasAudioHandler::Get()->style_transfer_supported();
 }
 
 // Vc can only support either noise cancellation or style transfer. So we skip
diff --git a/ash/system/focus_mode/focus_mode_controller.cc b/ash/system/focus_mode/focus_mode_controller.cc
index 09dc887..f4feec7 100644
--- a/ash/system/focus_mode/focus_mode_controller.cc
+++ b/ash/system/focus_mode/focus_mode_controller.cc
@@ -30,10 +30,8 @@
 #include "ash/system/status_area_widget.h"
 #include "ash/system/toast/anchored_nudge_manager_impl.h"
 #include "ash/system/unified/unified_system_tray.h"
-#include "base/check_op.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/rand_util.h"
-#include "base/strings/strcat.h"
 #include "base/time/time.h"
 #include "chromeos/ash/components/audio/sounds.h"
 #include "chromeos/ash/components/audio/system_sounds_delegate.h"
@@ -57,12 +55,6 @@
 
 constexpr base::TimeDelta kEndingMomentBounceAnimationDelay = base::Minutes(1);
 
-// YouTube Music API playlist name prefix.
-constexpr std::string_view kPlaylistIdPrefix = "playlists/";
-constexpr std::string_view kBasePlaylistUrl =
-    "https://music.youtube.com/playlist?list=";
-constexpr std::string_view kYouTubeMusicUrl = "https://music.youtube.com/";
-
 bool IsQuietModeOnSetByFocusMode() {
   auto* message_center = message_center::MessageCenter::Get();
   return message_center->IsQuietMode() &&
@@ -151,25 +143,6 @@
   std::move(callback).Run(task);
 }
 
-// Returns the direct URL to view info for the associated YouTube Music
-// `playlist`.
-GURL GetYouTubeMusicPlaylistUrl(focus_mode_util::SelectedPlaylist playlist) {
-  CHECK_EQ(playlist.type, focus_mode_util::SoundType::kYouTubeMusic);
-
-  if (playlist.id.starts_with(kPlaylistIdPrefix)) {
-    // Strip the prefix from `playlist.id` to get the actual playlist id and
-    // construct the URL.
-    return GURL(base::StrCat(
-        {kBasePlaylistUrl, playlist.id.substr(kPlaylistIdPrefix.length())}));
-  }
-
-  // The expected api playlist name should have the prefix "playlists/". Check
-  // the playlists api documentation:
-  // https://developers.google.com/youtube/mediaconnect/reference/rest/v1/playlists#Playlist"
-  LOG(WARNING) << "YTM playlist name format is invalid";
-  return GURL(kYouTubeMusicUrl);
-}
-
 }  // namespace
 
 FocusModeController::FocusModeController(
@@ -904,14 +877,6 @@
   web_view_params.source_title =
       focus_mode_util::GetSourceTitleForMediaControls(
           focus_mode_sounds_controller_->selected_playlist());
-  // Provide the playlist source URL to show for when users click on the media
-  // controls view.
-  if (focus_mode_sounds_controller_->selected_playlist().type ==
-      focus_mode_util::SoundType::kYouTubeMusic) {
-    web_view_params.activation_url = GetYouTubeMusicPlaylistUrl(
-        focus_mode_sounds_controller_->selected_playlist());
-  }
-
   focus_mode_media_view_ = media_widget_->SetContentsView(
       AshWebViewFactory::Get()->Create(web_view_params));
   focus_mode_media_view_->Navigate(GURL(chrome::kChromeUIFocusModeMediaURL));
diff --git a/ash/system/focus_mode/focus_mode_util.cc b/ash/system/focus_mode/focus_mode_util.cc
index cf83ba1..9c049dc 100644
--- a/ash/system/focus_mode/focus_mode_util.cc
+++ b/ash/system/focus_mode/focus_mode_util.cc
@@ -46,8 +46,6 @@
                        u"☑"),
 };
 
-constexpr const char* kYouTubeMusicUrl = "music.youtube.com";
-
 }  // namespace
 
 SelectedPlaylist::SelectedPlaylist() = default;
@@ -145,10 +143,10 @@
     return "";
   }
 
-  return playlist.type == SoundType::kYouTubeMusic
-             ? kYouTubeMusicUrl
-             : l10n_util::GetStringUTF8(
-                   IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_SOUNDSCAPE_BUTTON);
+  return l10n_util::GetStringUTF8(
+      playlist.type == SoundType::kYouTubeMusic
+          ? IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_YOUTUBE_MUSIC_BUTTON
+          : IDS_ASH_STATUS_TRAY_FOCUS_MODE_SOUNDS_SOUNDSCAPE_BUTTON);
 }
 
 std::u16string GetCongratulatoryText(const size_t index) {
diff --git a/ash/system/focus_mode/focus_mode_util_unittest.cc b/ash/system/focus_mode/focus_mode_util_unittest.cc
index 5ee7c29..b58bd8e 100644
--- a/ash/system/focus_mode/focus_mode_util_unittest.cc
+++ b/ash/system/focus_mode/focus_mode_util_unittest.cc
@@ -22,8 +22,7 @@
   SelectedPlaylist selected_playlist;
   selected_playlist.id = "id0";
   selected_playlist.type = SoundType::kYouTubeMusic;
-  EXPECT_EQ(GetSourceTitleForMediaControls(selected_playlist),
-            "music.youtube.com");
+  EXPECT_EQ(GetSourceTitleForMediaControls(selected_playlist), "YouTube Music");
 }
 
 // Verify the Soundscape source string.
diff --git a/ash/webui/common/resources/sea_pen/sea_pen_samples_element.html b/ash/webui/common/resources/sea_pen/sea_pen_samples_element.html
index fec5c54..aa1ea3a 100644
--- a/ash/webui/common/resources/sea_pen/sea_pen_samples_element.html
+++ b/ash/webui/common/resources/sea_pen/sea_pen_samples_element.html
@@ -44,6 +44,8 @@
     items="[[samples]]"
     as="sample"
     grid
+    aria-label="$i18n{seaPenFreeformAriaLabelSamplePrompts}"
+    aria-setsize="6"
     role="listbox">
   <template>
     <div class="container">
diff --git a/ash/webui/common/resources/sea_pen/sea_pen_suggestions_element.html b/ash/webui/common/resources/sea_pen/sea_pen_suggestions_element.html
index 8e718ef..2678914 100644
--- a/ash/webui/common/resources/sea_pen/sea_pen_suggestions_element.html
+++ b/ash/webui/common/resources/sea_pen/sea_pen_suggestions_element.html
@@ -51,6 +51,8 @@
       id="suggestionSelector"
       selected="0"
       selected-item="{{ironSelectedSuggestion_}}"
+      aria-label="$i18n{seaPenFreeformAriaLabelSuggestions}"
+      aria-setsize$="[[selectableSuggestions_.length]]"
       role="radiogroup">
     <template is="dom-repeat" items="[[selectableSuggestions_]]" as="suggestion">
       <cr-button
diff --git a/ash/webui/common/sea_pen_resources.cc b/ash/webui/common/sea_pen_resources.cc
index da362c4..bf29059e 100644
--- a/ash/webui/common/sea_pen_resources.cc
+++ b/ash/webui/common/sea_pen_resources.cc
@@ -86,6 +86,10 @@
        IDS_SEA_PEN_INTRODUCTION_DIALOG_FIRST_PARAGRAPH},
       {"seaPenFreeformIntroductionDialogFirstParagraph",
        IDS_SEA_PEN_FREEFORM_INTRODUCTION_DIALOG_FIRST_PARAGRAPH},
+      {"seaPenFreeformAriaLabelSamplePrompts",
+       IDS_SEA_PEN_FREEFORM_ARIA_LABEL_SAMPLE_PROMPTS},
+      {"seaPenFreeformAriaLabelSuggestions",
+       IDS_SEA_PEN_FREEFORM_ARIA_LABEL_SUGGESTIONS},
 
       {"seaPenDismissError", IDS_PERSONALIZATION_APP_DISMISS},
       {"ariaLabelLoading", IDS_PERSONALIZATION_APP_ARIA_LABEL_LOADING},
diff --git a/ash/webui/projector_app/projector_oauth_token_fetcher.cc b/ash/webui/projector_app/projector_oauth_token_fetcher.cc
index 08c1c81..f0fb421a 100644
--- a/ash/webui/projector_app/projector_oauth_token_fetcher.cc
+++ b/ash/webui/projector_app/projector_oauth_token_fetcher.cc
@@ -4,6 +4,7 @@
 
 #include "ash/webui/projector_app/projector_oauth_token_fetcher.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/projector/projector_controller.h"
 #include "ash/webui/projector_app/projector_app_client.h"
 #include "base/containers/contains.h"
@@ -29,6 +30,12 @@
 }
 
 OAuth2AccessTokenManager::ScopeSet GetScopeSet() {
+  if (ash::features::IsProjectorUseDVSPlaybackEndpointEnabled()) {
+    return OAuth2AccessTokenManager::ScopeSet{
+        GaiaConstants::kDriveOAuth2Scope,
+        GaiaConstants::kDriveReadOnlyOAuth2Scope};
+  }
+
   return OAuth2AccessTokenManager::ScopeSet{GaiaConstants::kDriveOAuth2Scope};
 }
 
diff --git a/ash/webui/projector_app/projector_xhr_sender.cc b/ash/webui/projector_app/projector_xhr_sender.cc
index 4707bf7..8c83a4b 100644
--- a/ash/webui/projector_app/projector_xhr_sender.cc
+++ b/ash/webui/projector_app/projector_xhr_sender.cc
@@ -12,6 +12,7 @@
 #include "ash/webui/projector_app/public/mojom/projector_types.mojom.h"
 #include "base/containers/flat_map.h"
 #include "base/functional/bind.h"
+#include "base/strings/pattern.h"
 #include "base/strings/string_util.h"
 #include "components/signin/public/identity_manager/access_token_info.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
@@ -105,8 +106,19 @@
     "https://drive.google.com/u/0/get_video_info",
     "https://translation.googleapis.com/language/translate/v2"};
 
+bool IsDVSPlaybackUrl(const std::string& url) {
+  return base::MatchPattern(url,
+                            "https://staging-workspacevideo-pa.googleapis.com/"
+                            "v1/drive/media/*/playback");
+}
+
 // Return true if the url matches the allowed URL prefix.
 bool IsUrlAllowlisted(const std::string& url) {
+  if (features::IsProjectorUseDVSPlaybackEndpointEnabled() &&
+      IsDVSPlaybackUrl(url)) {
+    return true;
+  }
+
   for (auto* urlPrefix : kUrlAllowlist) {
     if (base::StartsWith(url, urlPrefix, base::CompareCase::SENSITIVE))
       return true;
diff --git a/ash/webui/scanner_feedback_ui/BUILD.gn b/ash/webui/scanner_feedback_ui/BUILD.gn
index d487db2..ed28cc4 100644
--- a/ash/webui/scanner_feedback_ui/BUILD.gn
+++ b/ash/webui/scanner_feedback_ui/BUILD.gn
@@ -8,6 +8,10 @@
 
 static_library("scanner_feedback_ui") {
   sources = [
+    "scanner_feedback_browser_context_data.cc",
+    "scanner_feedback_browser_context_data.h",
+    "scanner_feedback_page_handler.cc",
+    "scanner_feedback_page_handler.h",
     "scanner_feedback_untrusted_ui.cc",
     "scanner_feedback_untrusted_ui.h",
     "url_constants.h",
@@ -21,7 +25,10 @@
   ]
 
   public_deps = [
+    "//ash/public/cpp",
     "//ash/webui/common:chrome_os_webui_config",
+    "//ash/webui/scanner_feedback_ui/mojom",
+    "//ui/web_dialogs",
     "//ui/webui",
   ]
 }
diff --git a/ash/webui/scanner_feedback_ui/DEPS b/ash/webui/scanner_feedback_ui/DEPS
new file mode 100644
index 0000000..2aa5189
--- /dev/null
+++ b/ash/webui/scanner_feedback_ui/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+ui/web_dialogs",
+]
diff --git a/ash/webui/scanner_feedback_ui/mojom/BUILD.gn b/ash/webui/scanner_feedback_ui/mojom/BUILD.gn
new file mode 100644
index 0000000..e91847fe
--- /dev/null
+++ b/ash/webui/scanner_feedback_ui/mojom/BUILD.gn
@@ -0,0 +1,15 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/chromeos/ui_mode.gni")
+import("//mojo/public/tools/bindings/mojom.gni")
+
+assert(is_chromeos_ash, "Scanner is ash-chrome only")
+
+mojom("mojom") {
+  sources = [ "scanner_feedback_ui.mojom" ]
+
+  public_deps = [ "//url/mojom:url_mojom_gurl" ]
+  webui_module_path = "/"
+}
diff --git a/ash/webui/scanner_feedback_ui/mojom/OWNERS b/ash/webui/scanner_feedback_ui/mojom/OWNERS
new file mode 100644
index 0000000..08850f4
--- /dev/null
+++ b/ash/webui/scanner_feedback_ui/mojom/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/ash/webui/scanner_feedback_ui/mojom/scanner_feedback_ui.mojom b/ash/webui/scanner_feedback_ui/mojom/scanner_feedback_ui.mojom
new file mode 100644
index 0000000..785b975
--- /dev/null
+++ b/ash/webui/scanner_feedback_ui/mojom/scanner_feedback_ui.mojom
@@ -0,0 +1,38 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module ash.mojom.scanner_feedback_ui;
+
+import "url/mojom/url.mojom";
+
+// Encompasses all fixed additional information to attach to a given feedback
+// report. Will be displayed to the user in the feedback form.
+struct FeedbackInfo {
+  // A human-readible string showing the details of the action performed.
+  // Will realistically be <50kB.
+  // The contents are derived from a Google-owned server response.
+  string action_details;
+  // A `chrome-untrusted://scanner-feedback/screenshots/UNGUESSABLETOKEN.png`
+  // URL which, when accessed, will display the screenshot.
+  // The contents are a (possibly resized) screen capture from Ash.
+  url.mojom.Url screenshot_url;
+};
+
+// Handles communication from `chrome-untrusted://scanner-feedback` to the
+// trusted browser process.
+interface PageHandler {
+  // Gets the `FeedbackInfo` for this page handler.
+  // If no feedback information was attached to this page handler (for example,
+  // if `chrome-untrusted://scanner-feedback` was manually opened in the
+  // browser) calling this will kill the renderer process by reporting a bad
+  // message.
+  GetFeedbackInfo() => (FeedbackInfo feedback_info);
+
+  // Requests for the dialog displaying this page to be closed.
+  // May not immediately close the dialog or the page handler.
+  //
+  // If no "close dialog" callback was attached to this page handler, calling
+  // this will kill the renderer process by reporting a bad message.
+  CloseDialog();
+};
diff --git a/ash/webui/scanner_feedback_ui/resources/BUILD.gn b/ash/webui/scanner_feedback_ui/resources/BUILD.gn
index d5ed3e2..e2bbbb20 100644
--- a/ash/webui/scanner_feedback_ui/resources/BUILD.gn
+++ b/ash/webui/scanner_feedback_ui/resources/BUILD.gn
@@ -17,10 +17,16 @@
 
   web_component_files = [ "app.ts" ]
 
+  mojo_files_deps =
+      [ "//ash/webui/scanner_feedback_ui/mojom:mojom_ts__generator" ]
+
+  mojo_files = [ "$root_gen_dir/ash/webui/scanner_feedback_ui/mojom/scanner_feedback_ui.mojom-webui.ts" ]
+
   ts_deps = [
     "//third_party/cros-components:cros_components_ts",
     "//third_party/polymer/v3_0:library",
     "//ui/webui/resources/cr_components/color_change_listener:build_ts",
+    "//ui/webui/resources/mojo:build_ts",
   ]
 
   ts_composite = true
diff --git a/ash/webui/scanner_feedback_ui/resources/app.html b/ash/webui/scanner_feedback_ui/resources/app.html
index eac703c..b8eb533 100644
--- a/ash/webui/scanner_feedback_ui/resources/app.html
+++ b/ash/webui/scanner_feedback_ui/resources/app.html
@@ -1,4 +1,9 @@
-<mako-orca-feedback
-  string-source="[[stringSource]]"
-  open-url="[[openUrl]]"
-  ></mako-orca-feedback>
+<template is="dom-if" if="[[!isEmpty(screenshotUrl)]]">
+  <mako-orca-feedback
+    string-source="[[stringSource]]"
+    open-url="[[openUrl]]"
+    extra-info-callback="[[extraInfoCallback]]"
+    extra-image="[[screenshotUrl]]"
+    revert-to-previous-screen="[[revertToPreviousScreen]]"
+    ></mako-orca-feedback>
+</template>
diff --git a/ash/webui/scanner_feedback_ui/resources/app.ts b/ash/webui/scanner_feedback_ui/resources/app.ts
index e015b43..1d21c2e 100644
--- a/ash/webui/scanner_feedback_ui/resources/app.ts
+++ b/ash/webui/scanner_feedback_ui/resources/app.ts
@@ -9,6 +9,13 @@
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {getTemplate} from './app.html.js';
+import {PageHandler} from './scanner_feedback_ui.mojom-webui.js';
+
+const PAGE_HANDLER_REMOTE = PageHandler.getRemote();
+
+const FEEDBACK_INFO_PROMISE = PAGE_HANDLER_REMOTE.getFeedbackInfo().then(
+    ({feedbackInfo}) => feedbackInfo);
+
 
 // `StringSource` is not exported from orca-feedback.js, so get a reference to
 // it via `OrcaFeedback`.
@@ -51,14 +58,35 @@
       // Private properties:
       stringSource: Object,
       openUrl: Object,
+      extraInfoCallback: Object,
+      screenshotUrl: String,
+      revertToPeviousScreen: Object,
     };
   }
 
+  // Used in template:
   private readonly stringSource = STRING_SOURCE;
   private readonly openUrl = (url: string) => {
     window.open(url, '_blank');
-    // TODO: b/382562555 - Close the dialog after opening the URL.
+    this.revertToPreviousScreen();
   };
+  private readonly extraInfoCallback = () =>
+      FEEDBACK_INFO_PROMISE.then(feedbackInfo => feedbackInfo.actionDetails);
+  private screenshotUrl = '';
+  private readonly revertToPreviousScreen = () =>
+      PAGE_HANDLER_REMOTE.closeDialog();
+
+  constructor() {
+    super();
+    FEEDBACK_INFO_PROMISE.then(feedbackInfo => {
+      this.screenshotUrl = feedbackInfo.screenshotUrl.url;
+    });
+  }
+
+  // Used in computed bindings:
+  private isEmpty(string: string): boolean {
+    return string === '';
+  }
 }
 
 declare global {
diff --git a/ash/webui/scanner_feedback_ui/scanner_feedback_browser_context_data.cc b/ash/webui/scanner_feedback_ui/scanner_feedback_browser_context_data.cc
new file mode 100644
index 0000000..07e55d8
--- /dev/null
+++ b/ash/webui/scanner_feedback_ui/scanner_feedback_browser_context_data.cc
@@ -0,0 +1,101 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/webui/scanner_feedback_ui/scanner_feedback_browser_context_data.h"
+
+#include <map>
+#include <memory>
+#include <utility>
+
+#include "ash/public/cpp/scanner/scanner_feedback_info.h"
+#include "base/compiler_specific.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
+#include "base/memory/weak_ptr.h"
+#include "base/supports_user_data.h"
+#include "base/unguessable_token.h"
+#include "content/public/browser/browser_context.h"
+
+namespace ash {
+
+namespace {
+
+const void* const kBrowserContextKey = &kBrowserContextKey;
+
+struct BrowserContextData : public base::SupportsUserData::Data {
+  std::map<base::UnguessableToken, ScannerFeedbackInfo> feedback_info_map;
+
+  static BrowserContextData* GetForBrowserContext(
+      content::BrowserContext& browser_context LIFETIME_BOUND) {
+    base::SupportsUserData::Data* data =
+        browser_context.GetUserData(&kBrowserContextKey);
+
+    // Can be nullptr.
+    return static_cast<BrowserContextData*>(data);
+  }
+
+  static BrowserContextData& CreateOrGetForBrowserContext(
+      content::BrowserContext& browser_context LIFETIME_BOUND) {
+    BrowserContextData* current_data = GetForBrowserContext(browser_context);
+
+    if (current_data != nullptr) {
+      return *current_data;
+    }
+
+    auto new_data = std::make_unique<BrowserContextData>();
+    BrowserContextData& new_data_ref = *new_data;
+    browser_context.SetUserData(&kBrowserContextKey, std::move(new_data));
+    // Still valid, as the `unique_ptr` - now owned by the browser context -
+    // still points to the same heap-allocated memory.
+    return new_data_ref;
+  }
+};
+
+}  // namespace
+
+base::ScopedClosureRunner SetScannerFeedbackInfoForBrowserContext(
+    content::BrowserContext& browser_context,
+    base::UnguessableToken id,
+    ScannerFeedbackInfo feedback_info) {
+  auto& data =
+      BrowserContextData::CreateOrGetForBrowserContext(browser_context);
+  data.feedback_info_map.insert({id, std::move(feedback_info)});
+
+  return base::ScopedClosureRunner(base::BindOnce(
+      [](base::WeakPtr<content::BrowserContext> weak_browser_context,
+         base::UnguessableToken id) {
+        if (weak_browser_context == nullptr) {
+          // The browser context is already gone - no need to clean up.
+          return;
+        }
+
+        auto* data =
+            BrowserContextData::GetForBrowserContext(*weak_browser_context);
+        if (data == nullptr) {
+          // The browser context's user data was cleared.
+          return;
+        }
+
+        data->feedback_info_map.erase(id);
+      },
+      browser_context.GetWeakPtr(), id));
+}
+
+ScannerFeedbackInfo* GetScannerFeedbackInfoForBrowserContext(
+    content::BrowserContext& browser_context LIFETIME_BOUND,
+    base::UnguessableToken id) {
+  auto* data = BrowserContextData::GetForBrowserContext(browser_context);
+  if (data == nullptr) {
+    return nullptr;
+  }
+
+  auto it = data->feedback_info_map.find(id);
+  if (it == data->feedback_info_map.end()) {
+    return nullptr;
+  }
+
+  return &it->second;
+}
+
+}  // namespace ash
diff --git a/ash/webui/scanner_feedback_ui/scanner_feedback_browser_context_data.h b/ash/webui/scanner_feedback_ui/scanner_feedback_browser_context_data.h
new file mode 100644
index 0000000..4479bdf2
--- /dev/null
+++ b/ash/webui/scanner_feedback_ui/scanner_feedback_browser_context_data.h
@@ -0,0 +1,42 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_WEBUI_SCANNER_FEEDBACK_UI_SCANNER_FEEDBACK_BROWSER_CONTEXT_DATA_H_
+#define ASH_WEBUI_SCANNER_FEEDBACK_UI_SCANNER_FEEDBACK_BROWSER_CONTEXT_DATA_H_
+
+#include "ash/public/cpp/scanner/scanner_feedback_info.h"
+#include "base/compiler_specific.h"
+#include "base/functional/callback_helpers.h"
+#include "base/unguessable_token.h"
+
+// Functions for storing and retrieving `ScannerFeedbackInfo` on a browser
+// context, keyed by an `base::UnguessableToken` ID. Allows access to a WebUI's
+// `ScannerFeedbackInfo` from both the page handler (which stores the ID) as
+// well as any request filters, provided the ID is encoded in the URL.
+
+namespace content {
+class BrowserContext;
+}
+
+namespace ash {
+
+// Sets `feedback_info` keyed by `id` in `browser_context`.
+// `feedback_info` can later be retrieved from the `Get` function below.
+// Returns an object that, when destructed, also destructs `feedback_info` to
+// prevent memory leaks.
+base::ScopedClosureRunner SetScannerFeedbackInfoForBrowserContext(
+    content::BrowserContext& browser_context,
+    base::UnguessableToken id,
+    ScannerFeedbackInfo feedback_info);
+
+// Gets a reference to a `ScannerFeedbackInfo` keyed by `id` in
+// `browser_context`, set by the `Set` function above.
+// If no `ScannerFeedbackInfo` exists for `id`, returns nullptr.
+ScannerFeedbackInfo* GetScannerFeedbackInfoForBrowserContext(
+    content::BrowserContext& browser_context LIFETIME_BOUND,
+    base::UnguessableToken id);
+
+}  // namespace ash
+
+#endif  // ASH_WEBUI_SCANNER_FEEDBACK_UI_SCANNER_FEEDBACK_BROWSER_CONTEXT_DATA_H_
diff --git a/ash/webui/scanner_feedback_ui/scanner_feedback_page_handler.cc b/ash/webui/scanner_feedback_ui/scanner_feedback_page_handler.cc
new file mode 100644
index 0000000..f342288
--- /dev/null
+++ b/ash/webui/scanner_feedback_ui/scanner_feedback_page_handler.cc
@@ -0,0 +1,69 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/webui/scanner_feedback_ui/scanner_feedback_page_handler.h"
+
+#include <utility>
+
+#include "ash/public/cpp/scanner/scanner_feedback_info.h"
+#include "ash/webui/scanner_feedback_ui/mojom/scanner_feedback_ui.mojom.h"
+#include "ash/webui/scanner_feedback_ui/scanner_feedback_browser_context_data.h"
+#include "ash/webui/scanner_feedback_ui/url_constants.h"
+#include "base/strings/strcat.h"
+#include "base/unguessable_token.h"
+#include "content/public/browser/browser_context.h"
+#include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+
+namespace ash {
+
+ScannerFeedbackPageHandler::ScannerFeedbackPageHandler(
+    content::BrowserContext& browser_context)
+    : id_(base::UnguessableToken::Create()),
+      browser_context_(browser_context) {}
+
+ScannerFeedbackPageHandler::~ScannerFeedbackPageHandler() = default;
+
+void ScannerFeedbackPageHandler::Bind(
+    mojo::PendingReceiver<mojom::scanner_feedback_ui::PageHandler> receiver) {
+  if (receiver_.is_bound()) {
+    receiver_.reset();
+  }
+  receiver_.Bind(std::move(receiver));
+}
+
+void ScannerFeedbackPageHandler::GetFeedbackInfo(
+    GetFeedbackInfoCallback callback) {
+  auto feedback_info_ptr = mojom::scanner_feedback_ui::FeedbackInfo::New();
+  ScannerFeedbackInfo* feedback_info =
+      GetScannerFeedbackInfoForBrowserContext(*browser_context_, id_);
+  if (feedback_info == nullptr) {
+    mojo::ReportBadMessage("No feedback info was set.");
+    // The callback still needs to be called with a valid `FeedbackInfoPtr`
+    // before the renderer can be killed.
+    std::move(callback).Run(std::move(feedback_info_ptr));
+    return;
+  }
+
+  feedback_info_ptr->action_details = feedback_info->action_details;
+  feedback_info_ptr->screenshot_url = GURL(base::StrCat({
+      kScannerFeedbackUntrustedUrl,
+      kScannerFeedbackScreenshotPrefix,
+      id_.ToString(),
+      kScannerFeedbackScreenshotSuffix,
+  }));
+
+  std::move(callback).Run(std::move(feedback_info_ptr));
+}
+
+void ScannerFeedbackPageHandler::CloseDialog() {
+  if (close_dialog_callback_.is_null()) {
+    mojo::ReportBadMessage(
+        "No close dialog callback was attached to the page handler.");
+    return;
+  }
+  close_dialog_callback_.Run();
+}
+
+}  // namespace ash
diff --git a/ash/webui/scanner_feedback_ui/scanner_feedback_page_handler.h b/ash/webui/scanner_feedback_ui/scanner_feedback_page_handler.h
new file mode 100644
index 0000000..fd739aae
--- /dev/null
+++ b/ash/webui/scanner_feedback_ui/scanner_feedback_page_handler.h
@@ -0,0 +1,73 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_WEBUI_SCANNER_FEEDBACK_UI_SCANNER_FEEDBACK_PAGE_HANDLER_H_
+#define ASH_WEBUI_SCANNER_FEEDBACK_UI_SCANNER_FEEDBACK_PAGE_HANDLER_H_
+
+#include "ash/webui/scanner_feedback_ui/mojom/scanner_feedback_ui.mojom.h"
+#include "base/functional/callback_forward.h"
+#include "base/memory/raw_ref.h"
+#include "base/unguessable_token.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace ash {
+
+// Stores and handles all data related to a Scanner feedback prompt.
+//
+// Used for serving Mojo calls for a given `ScannerFeedbackUntrustedUI`. Serves
+// data from feedback info stored on the browser context - see
+// scanner_feedback_browser_context_data.h for more details. Use `id()` to get
+// the ID used for this page.
+class ScannerFeedbackPageHandler
+    : public mojom::scanner_feedback_ui::PageHandler {
+ public:
+  // Callback called from `CloseDialog`.
+  // Not guaranteed to be called if, for example, if the user closes the UI
+  // through other means such as the Escape key.
+  // May be called multiple times if, for example, this callback is a no-op and
+  // the button is clicked multiple times, or a user's click races the closing
+  // of the dialog.
+  using CloseDialogCallback = base::RepeatingClosure;
+
+  explicit ScannerFeedbackPageHandler(content::BrowserContext& browser_context);
+
+  ScannerFeedbackPageHandler(const ScannerFeedbackPageHandler&) = delete;
+  ScannerFeedbackPageHandler& operator=(const ScannerFeedbackPageHandler&) =
+      delete;
+
+  ~ScannerFeedbackPageHandler() override;
+
+  // Binds the receiver, unbinding the existing one if necessary.
+  void Bind(
+      mojo::PendingReceiver<mojom::scanner_feedback_ui::PageHandler> receiver);
+
+  void SetCloseDialogCallback(CloseDialogCallback close_dialog_callback) {
+    close_dialog_callback_ = std::move(close_dialog_callback);
+  }
+
+  base::UnguessableToken id() const { return id_; }
+
+  // mojom::scanner_feedback_ui::PageHandler:
+  void GetFeedbackInfo(GetFeedbackInfoCallback callback) override;
+  void CloseDialog() override;
+
+ private:
+  const base::UnguessableToken id_;
+
+  // Null on construction. Set in `SetCloseDialogCallback`.
+  CloseDialogCallback close_dialog_callback_;
+
+  const raw_ref<content::BrowserContext> browser_context_;
+
+  mojo::Receiver<mojom::scanner_feedback_ui::PageHandler> receiver_{this};
+};
+
+}  // namespace ash
+
+#endif  // ASH_WEBUI_SCANNER_FEEDBACK_UI_SCANNER_FEEDBACK_PAGE_HANDLER_H_
diff --git a/ash/webui/scanner_feedback_ui/scanner_feedback_untrusted_ui.cc b/ash/webui/scanner_feedback_ui/scanner_feedback_untrusted_ui.cc
index f5abc30f..d5deff4 100644
--- a/ash/webui/scanner_feedback_ui/scanner_feedback_untrusted_ui.cc
+++ b/ash/webui/scanner_feedback_ui/scanner_feedback_untrusted_ui.cc
@@ -4,29 +4,125 @@
 
 #include "ash/webui/scanner_feedback_ui/scanner_feedback_untrusted_ui.h"
 
+#include <cstddef>
 #include <memory>
+#include <optional>
 #include <string>
+#include <string_view>
 #include <utility>
 
 #include "ash/constants/ash_features.h"
+#include "ash/public/cpp/scanner/scanner_feedback_info.h"
 #include "ash/webui/common/chrome_os_webui_config.h"
 #include "ash/webui/common/trusted_types_util.h"
 #include "ash/webui/grit/ash_scanner_feedback_ui_resources.h"
 #include "ash/webui/grit/ash_scanner_feedback_ui_resources_map.h"
+#include "ash/webui/scanner_feedback_ui/mojom/scanner_feedback_ui.mojom.h"
+#include "ash/webui/scanner_feedback_ui/scanner_feedback_browser_context_data.h"
+#include "ash/webui/scanner_feedback_ui/scanner_feedback_page_handler.h"
 #include "ash/webui/scanner_feedback_ui/url_constants.h"
+#include "base/check.h"
+#include "base/check_deref.h"
+#include "base/functional/bind.h"
+#include "base/memory/weak_ptr.h"
+#include "base/unguessable_token.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_controller.h"
 #include "content/public/browser/web_ui_data_source.h"
+#include "content/public/common/bindings_policy.h"
 #include "content/public/common/url_constants.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "services/network/public/mojom/content_security_policy.mojom-shared.h"
+#include "ui/web_dialogs/web_dialog_ui.h"
 #include "ui/webui/color_change_listener/color_change_handler.h"
 #include "ui/webui/resources/cr_components/color_change_listener/color_change_listener.mojom.h"
-#include "ui/webui/untrusted_web_ui_controller.h"
 
 namespace ash {
 
+namespace {
+
+constexpr bool HasOverlap(std::string_view prefix, std::string_view suffix) {
+  for (size_t i = 0; i < suffix.size(); ++i) {
+    std::string_view truncated_suffix = suffix;
+    truncated_suffix.remove_suffix(i);
+    if (prefix.ends_with(truncated_suffix)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// `kScannerFeedbackScreenshotPrefix` and `kScannerFeedbackScreenshotSuffix`
+// must not have any "overlap", or else
+//     (path.starts_with(kScannerFeedbackScreenshotPrefix) &&
+//      path.ends_with(kScannerFeedbackScreenshotSuffix))
+// may not necessarily imply that
+//     (path.size() >=
+//      kScannerFeedbackScreenshotSuffix.size() +
+//          kScannerFeedbackScreenshotSuffix.size())
+static_assert(!HasOverlap(kScannerFeedbackScreenshotPrefix,
+                          kScannerFeedbackScreenshotSuffix));
+
+// Returns the `base::UnguessableToken` ID for a given screenshot URL path.
+std::optional<base::UnguessableToken> GetScreenshotId(std::string_view path) {
+  if (!path.starts_with(kScannerFeedbackScreenshotPrefix)) {
+    return std::nullopt;
+  }
+
+  if (!path.ends_with(kScannerFeedbackScreenshotSuffix)) {
+    return std::nullopt;
+  }
+
+  path.remove_prefix(kScannerFeedbackScreenshotPrefix.size());
+  path.remove_suffix(kScannerFeedbackScreenshotSuffix.size());
+
+  return base::UnguessableToken::DeserializeFromString(path);
+}
+
+// Returns whether we should handle a given request, given the path.
+bool ShouldHandleRequest(base::WeakPtr<content::BrowserContext> browser_context,
+                         const std::string& path) {
+  std::optional<base::UnguessableToken> id = GetScreenshotId(path);
+  if (!id.has_value()) {
+    return false;
+  }
+
+  CHECK(browser_context);
+  ScannerFeedbackInfo* feedback_info =
+      GetScannerFeedbackInfoForBrowserContext(*browser_context, *id);
+
+  return feedback_info != nullptr;
+}
+
+// Handles the given request and returns the screenshot to the
+// `GotDataCallback`.
+void HandleRequest(base::WeakPtr<content::BrowserContext> browser_context,
+                   const std::string& path,
+                   content::WebUIDataSource::GotDataCallback callback) {
+  std::optional<base::UnguessableToken> id = GetScreenshotId(path);
+  // `GetScreenshotId` is deterministic, so this should always be true as we
+  // checked it in `ShouldHandleRequest`.
+  CHECK(id.has_value());
+
+  CHECK(browser_context);
+  ScannerFeedbackInfo* feedback_info =
+      GetScannerFeedbackInfoForBrowserContext(*browser_context, *id);
+
+  // `GetScannerFeedbackInfoForBrowserContext` is _not_ deterministic, but is
+  // run synchronously after `ShouldHandleRequest` in
+  // `WebUIDataSourceImpl::StartDataRequest`.
+  // If this ever changes - for example, it is `PostTask`ed instead, this
+  // `CHECK` could fail if the `WebUI` is destroyed between
+  // `ShouldHandleRequest` and `HandleRequest`.
+  CHECK(feedback_info);
+
+  std::move(callback).Run(feedback_info->screenshot);
+}
+
+}  // namespace
+
 ScannerFeedbackUntrustedUIConfig::ScannerFeedbackUntrustedUIConfig()
     : ChromeOSWebUIConfig(content::kChromeUIUntrustedScheme,
                           kScannerFeedbackUntrustedHost) {}
@@ -39,7 +135,17 @@
 }
 
 ScannerFeedbackUntrustedUI::ScannerFeedbackUntrustedUI(content::WebUI* web_ui)
-    : ui::UntrustedWebUIController(web_ui) {
+    : ui::WebDialogUI(web_ui),
+      page_handler_(
+          CHECK_DEREF(CHECK_DEREF(CHECK_DEREF(web_ui).GetWebContents())
+                          .GetBrowserContext())) {
+  // Emulate `ui::UntrustedWebUIController`. This should never enable bindings.
+  web_ui->SetBindings(content::BindingsPolicySet());
+
+  // This should be non-null as it was checked above.
+  content::BrowserContext* browser_context =
+      web_ui->GetWebContents()->GetBrowserContext();
+
   // `content::WebUIDataSource`s are stored on the browser context. If an
   // existing `content::WebUIDataSource` exists in the browser context for the
   // given source name, calling `CreateAndAdd` will destroy the previous one.
@@ -61,8 +167,7 @@
   // sources, so this may change in the future.
   content::WebUIDataSource* untrusted_source =
       content::WebUIDataSource::CreateAndAdd(
-          web_ui->GetWebContents()->GetBrowserContext(),
-          std::string(kScannerFeedbackUntrustedUrl));
+          browser_context, std::string(kScannerFeedbackUntrustedUrl));
 
   untrusted_source->AddResourcePaths(kAshScannerFeedbackUiResources);
   // We intentionally do not use `SetDefaultResource` here as we do not want to
@@ -73,6 +178,10 @@
   untrusted_source->OverrideContentSecurityPolicy(
       network::mojom::CSPDirectiveName::StyleSrc,
       "style-src-elem 'self' theme;");
+
+  untrusted_source->SetRequestFilter(
+      base::BindRepeating(&ShouldHandleRequest, browser_context->GetWeakPtr()),
+      base::BindRepeating(&HandleRequest, browser_context->GetWeakPtr()));
 }
 
 ScannerFeedbackUntrustedUI::~ScannerFeedbackUntrustedUI() = default;
@@ -83,6 +192,11 @@
       web_ui()->GetWebContents(), std::move(receiver));
 }
 
+void ScannerFeedbackUntrustedUI::BindInterface(
+    mojo::PendingReceiver<mojom::scanner_feedback_ui::PageHandler> receiver) {
+  page_handler_.Bind(std::move(receiver));
+}
+
 WEB_UI_CONTROLLER_TYPE_IMPL(ScannerFeedbackUntrustedUI)
 
 }  // namespace ash
diff --git a/ash/webui/scanner_feedback_ui/scanner_feedback_untrusted_ui.h b/ash/webui/scanner_feedback_ui/scanner_feedback_untrusted_ui.h
index f8400e7e..4b4b98f 100644
--- a/ash/webui/scanner_feedback_ui/scanner_feedback_untrusted_ui.h
+++ b/ash/webui/scanner_feedback_ui/scanner_feedback_untrusted_ui.h
@@ -8,10 +8,12 @@
 #include <memory>
 
 #include "ash/webui/common/chrome_os_webui_config.h"
+#include "ash/webui/scanner_feedback_ui/mojom/scanner_feedback_ui.mojom-forward.h"
+#include "ash/webui/scanner_feedback_ui/scanner_feedback_page_handler.h"
 #include "content/public/browser/web_ui_controller.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "ui/web_dialogs/web_dialog_ui.h"
 #include "ui/webui/resources/cr_components/color_change_listener/color_change_listener.mojom-forward.h"
-#include "ui/webui/untrusted_web_ui_controller.h"
 
 namespace content {
 class BrowserContext;
@@ -35,7 +37,7 @@
   bool IsWebUIEnabled(content::BrowserContext* browser_context) override;
 };
 
-class ScannerFeedbackUntrustedUI : public ui::UntrustedWebUIController {
+class ScannerFeedbackUntrustedUI : public ui::WebDialogUI {
  public:
   explicit ScannerFeedbackUntrustedUI(content::WebUI* web_ui);
 
@@ -45,15 +47,22 @@
 
   ~ScannerFeedbackUntrustedUI() override;
 
+  ScannerFeedbackPageHandler& page_handler() { return page_handler_; }
+
   void BindInterface(
       mojo::PendingReceiver<color_change_listener::mojom::PageHandler>
           receiver);
 
+  void BindInterface(
+      mojo::PendingReceiver<mojom::scanner_feedback_ui::PageHandler> receiver);
+
  private:
   // The color change handler notifies the WebUI when the color provider
   // changes.
   std::unique_ptr<ui::ColorChangeHandler> color_provider_handler_;
 
+  ScannerFeedbackPageHandler page_handler_;
+
   WEB_UI_CONTROLLER_TYPE_DECL();
 };
 
diff --git a/ash/webui/scanner_feedback_ui/url_constants.h b/ash/webui/scanner_feedback_ui/url_constants.h
index 87a9c4e..d9e0484 100644
--- a/ash/webui/scanner_feedback_ui/url_constants.h
+++ b/ash/webui/scanner_feedback_ui/url_constants.h
@@ -13,6 +13,9 @@
     "chrome-untrusted://scanner-feedback/";
 inline constexpr std::string_view kScannerFeedbackUntrustedHost =
     "scanner-feedback";
+inline constexpr std::string_view kScannerFeedbackScreenshotPrefix =
+    "screenshots/";
+inline constexpr std::string_view kScannerFeedbackScreenshotSuffix = ".jpg";
 
 }  // namespace ash
 
diff --git a/ash/webui/settings/public/constants/routes.mojom b/ash/webui/settings/public/constants/routes.mojom
index 3cbc7cd..5098203 100644
--- a/ash/webui/settings/public/constants/routes.mojom
+++ b/ash/webui/settings/public/constants/routes.mojom
@@ -22,7 +22,7 @@
   // https://crbug.com/1074101. Do not reuse.
   // Note: Value 10 was for deprecated kDateAndTime. Do not reuse.
   kPrivacyAndSecurity = 11,
-  kLanguagesAndInput = 12,
+  // Note: Value 12 was used for deprecated kLanguagesAndInput. Do not reuse.
   // Note: Value 13 was for deprecated kFiles. Do not reuse.
   // Note: Value 14 was for deprecated kPrinting. Do not reuse.
   kAccessibility = 15,
@@ -310,7 +310,6 @@
       "osPrivacy/privacyHub/geolocation/advanced";
 
 // Languages and Input section.
-const string kLanguagesAndInputSectionPath = "osLanguages";
 const string kInputMethodOptionsSubpagePath = "osLanguages/inputMethodOptions";
 const string kLanguagesSubpagePath = "osLanguages/languages";
 const string kInputSubpagePath = "osLanguages/input";
diff --git a/base/check.h b/base/check.h
index 08c7ac3..b7605cc 100644
--- a/base/check.h
+++ b/base/check.h
@@ -78,44 +78,56 @@
   // Takes ownership of `log_message`.
   explicit CheckError(LogMessage* log_message);
 
+  // All instances that take a base::Location should use
+  // base::Location::CurrentWithoutFunctionName() by default since we
+  // immediately pass file_name() and line_number() to LogMessage's constructor
+  // and discard the function_name() anyways. This saves ~23k on the Android
+  // size bots (as of 2024-12-17) but that's the official build that barely uses
+  // these for CHECKs. The size gains are believed to be significantly larger on
+  // developer builds and official+DCHECK where all CHECK failures generate
+  // logs.
+
   // TODO(pbos): Make all static methods that currently return some version of
   // CheckError return LogMessage*.
-  static CheckError Check(
-      const char* condition,
-      base::NotFatalUntil fatal_milestone,
-      const base::Location& location = base::Location::Current());
+  static CheckError Check(const char* condition,
+                          base::NotFatalUntil fatal_milestone,
+                          const base::Location& location =
+                              base::Location::CurrentWithoutFunctionName());
   // Takes ownership over (free()s after using) `log_message_str`, for use with
   // CHECK_op macros.
-  static LogMessage* CheckOp(
-      char* log_message_str,
-      base::NotFatalUntil fatal_milestone,
-      const base::Location& location = base::Location::Current());
+  static LogMessage* CheckOp(char* log_message_str,
+                             base::NotFatalUntil fatal_milestone,
+                             const base::Location& location =
+                                 base::Location::CurrentWithoutFunctionName());
 
-  static CheckError DCheck(
-      const char* condition,
-      const base::Location& location = base::Location::Current());
+  static CheckError DCheck(const char* condition,
+                           const base::Location& location =
+                               base::Location::CurrentWithoutFunctionName());
   // Takes ownership over (free()s after using) `log_message_str`, for use with
   // DCHECK_op macros.
-  static LogMessage* DCheckOp(
-      char* log_message_str,
-      const base::Location& location = base::Location::Current());
+  static LogMessage* DCheckOp(char* log_message_str,
+                              const base::Location& location =
+                                  base::Location::CurrentWithoutFunctionName());
 
   static CheckError DumpWillBeCheck(
       const char* condition,
-      const base::Location& location = base::Location::Current());
+      const base::Location& location =
+          base::Location::CurrentWithoutFunctionName());
   // Takes ownership over (free()s after using) `log_message_str`, for use with
   // DUMP_WILL_BE_CHECK_op macros.
   static LogMessage* DumpWillBeCheckOp(
       char* log_message_str,
-      const base::Location& location = base::Location::Current());
+      const base::Location& location =
+          base::Location::CurrentWithoutFunctionName());
 
-  static CheckError DPCheck(
-      const char* condition,
-      const base::Location& location = base::Location::Current());
+  static CheckError DPCheck(const char* condition,
+                            const base::Location& location =
+                                base::Location::CurrentWithoutFunctionName());
 
   static CheckError NotImplemented(
       const char* function,
-      const base::Location& location = base::Location::Current());
+      const base::Location& location =
+          base::Location::CurrentWithoutFunctionName());
 
   // Stream for adding optional details to the error message.
   std::ostream& stream();
@@ -144,18 +156,21 @@
 
   static CheckNoreturnError Check(
       const char* condition,
-      const base::Location& location = base::Location::Current());
+      const base::Location& location =
+          base::Location::CurrentWithoutFunctionName());
   // Takes ownership over (free()s after using) `log_message_str`, for use with
   // CHECK_op macros.
-  static LogMessage* CheckOp(
-      char* log_message_str,
-      const base::Location& location = base::Location::Current());
+  static LogMessage* CheckOp(char* log_message_str,
+                             const base::Location& location =
+                                 base::Location::CurrentWithoutFunctionName());
 
   static CheckNoreturnError PCheck(
       const char* condition,
-      const base::Location& location = base::Location::Current());
+      const base::Location& location =
+          base::Location::CurrentWithoutFunctionName());
   static CheckNoreturnError PCheck(
-      const base::Location& location = base::Location::Current());
+      const base::Location& location =
+          base::Location::CurrentWithoutFunctionName());
 };
 
 // Used for NOTREACHED(base::NotFatalUntil) and DUMP_WILL_BE_NOTREACHED().
@@ -163,10 +178,12 @@
  public:
   static NotReachedError NotReached(
       base::NotFatalUntil fatal_milestone,
-      const base::Location& location = base::Location::Current());
+      const base::Location& location =
+          base::Location::CurrentWithoutFunctionName());
 
   static NotReachedError DumpWillBeNotReached(
-      const base::Location& location = base::Location::Current());
+      const base::Location& location =
+          base::Location::CurrentWithoutFunctionName());
 
   NOMERGE NOINLINE NOT_TAIL_CALLED ~NotReachedError();
 
@@ -178,7 +195,8 @@
 class BASE_EXPORT NotReachedNoreturnError : public CheckError {
  public:
   explicit NotReachedNoreturnError(
-      const base::Location& location = base::Location::Current());
+      const base::Location& location =
+          base::Location::CurrentWithoutFunctionName());
 
   [[noreturn]] NOMERGE NOINLINE NOT_TAIL_CALLED ~NotReachedNoreturnError();
 };
diff --git a/base/location.cc b/base/location.cc
index 917460f..da4356f 100644
--- a/base/location.cc
+++ b/base/location.cc
@@ -137,6 +137,13 @@
                   RETURN_ADDRESS());
 }
 
+// static
+NOINLINE Location Location::CurrentWithoutFunctionName(const char* file_name,
+                                                       int line_number) {
+  return Location(nullptr, file_name + kStrippedPrefixLength, line_number,
+                  RETURN_ADDRESS());
+}
+
 //------------------------------------------------------------------------------
 NOINLINE const void* GetProgramCounter() {
   return RETURN_ADDRESS();
diff --git a/base/location.h b/base/location.h
index e9bc21a..f324c40 100644
--- a/base/location.h
+++ b/base/location.h
@@ -79,6 +79,10 @@
                           const char* file_name = __builtin_FILE(),
                           int line_number = __builtin_LINE());
 
+  static Location CurrentWithoutFunctionName(
+      const char* file_name = __builtin_FILE(),
+      int line_number = __builtin_LINE());
+
  private:
   // Only initializes the file name and program counter, the source information
   // will be null for the strings, and -1 for the line number.
diff --git a/base/memory/discardable_shared_memory.cc b/base/memory/discardable_shared_memory.cc
index ab04ee51..68be54a 100644
--- a/base/memory/discardable_shared_memory.cc
+++ b/base/memory/discardable_shared_memory.cc
@@ -112,9 +112,14 @@
 };
 
 // Shared state is stored at offset 0 in shared memory segments.
-SharedState* SharedStateFromSharedMemory(
+const SharedState* SharedStateFromSharedMemory(
     const WritableSharedMemoryMapping& shared_memory) {
   DCHECK(shared_memory.IsValid());
+  return shared_memory.GetMemoryAs<const SharedState>();
+}
+SharedState* SharedStateFromSharedMemory(
+    WritableSharedMemoryMapping& shared_memory) {
+  DCHECK(shared_memory.IsValid());
   return shared_memory.GetMemoryAs<SharedState>();
 }
 
@@ -354,12 +359,22 @@
   last_known_usage_ = current_time;
 }
 
-span<uint8_t> DiscardableSharedMemory::memory() const {
+span<uint8_t> DiscardableSharedMemory::memory() {
   return shared_memory_mapping_.GetMemoryAsSpan<uint8_t>().subspan(
       AlignToPageSize(sizeof(SharedState)));
 }
 
-span<uint8_t> DiscardableSharedMemory::mapped_memory() const {
+span<const uint8_t> DiscardableSharedMemory::memory() const {
+  return shared_memory_mapping_.GetMemoryAsSpan<const uint8_t>().subspan(
+      AlignToPageSize(sizeof(SharedState)));
+}
+
+span<uint8_t> DiscardableSharedMemory::mapped_memory() {
+  return shared_memory_mapping_.mapped_memory().subspan(
+      AlignToPageSize(sizeof(SharedState)));
+}
+
+span<const uint8_t> DiscardableSharedMemory::mapped_memory() const {
   return shared_memory_mapping_.mapped_memory().subspan(
       AlignToPageSize(sizeof(SharedState)));
 }
diff --git a/base/memory/discardable_shared_memory.h b/base/memory/discardable_shared_memory.h
index 7ed84f7..4571b3c1 100644
--- a/base/memory/discardable_shared_memory.h
+++ b/base/memory/discardable_shared_memory.h
@@ -125,7 +125,8 @@
   // requested. The actual mapped memory may be larger due to system alignment
   // requirements. See `SharedMemoryMapping::size()` vs
   // `SharedMemoryMapping::mapped_size()`.
-  span<uint8_t> memory() const;
+  span<uint8_t> memory();
+  span<const uint8_t> memory() const;
 
   // Returns the last known usage time for DiscardableSharedMemory object. This
   // may be earlier than the "true" usage time when memory has been used by a
@@ -177,7 +178,8 @@
   // header. This may be larger than the region exposed through `memory()` due
   // to platform alignment requirements. Discardable memory must have been
   // mapped via Map().
-  span<uint8_t> mapped_memory() const;
+  span<uint8_t> mapped_memory();
+  span<const uint8_t> mapped_memory() const;
 
   // LockPages/UnlockPages are platform-native discardable page management
   // helper functions. Both expect |offset| to be specified relative to the
diff --git a/base/memory/shared_memory_mapping.h b/base/memory/shared_memory_mapping.h
index ed18aa5..b45619d 100644
--- a/base/memory/shared_memory_mapping.h
+++ b/base/memory/shared_memory_mapping.h
@@ -6,6 +6,7 @@
 #define BASE_MEMORY_SHARED_MEMORY_MAPPING_H_
 
 #include <cstddef>
+#include <utility>
 
 #include "base/base_export.h"
 #include "base/check.h"
@@ -142,11 +143,9 @@
   template <typename T>
     requires subtle::AllowedOverSharedMemory<T>
   const T* GetMemoryAs() const {
-    if (!IsValid())
-      return nullptr;
-    if (sizeof(T) > size())
-      return nullptr;
-    return reinterpret_cast<const T*>(mapped_memory().data());
+    return (IsValid() && sizeof(T) <= size())
+               ? reinterpret_cast<const T*>(mapped_memory().data())
+               : nullptr;
   }
 
   // Returns a span of const T. The number of elements is autodeduced from the
@@ -158,10 +157,8 @@
   template <typename T>
     requires subtle::AllowedOverSharedMemory<T>
   span<const T> GetMemoryAsSpan() const {
-    if (!IsValid())
-      return span<const T>();
-    size_t count = size() / sizeof(T);
-    return GetMemoryAsSpan<T>(count);
+    return IsValid() ? GetMemoryAsSpan<const T>(size() / sizeof(T))
+                     : span<const T>();
   }
 
   // Returns a span of const T with |count| elements if the mapping is valid and
@@ -170,16 +167,14 @@
   template <typename T>
     requires subtle::AllowedOverSharedMemory<T>
   span<const T> GetMemoryAsSpan(size_t count) const {
-    if (!IsValid())
-      return span<const T>();
-    if (size() / sizeof(T) < count)
-      return span<const T>();
+    const T* const ptr = GetMemoryAs<const T>();
     // SAFETY: There is an internal invariant (enforced in the constructors)
     // that `size() <= mapped_memory().size()`. `count` is the number of objects
-    // of type T that fit within size(), so the pointer given to span() points
-    // to at least that many T objects.
-    return UNSAFE_BUFFERS(
-        span(reinterpret_cast<const T*>(mapped_memory().data()), count));
+    // of type `T` that fit within `size()`, so the pointer given to `span()`
+    // points to at least that many `T` objects.
+    return (ptr && count <= size() / sizeof(T))
+               ? UNSAFE_BUFFERS(span(ptr, count))
+               : span<const T>();
   }
 
  private:
@@ -249,12 +244,15 @@
   // enough to contain a T, or nullptr otherwise.
   template <typename T>
     requires subtle::AllowedOverSharedMemory<T>
-  T* GetMemoryAs() const {
-    if (!IsValid())
-      return nullptr;
-    if (sizeof(T) > size())
-      return nullptr;
-    return reinterpret_cast<T*>(mapped_memory().data());
+  const T* GetMemoryAs() const {
+    return (IsValid() && sizeof(T) <= size())
+               ? reinterpret_cast<T*>(mapped_memory().data())
+               : nullptr;
+  }
+  template <typename T>
+    requires(!std::is_const_v<T> && subtle::AllowedOverSharedMemory<T>)
+  T* GetMemoryAs() {
+    return const_cast<T*>(std::as_const(*this).GetMemoryAs<const T>());
   }
 
   // Returns a span of T. The number of elements is autodeduced from the size of
@@ -264,11 +262,14 @@
   // The first element, if any, is guaranteed to be page-aligned.
   template <typename T>
     requires subtle::AllowedOverSharedMemory<T>
-  span<T> GetMemoryAsSpan() const {
-    if (!IsValid())
-      return span<T>();
-    size_t count = size() / sizeof(T);
-    return GetMemoryAsSpan<T>(count);
+  span<const T> GetMemoryAsSpan() const {
+    return IsValid() ? GetMemoryAsSpan<const T>(size() / sizeof(T))
+                     : span<const T>();
+  }
+  template <typename T>
+    requires(!std::is_const_v<T> && subtle::AllowedOverSharedMemory<T>)
+  span<T> GetMemoryAsSpan() {
+    return IsValid() ? GetMemoryAsSpan<T>(size() / sizeof(T)) : span<T>();
   }
 
   // Returns a span of T with |count| elements if the mapping is valid and large
@@ -276,17 +277,21 @@
   // element, if any, is guaranteed to be page-aligned.
   template <typename T>
     requires subtle::AllowedOverSharedMemory<T>
-  span<T> GetMemoryAsSpan(size_t count) const {
-    if (!IsValid())
-      return span<T>();
-    if (size() / sizeof(T) < count)
-      return span<T>();
-    // SAFETY: There is an internal invariant (enforced in the constructors)
-    // that `size() <= mapped_memory().size()`. `count` is the number of objects
-    // of type T that fit within size(), so the pointer given to span() points
-    // to at least that many T objects.
-    return UNSAFE_BUFFERS(
-        span(reinterpret_cast<T*>(mapped_memory().data()), count));
+  span<const T> GetMemoryAsSpan(size_t count) const {
+    const T* const ptr = GetMemoryAs<const T>();
+    // SAFETY: As in the ReadOnly code above.
+    return (ptr && count <= size() / sizeof(T))
+               ? UNSAFE_BUFFERS(span(ptr, count))
+               : span<const T>();
+  }
+  template <typename T>
+    requires(!std::is_const_v<T> && subtle::AllowedOverSharedMemory<T>)
+  span<T> GetMemoryAsSpan(size_t count) {
+    T* const ptr = GetMemoryAs<T>();
+    // SAFETY: As in the ReadOnly code above.
+    return (ptr && count <= size() / sizeof(T))
+               ? UNSAFE_BUFFERS(span(ptr, count))
+               : span<T>();
   }
 
  private:
diff --git a/base/memory/shared_memory_mapping_unittest.cc b/base/memory/shared_memory_mapping_unittest.cc
index 31dd519..8eebf26 100644
--- a/base/memory/shared_memory_mapping_unittest.cc
+++ b/base/memory/shared_memory_mapping_unittest.cc
@@ -8,6 +8,8 @@
 
 #include <atomic>
 #include <limits>
+#include <memory>
+#include <type_traits>
 
 #include "base/containers/span.h"
 #include "base/memory/read_only_shared_memory_region.h"
@@ -19,6 +21,11 @@
 
 namespace base {
 
+namespace {
+template <typename T>
+using ElementType = std::pointer_traits<T>::element_type;
+}
+
 class SharedMemoryMappingTest : public ::testing::Test {
  protected:
   void CreateMapping(size_t size) {
@@ -117,6 +124,86 @@
   EXPECT_TRUE(read_mapping_.GetMemoryAsSpan<uint8_t>(0).empty());
 }
 
+TEST_F(SharedMemoryMappingTest, ConstCorrectness) {
+  // All memory accessors for read-only mappings should return const T.
+  ReadOnlySharedMemoryMapping ro;
+
+  static_assert(std::is_const_v<ElementType<decltype(ro.data())>>);
+  static_assert(std::is_const_v<ElementType<decltype(ro.begin())>>);
+  static_assert(std::is_const_v<ElementType<decltype(ro.end())>>);
+  static_assert(std::is_const_v<ElementType<decltype(ro.memory())>>);
+  static_assert(
+      std::is_const_v<ElementType<decltype(ro.GetMemoryAs<uint8_t>())>>);
+  static_assert(
+      std::is_const_v<ElementType<decltype(ro.GetMemoryAs<const uint8_t>())>>);
+  static_assert(
+      std::is_const_v<decltype(ro.GetMemoryAsSpan<uint8_t>())::element_type>);
+  static_assert(std::is_const_v<
+                decltype(ro.GetMemoryAsSpan<const uint8_t>())::element_type>);
+  static_assert(
+      std::is_const_v<decltype(ro.GetMemoryAsSpan<uint8_t>(1))::element_type>);
+  static_assert(std::is_const_v<decltype(ro.GetMemoryAsSpan<const uint8_t>(
+                    1))::element_type>);
+
+  // Making the mapping const should still allow all accessors to be called.
+  const ReadOnlySharedMemoryMapping cro;
+  static_assert(std::is_const_v<ElementType<decltype(cro.data())>>);
+  static_assert(std::is_const_v<ElementType<decltype(cro.begin())>>);
+  static_assert(std::is_const_v<ElementType<decltype(cro.end())>>);
+  static_assert(std::is_const_v<ElementType<decltype(cro.memory())>>);
+  static_assert(
+      std::is_const_v<ElementType<decltype(cro.GetMemoryAs<uint8_t>())>>);
+  static_assert(
+      std::is_const_v<ElementType<decltype(cro.GetMemoryAs<const uint8_t>())>>);
+  static_assert(
+      std::is_const_v<decltype(cro.GetMemoryAsSpan<uint8_t>())::element_type>);
+  static_assert(std::is_const_v<
+                decltype(cro.GetMemoryAsSpan<const uint8_t>())::element_type>);
+  static_assert(
+      std::is_const_v<decltype(cro.GetMemoryAsSpan<uint8_t>(1))::element_type>);
+  static_assert(std::is_const_v<decltype(cro.GetMemoryAsSpan<const uint8_t>(
+                    1))::element_type>);
+
+  // Accessors for writable mappings should be non-const unless requested.
+  WritableSharedMemoryMapping rw;
+  static_assert(!std::is_const_v<ElementType<decltype(rw.data())>>);
+  static_assert(!std::is_const_v<ElementType<decltype(rw.begin())>>);
+  static_assert(!std::is_const_v<ElementType<decltype(rw.end())>>);
+  static_assert(!std::is_const_v<ElementType<decltype(rw.memory())>>);
+  static_assert(
+      !std::is_const_v<ElementType<decltype(rw.GetMemoryAs<uint8_t>())>>);
+  static_assert(
+      std::is_const_v<ElementType<decltype(rw.GetMemoryAs<const uint8_t>())>>);
+  static_assert(
+      !std::is_const_v<decltype(rw.GetMemoryAsSpan<uint8_t>())::element_type>);
+  static_assert(std::is_const_v<
+                decltype(rw.GetMemoryAsSpan<const uint8_t>())::element_type>);
+  static_assert(
+      !std::is_const_v<decltype(rw.GetMemoryAsSpan<uint8_t>(1))::element_type>);
+  static_assert(std::is_const_v<decltype(rw.GetMemoryAsSpan<const uint8_t>(
+                    1))::element_type>);
+
+  // Making the mapping const should still allow all accessors to be called, but
+  // they should now return const T.
+  const WritableSharedMemoryMapping crw;
+  static_assert(std::is_const_v<ElementType<decltype(crw.data())>>);
+  static_assert(std::is_const_v<ElementType<decltype(crw.begin())>>);
+  static_assert(std::is_const_v<ElementType<decltype(crw.end())>>);
+  static_assert(std::is_const_v<ElementType<decltype(crw.memory())>>);
+  static_assert(
+      std::is_const_v<ElementType<decltype(crw.GetMemoryAs<uint8_t>())>>);
+  static_assert(
+      std::is_const_v<ElementType<decltype(crw.GetMemoryAs<const uint8_t>())>>);
+  static_assert(
+      std::is_const_v<decltype(crw.GetMemoryAsSpan<uint8_t>())::element_type>);
+  static_assert(std::is_const_v<
+                decltype(crw.GetMemoryAsSpan<const uint8_t>())::element_type>);
+  static_assert(
+      std::is_const_v<decltype(crw.GetMemoryAsSpan<uint8_t>(1))::element_type>);
+  static_assert(std::is_const_v<decltype(crw.GetMemoryAsSpan<const uint8_t>(
+                    1))::element_type>);
+}
+
 TEST_F(SharedMemoryMappingTest, TooBigScalar) {
   CreateMapping(sizeof(uint8_t));
 
diff --git a/base/memory/shared_memory_safety_checker.h b/base/memory/shared_memory_safety_checker.h
index 51333ab3..ead0313 100644
--- a/base/memory/shared_memory_safety_checker.h
+++ b/base/memory/shared_memory_safety_checker.h
@@ -58,7 +58,8 @@
 };
 
 template <typename T>
-concept AllowedOverSharedMemory = SharedMemorySafetyChecker<T>::kIsAllowed;
+concept AllowedOverSharedMemory =
+    SharedMemorySafetyChecker<std::remove_cvref_t<T>>::kIsAllowed;
 
 // Convenience alias for atomics that are safe to share across memory spaces.
 template <typename T>
diff --git a/base/memory/structured_shared_memory.h b/base/memory/structured_shared_memory.h
index 12011c2b..4aefbee 100644
--- a/base/memory/structured_shared_memory.h
+++ b/base/memory/structured_shared_memory.h
@@ -113,7 +113,7 @@
       SharedMemoryMapper* mapper = nullptr);
 
   // Returns a pointer to the object stored in the mapped region.
-  T* WritablePtr() const {
+  T* WritablePtr() {
     CHECK(writable_mapping_.IsValid());
     return writable_mapping_.GetMemoryAs<T>();
   }
@@ -123,7 +123,7 @@
   }
 
   // Returns a reference to the object stored in the mapped region.
-  T& WritableRef() const LIFETIME_BOUND {
+  T& WritableRef() LIFETIME_BOUND {
     T* ptr = WritablePtr();
     CHECK(ptr);
     return *ptr;
diff --git a/base/memory/unsafe_shared_memory_pool.h b/base/memory/unsafe_shared_memory_pool.h
index e76b5678..2ba52f9 100644
--- a/base/memory/unsafe_shared_memory_pool.h
+++ b/base/memory/unsafe_shared_memory_pool.h
@@ -42,6 +42,11 @@
     Handle& operator=(const Handle&) = delete;
 
     const UnsafeSharedMemoryRegion& GetRegion() const LIFETIME_BOUND;
+
+    WritableSharedMemoryMapping& GetMapping() LIFETIME_BOUND {
+      return const_cast<WritableSharedMemoryMapping&>(
+          std::as_const(*this).GetMapping());
+    }
     const WritableSharedMemoryMapping& GetMapping() const LIFETIME_BOUND;
 
    private:
diff --git a/base/threading/hang_watcher.cc b/base/threading/hang_watcher.cc
index 7c46ca54..b9fb189e 100644
--- a/base/threading/hang_watcher.cc
+++ b/base/threading/hang_watcher.cc
@@ -765,12 +765,6 @@
       hung_counts_per_thread_type[hang_count_index] = 0;
     }
 
-#if BUILDFLAG(ENABLE_BASE_TRACING)
-    const PlatformThreadId thread_id = watch_state.get()->GetThreadID();
-    const auto track = perfetto::Track::FromPointer(
-        this, perfetto::ThreadTrack::ForThread(thread_id));
-#endif
-
     // Only copy hung threads.
     if (deadline <= now) {
       ++hung_counts_per_thread_type[hang_count_index];
@@ -784,11 +778,12 @@
       // Emit trace events for monitored threads.
       if (ThreadTypeLoggingLevelGreaterOrEqual(watch_state.get()->thread_type(),
                                                LoggingLevel::kUmaOnly)) {
-        if (!watch_state.get()->TraceEventStarted()) {
-          TRACE_EVENT_BEGIN("latency", "HangWatcher::ThreadHung", track,
-                            deadline - kMonitoringPeriod, "id", thread_id);
-          watch_state.get()->MarkTraceEventStarted(true);
-        }
+        const PlatformThreadId thread_id = watch_state.get()->GetThreadID();
+        const auto track = perfetto::Track::FromPointer(
+            this, perfetto::ThreadTrack::ForThread(thread_id));
+        TRACE_EVENT_BEGIN("latency", "HangWatcher::ThreadHung", track,
+                          deadline);
+        TRACE_EVENT_END("latency", track, now);
       }
 #endif
 
@@ -807,13 +802,6 @@
       } else {
         all_threads_marked = false;
       }
-    } else {  // For threads that are not hung.
-#if BUILDFLAG(ENABLE_BASE_TRACING)
-      if (watch_state.get()->TraceEventStarted()) {
-        TRACE_EVENT_END("latency", track, now - kMonitoringPeriod);
-        watch_state.get()->MarkTraceEventStarted(false);
-      }
-#endif
     }
   }
 
@@ -1041,17 +1029,6 @@
   // Thread should be registered to get unregistered.
   CHECK(it != watch_states_.end(), base::NotFatalUntil::M125);
 
-  // If a trace event was started it will never be finished if the thread
-  // unregisters so finish it now.
-#if BUILDFLAG(ENABLE_BASE_TRACING)
-  const internal::HangWatchState& watch_state = *(it->get());
-  if (watch_state.TraceEventStarted()) {
-    const auto track = perfetto::Track::FromPointer(
-        this, perfetto::ThreadTrack::ForThread(watch_state.GetThreadID()));
-    TRACE_EVENT_END("latency", track, base::TimeTicks::Now());
-  }
-#endif
-
   watch_states_.erase(it);
 }
 
@@ -1339,14 +1316,6 @@
 #endif
 }
 
-bool HangWatchState::TraceEventStarted() const {
-  return trace_event_started_;
-}
-
-void HangWatchState::MarkTraceEventStarted(bool capturing) {
-  trace_event_started_ = capturing;
-}
-
 }  // namespace internal
 
 }  // namespace base
diff --git a/base/threading/hang_watcher.h b/base/threading/hang_watcher.h
index 8220c67..a9802250 100644
--- a/base/threading/hang_watcher.h
+++ b/base/threading/hang_watcher.h
@@ -651,12 +651,6 @@
   // Returns the type of the thread under watch.
   HangWatcher::ThreadType thread_type() const { return thread_type_; }
 
-  // Functions used to coordinate capture of the trace event per hung thread.
-  // These functions need to evolve if HangWatcher starts logging more than one
-  // trace event per hung thread.
-  bool TraceEventStarted() const;
-  void MarkTraceEventStarted(bool capturing);
-
  private:
   // The thread that creates the instance should be the class that updates
   // the deadline.
@@ -686,8 +680,6 @@
   // The type of the thread under watch.
   const HangWatcher::ThreadType thread_type_;
 
-  bool trace_event_started_ = false;
-
 #if DCHECK_IS_ON()
   // Used to keep track of the current WatchHangsInScope and detect improper
   // usage. Scopes should always be destructed in reverse order from the one
diff --git a/base/tracing/stdlib/chrome/input.sql b/base/tracing/stdlib/chrome/input.sql
index 75db2b1..4eeaccc 100644
--- a/base/tracing/stdlib/chrome/input.sql
+++ b/base/tracing/stdlib/chrome/input.sql
@@ -148,11 +148,15 @@
     (
       (
         SELECT slice_id AS id, *
-        FROM scroll_update_steps),
+        FROM scroll_update_steps
+        WHERE dur > 0
+      ),
       (
         SELECT slice_id AS id, *
         FROM chrome_input_pipeline_steps step
-        WHERE step = 'STEP_TOUCH_EVENT_HANDLED')
+        WHERE step = 'STEP_TOUCH_EVENT_HANDLED'
+          AND dur > 0
+      )
     ),
     (utid)
   ) AS ii
@@ -177,11 +181,16 @@
     (
       (
         SELECT slice_id AS id, *
-        FROM scroll_update_steps),
+        FROM scroll_update_steps
+        WHERE dur > 0
+      ),
       (
         SELECT slice_id AS id, *
         FROM chrome_input_pipeline_steps step
-        WHERE step = 'STEP_SEND_INPUT_EVENT_UI' AND input_type = 'TOUCH_MOVE_EVENT')
+        WHERE step = 'STEP_SEND_INPUT_EVENT_UI'
+          AND input_type = 'TOUCH_MOVE_EVENT'
+          AND dur > 0
+      )
     ),
     (utid)
   ) AS ii
diff --git a/cc/paint/display_item_list.cc b/cc/paint/display_item_list.cc
index b7c796c..51d84e6e 100644
--- a/cc/paint/display_item_list.cc
+++ b/cc/paint/display_item_list.cc
@@ -110,7 +110,7 @@
     size_t rastered_op_count = 0;
     for (PaintOpBuffer::PlaybackFoldingIterator it(paint_op_buffer_, &offsets);
          it; ++it) {
-      rastered_op_count += 1 + it->AdditionalOpCount();
+      rastered_op_count += 1 + PaintOp::OpAdditionalOpCount(*it);
     }
     TRACE_EVENT_END1("cc", "DisplayItemList::Raster", "rastered_op_count",
                      rastered_op_count);
@@ -161,13 +161,8 @@
   size_t index = 0;
   for (const PaintOp& op :
        PaintOpBuffer::OffsetIterator(paint_op_buffer_, offsets)) {
-    if (op.GetType() == PaintOpType::kDrawTextBlob ||
-        // Don't walk into the record because the visual rect is already the
-        // bounding box of the sub paint operations. This works for most paint
-        // results for text generated by blink.
-        (op.GetType() == PaintOpType::kDrawRecord &&
-         static_cast<const DrawRecordOp&>(op).record.has_draw_text_ops())) {
-      area += static_cast<double>(rects[index].width()) * rects[index].height();
+    if (PaintOp::OpHasDrawTextOps(op)) {
+      area += rects[index].size().Area64();
     }
     ++index;
   }
diff --git a/cc/paint/paint_op.cc b/cc/paint/paint_op.cc
index 99d1bd9..a16449b 100644
--- a/cc/paint/paint_op.cc
+++ b/cc/paint/paint_op.cc
@@ -241,7 +241,8 @@
     Rasterizer<T, T::kHasPaintFlags>::Raster(static_cast<const T*>(op),   \
                                              canvas, params);             \
   },
-static const RasterFunction g_raster_functions[kNumOpTypes] = {TYPES(M)};
+constexpr std::array<RasterFunction, kNumOpTypes> g_raster_functions = {
+    TYPES(M)};
 #undef M
 
 using RasterWithFlagsFunction = void (*)(const PaintOp* op,
@@ -254,8 +255,8 @@
     Rasterizer<T, T::kHasPaintFlags>::RasterWithFlags(             \
         static_cast<const T*>(op), flags, canvas, params);         \
   },
-static const RasterWithFlagsFunction
-    g_raster_with_flags_functions[kNumOpTypes] = {TYPES(M)};
+constexpr std::array<RasterWithFlagsFunction, kNumOpTypes>
+    g_raster_with_flags_functions = {TYPES(M)};
 #undef M
 
 using SerializeFunction = void (*)(const PaintOp& op,
@@ -278,7 +279,8 @@
   op_t.Serialize(writer, flags_to_serialize, current_ctm, original_ctm);
 }
 #define M(T) &Serialize<T>,
-static const SerializeFunction g_serialize_functions[kNumOpTypes] = {TYPES(M)};
+constexpr std::array<SerializeFunction, kNumOpTypes> g_serialize_functions = {
+    TYPES(M)};
 #undef M
 
 using DeserializeFunction = PaintOp* (*)(PaintOpReader& reader,
@@ -298,8 +300,8 @@
   return op;
 }
 #define M(T) &Deserialize<T>,
-static const DeserializeFunction g_deserialize_functions[kNumOpTypes] = {
-    TYPES(M)};
+constexpr std::array<DeserializeFunction, kNumOpTypes> g_deserialize_functions =
+    {TYPES(M)};
 #undef M
 
 using AreEqualForTestingFunction = bool (*)(const PaintOp&, const PaintOp&);
@@ -309,8 +311,8 @@
       static_cast<const T&>(b));
 }
 #define M(T) &AreEqualForTesting<T>,
-static const AreEqualForTestingFunction
-    g_equal_for_testing_functions[kNumOpTypes] = {TYPES(M)};
+constexpr std::array<AreEqualForTestingFunction, kNumOpTypes>
+    g_equal_for_testing_functions = {TYPES(M)};
 #undef M
 
 // Most state ops (matrix, clip, save, restore) have a trivial destructor.
@@ -321,7 +323,8 @@
   !std::is_trivially_destructible<T>::value            \
       ? [](PaintOp* op) { static_cast<T*>(op)->~T(); } \
       : static_cast<VoidFunction>(nullptr),
-static const VoidFunction g_destructor_functions[kNumOpTypes] = {TYPES(M)};
+constexpr std::array<VoidFunction, kNumOpTypes> g_destructor_functions = {
+    TYPES(M)};
 #undef M
 
 #define M(T)                                         \
@@ -341,21 +344,23 @@
   [](PaintOpBuffer* buffer, const PaintOp* op) {       \
     buffer->AnalyzeAddedOp(static_cast<const T*>(op)); \
   },
-static const AnalyzeOpFunc g_analyze_op_functions[kNumOpTypes] = {TYPES(M)};
+constexpr std::array<AnalyzeOpFunc, kNumOpTypes> g_analyze_op_functions = {
+    TYPES(M)};
 #undef M
 
 }  // namespace
 
 #define M(T) PaintOpBuffer::ComputeOpAlignedSize<T>(),
-uint16_t PaintOp::g_type_to_aligned_size[kNumOpTypes] = {TYPES(M)};
+const std::array<uint16_t, kNumOpTypes> PaintOp::g_type_to_aligned_size = {
+    TYPES(M)};
 #undef M
 
 #define M(T) T::kIsDrawOp,
-bool PaintOp::g_is_draw_op[kNumOpTypes] = {TYPES(M)};
+const std::array<bool, kNumOpTypes> PaintOp::g_is_draw_op = {TYPES(M)};
 #undef M
 
 #define M(T) T::kHasPaintFlags,
-bool PaintOp::g_has_paint_flags[kNumOpTypes] = {TYPES(M)};
+const std::array<bool, kNumOpTypes> PaintOp::g_has_paint_flags = {TYPES(M)};
 #undef M
 
 const SkRect PaintOp::kUnsetRect = {SK_ScalarInfinity, 0, 0, 0};
@@ -402,6 +407,28 @@
   }
 }
 
+bool OpHasDrawTextOpsImpl(const PaintOp& op) {
+  switch (op.GetType()) {
+#define M(T)     \
+  case T::kType: \
+    return static_cast<const T&>(op).HasDrawTextOps();
+
+    TYPES(M)
+#undef M
+  }
+}
+
+size_t OpAdditionalOpCountImpl(const PaintOp& op) {
+  switch (op.GetType()) {
+#define M(T)     \
+  case T::kType: \
+    return static_cast<const T&>(op).AdditionalOpCount();
+
+    TYPES(M)
+#undef M
+  }
+}
+
 #undef TYPES
 
 std::ostream& operator<<(std::ostream& os, PaintOpType type) {
@@ -2320,6 +2347,16 @@
   return OpHasDiscardableImagesImpl(op);
 }
 
+// static
+bool PaintOp::OpHasDrawTextOps(const PaintOp& op) {
+  return OpHasDrawTextOpsImpl(op);
+}
+
+// static
+size_t PaintOp::OpAdditionalOpCount(const PaintOp& op) {
+  return OpAdditionalOpCountImpl(op);
+}
+
 void PaintOp::DestroyThis() {
   auto func = g_destructor_functions[type];
   if (func)
@@ -2444,22 +2481,22 @@
   return has_discardable_images;
 }
 
-AnnotateOp::AnnotateOp() : PaintOp(kType) {}
+AnnotateOp::AnnotateOp() : PaintOpBaseInternal(kType) {}
 
 AnnotateOp::AnnotateOp(PaintCanvas::AnnotationType annotation_type,
                        const SkRect& rect,
                        sk_sp<SkData> data)
-    : PaintOp(kType),
+    : PaintOpBaseInternal(kType),
       annotation_type(annotation_type),
       rect(rect),
       data(std::move(data)) {}
 
 AnnotateOp::~AnnotateOp() = default;
 
-DrawImageOp::DrawImageOp() : PaintOpWithFlags(kType) {}
+DrawImageOp::DrawImageOp() : PaintOpWithFlagsBaseInternal(kType) {}
 
 DrawImageOp::DrawImageOp(const PaintImage& image, SkScalar left, SkScalar top)
-    : PaintOpWithFlags(kType, PaintFlags()),
+    : PaintOpWithFlagsBaseInternal(kType, PaintFlags()),
       image(image),
       left(left),
       top(top) {}
@@ -2469,7 +2506,7 @@
                          SkScalar top,
                          const SkSamplingOptions& sampling,
                          const PaintFlags* flags)
-    : PaintOpWithFlags(kType, flags ? *flags : PaintFlags()),
+    : PaintOpWithFlagsBaseInternal(kType, flags ? *flags : PaintFlags()),
       image(image),
       left(left),
       top(top),
@@ -2486,13 +2523,13 @@
 
 DrawImageOp::~DrawImageOp() = default;
 
-DrawImageRectOp::DrawImageRectOp() : PaintOpWithFlags(kType) {}
+DrawImageRectOp::DrawImageRectOp() : PaintOpWithFlagsBaseInternal(kType) {}
 
 DrawImageRectOp::DrawImageRectOp(const PaintImage& image,
                                  const SkRect& src,
                                  const SkRect& dst,
                                  SkCanvas::SrcRectConstraint constraint)
-    : PaintOpWithFlags(kType, PaintFlags()),
+    : PaintOpWithFlagsBaseInternal(kType, PaintFlags()),
       image(image),
       src(src),
       dst(dst),
@@ -2504,7 +2541,7 @@
                                  const SkSamplingOptions& sampling,
                                  const PaintFlags* flags,
                                  SkCanvas::SrcRectConstraint constraint)
-    : PaintOpWithFlags(kType, flags ? *flags : PaintFlags()),
+    : PaintOpWithFlagsBaseInternal(kType, flags ? *flags : PaintFlags()),
       image(image),
       src(src),
       dst(dst),
@@ -2523,7 +2560,9 @@
 DrawImageRectOp::~DrawImageRectOp() = default;
 
 DrawRecordOp::DrawRecordOp(PaintRecord record, bool local_ctm)
-    : PaintOp(kType), record(std::move(record)), local_ctm(local_ctm) {}
+    : PaintOpBaseInternal(kType),
+      record(std::move(record)),
+      local_ctm(local_ctm) {}
 
 DrawRecordOp::~DrawRecordOp() = default;
 
@@ -2538,7 +2577,7 @@
 DrawScrollingContentsOp::DrawScrollingContentsOp(
     ElementId scroll_element_id,
     scoped_refptr<DisplayItemList> display_item_list)
-    : PaintOp(kType),
+    : PaintOpBaseInternal(kType),
       scroll_element_id(scroll_element_id),
       display_item_list(std::move(display_item_list)) {}
 
@@ -2552,14 +2591,14 @@
   return display_item_list->TotalOpCount();
 }
 
-DrawVerticesOp::DrawVerticesOp() : PaintOpWithFlags(kType) {}
+DrawVerticesOp::DrawVerticesOp() : PaintOpWithFlagsBaseInternal(kType) {}
 
 DrawVerticesOp::DrawVerticesOp(
     scoped_refptr<RefCountedBuffer<SkPoint>> vertices,
     scoped_refptr<RefCountedBuffer<SkPoint>> uvs,
     scoped_refptr<RefCountedBuffer<uint16_t>> indices,
     const PaintFlags& flags)
-    : PaintOpWithFlags(kType, flags),
+    : PaintOpWithFlagsBaseInternal(kType, flags),
       vertices(std::move(vertices)),
       uvs(std::move(uvs)),
       indices(std::move(indices)) {}
@@ -2572,7 +2611,7 @@
                              SkottieFrameDataMap images,
                              const SkottieColorMap& color_map,
                              SkottieTextPropertyValueMap text_map)
-    : PaintOp(kType),
+    : PaintOpBaseInternal(kType),
       skottie(std::move(skottie)),
       dst(dst),
       t(t),
@@ -2580,7 +2619,7 @@
       color_map(color_map),
       text_map(std::move(text_map)) {}
 
-DrawSkottieOp::DrawSkottieOp() : PaintOp(kType) {}
+DrawSkottieOp::DrawSkottieOp() : PaintOpBaseInternal(kType) {}
 
 DrawSkottieOp::~DrawSkottieOp() = default;
 
@@ -2598,20 +2637,23 @@
   return true;
 }
 
-DrawTextBlobOp::DrawTextBlobOp() : PaintOpWithFlags(kType) {}
+DrawTextBlobOp::DrawTextBlobOp() : PaintOpWithFlagsBaseInternal(kType) {}
 
 DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob,
                                SkScalar x,
                                SkScalar y,
                                const PaintFlags& flags)
-    : PaintOpWithFlags(kType, flags), blob(std::move(blob)), x(x), y(y) {}
+    : PaintOpWithFlagsBaseInternal(kType, flags),
+      blob(std::move(blob)),
+      x(x),
+      y(y) {}
 
 DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob,
                                SkScalar x,
                                SkScalar y,
                                NodeId node_id,
                                const PaintFlags& flags)
-    : PaintOpWithFlags(kType, flags),
+    : PaintOpWithFlagsBaseInternal(kType, flags),
       blob(std::move(blob)),
       x(x),
       y(y),
@@ -2619,19 +2661,21 @@
 
 DrawTextBlobOp::~DrawTextBlobOp() = default;
 
-DrawSlugOp::DrawSlugOp() : PaintOpWithFlags(kType) {}
+DrawSlugOp::DrawSlugOp() : PaintOpWithFlagsBaseInternal(kType) {}
 
 DrawSlugOp::DrawSlugOp(sk_sp<sktext::gpu::Slug> slug, const PaintFlags& flags)
-    : PaintOpWithFlags(kType, flags), slug(std::move(slug)) {}
+    : PaintOpWithFlagsBaseInternal(kType, flags), slug(std::move(slug)) {}
 
 DrawSlugOp::~DrawSlugOp() = default;
 
 SaveLayerFiltersOp::SaveLayerFiltersOp(
     base::span<const sk_sp<PaintFilter>> filters,
     const PaintFlags& flags)
-    : PaintOpWithFlags(kType, flags), filters(filters.begin(), filters.end()) {}
+    : PaintOpWithFlagsBaseInternal(kType, flags),
+      filters(filters.begin(), filters.end()) {}
 
-SaveLayerFiltersOp::SaveLayerFiltersOp() : PaintOpWithFlags(kType) {}
+SaveLayerFiltersOp::SaveLayerFiltersOp()
+    : PaintOpWithFlagsBaseInternal(kType) {}
 
 SaveLayerFiltersOp::~SaveLayerFiltersOp() = default;
 
diff --git a/cc/paint/paint_op.h b/cc/paint/paint_op.h
index 31c9b4c..c5c0a454 100644
--- a/cc/paint/paint_op.h
+++ b/cc/paint/paint_op.h
@@ -130,13 +130,18 @@
 
 class CC_PAINT_EXPORT PaintOp {
  public:
+  PaintOp(const PaintOp&) = delete;
+  PaintOp& operator=(const PaintOp&) = delete;
+
+  // Run the destructor for the derived op type.  Ops are usually contained in
+  // memory buffers and so don't have their destructors run automatically.
+  void DestroyThis();
+
   uint8_t type;
 
   using SerializeOptions = PaintOpBuffer::SerializeOptions;
   using DeserializeOptions = PaintOpBuffer::DeserializeOptions;
 
-  explicit PaintOp(PaintOpType type) : type(static_cast<uint8_t>(type)) {}
-
   PaintOpType GetType() const { return static_cast<PaintOpType>(type); }
 
   // Subclasses should provide a static Raster() method which is called from
@@ -212,12 +217,36 @@
   // generated images.
   static bool OpHasDiscardableImages(const PaintOp& op);
 
-  // Gets the maximum content color usage of all images in this PaintOp.
-  gfx::ContentColorUsage GetContentColorUsage() const;
+  // Returns true if the op contains any draw text operations.
+  static bool OpHasDrawTextOps(const PaintOp& op);
+
+  static size_t OpAdditionalOpCount(const PaintOp& op);
 
   // Returns true if the given op type has PaintFlags.
   static bool TypeHasFlags(PaintOpType type);
 
+  // kDrawColor is more restrictive on the blend modes that can be used.
+  static bool IsValidDrawColorSkBlendMode(SkBlendMode mode) {
+    return static_cast<uint32_t>(mode) <=
+           static_cast<uint32_t>(SkBlendMode::kLastCoeffMode);
+  }
+
+  // PaintFlags can have more complex blend modes than kDrawColor.
+  static bool IsValidPaintFlagsSkBlendMode(SkBlendMode mode) {
+    return static_cast<uint32_t>(mode) <=
+           static_cast<uint32_t>(SkBlendMode::kLastMode);
+  }
+
+  static constexpr size_t kNumOpTypes =
+      static_cast<size_t>(PaintOpType::kLastPaintOpType) + 1;
+
+  static constexpr bool kIsDrawOp = false;
+  static constexpr bool kHasPaintFlags = false;
+
+ protected:
+  explicit PaintOp(PaintOpType type) : type(static_cast<uint8_t>(type)) {}
+  ~PaintOp() = default;
+
   int CountSlowPaths() const { return 0; }
   int CountSlowPathsFromFlags() const { return 0; }
 
@@ -247,22 +276,6 @@
   // Returns the number of ops in referenced sub records and display lists.
   size_t AdditionalOpCount() const { return 0; }
 
-  // Run the destructor for the derived op type.  Ops are usually contained in
-  // memory buffers and so don't have their destructors run automatically.
-  void DestroyThis();
-
-  // kDrawColor is more restrictive on the blend modes that can be used.
-  static bool IsValidDrawColorSkBlendMode(SkBlendMode mode) {
-    return static_cast<uint32_t>(mode) <=
-           static_cast<uint32_t>(SkBlendMode::kLastCoeffMode);
-  }
-
-  // PaintFlags can have more complex blend modes than kDrawColor.
-  static bool IsValidPaintFlagsSkBlendMode(SkBlendMode mode) {
-    return static_cast<uint32_t>(mode) <=
-           static_cast<uint32_t>(SkBlendMode::kLastMode);
-  }
-
   static bool IsValidSkClipOp(SkClipOp op) {
     return static_cast<uint32_t>(op) <=
            static_cast<uint32_t>(SkClipOp::kMax_EnumValue);
@@ -278,31 +291,18 @@
     return IsUnsetRect(rect) || rect.isFinite();
   }
 
-  static constexpr size_t kNumOpTypes =
-      static_cast<size_t>(PaintOpType::kLastPaintOpType) + 1;
-  static bool g_is_draw_op[kNumOpTypes];
-  static bool g_has_paint_flags[kNumOpTypes];
-  static uint16_t g_type_to_aligned_size[kNumOpTypes];
+  static const std::array<bool, kNumOpTypes> g_is_draw_op;
+  static const std::array<bool, kNumOpTypes> g_has_paint_flags;
+  static const std::array<uint16_t, kNumOpTypes> g_type_to_aligned_size;
 
-  static constexpr bool kIsDrawOp = false;
-  static constexpr bool kHasPaintFlags = false;
   static const SkRect kUnsetRect;
-
-  PaintOp(const PaintOp&) = delete;
-  PaintOp& operator=(const PaintOp&) = delete;
-
- protected:
-  ~PaintOp() = default;
 };
 
 class CC_PAINT_EXPORT PaintOpWithFlags : public PaintOp {
  public:
   static constexpr bool kHasPaintFlags = true;
-  PaintOpWithFlags(PaintOpType type, const PaintFlags& flags)
-      : PaintOp(type), flags(flags) {}
 
   int CountSlowPathsFromFlags() const { return flags.getPathEffect() ? 1 : 0; }
-  bool HasNonAAPaint() const { return !flags.isAntiAlias(); }
   bool HasDiscardableImagesFromFlags(
       gfx::ContentColorUsage* content_color_usage) const;
 
@@ -319,12 +319,43 @@
   PaintFlags flags;
 
  protected:
+  PaintOpWithFlags(PaintOpType type, const PaintFlags& flags)
+      : PaintOp(type), flags(flags) {}
+  explicit PaintOpWithFlags(PaintOpType type) : PaintOp(type) {}
   ~PaintOpWithFlags() = default;
 
-  explicit PaintOpWithFlags(PaintOpType type) : PaintOp(type) {}
+  bool HasNonAAPaint() const { return !flags.isAntiAlias(); }
 };
 
-class CC_PAINT_EXPORT AnnotateOp final : public PaintOp {
+// The internal types make the non-runtime-polymorphic functions (which are
+// protected in PaintOp[WithFlags] to prevent bugs where the functions are
+// incorrectly used outside of paint_op.{h,cc}) public in subclasses.
+
+#define INTERNAL_PAINTOP_BASE_TYPE(type, super)                \
+  class type : public super {                                  \
+   public:                                                     \
+    using super::CountSlowPaths;                               \
+    using super::CountSlowPathsFromFlags;                      \
+    using super::HasNonAAPaint;                                \
+    using super::HasDrawTextOps;                               \
+    using super::HasSaveLayerOps;                              \
+    using super::HasSaveLayerAlphaOps;                         \
+    using super::HasEffectsPreventingLCDTextForSaveLayerAlpha; \
+    using super::HasDiscardableImages;                         \
+    using super::HasDiscardableImagesFromFlags;                \
+    using super::AdditionalBytesUsed;                          \
+    using super::AdditionalOpCount;                            \
+                                                               \
+   protected:                                                  \
+    using super::super;                                        \
+  }
+
+INTERNAL_PAINTOP_BASE_TYPE(PaintOpBaseInternal, PaintOp);
+INTERNAL_PAINTOP_BASE_TYPE(PaintOpWithFlagsBaseInternal, PaintOpWithFlags);
+
+#undef INTERNAL_PAINTOP_BASE_TYPE
+
+class CC_PAINT_EXPORT AnnotateOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kAnnotate;
   AnnotateOp(PaintCanvas::AnnotationType annotation_type,
@@ -346,14 +377,14 @@
   AnnotateOp();
 };
 
-class CC_PAINT_EXPORT ClipPathOp final : public PaintOp {
+class CC_PAINT_EXPORT ClipPathOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kClipPath;
   ClipPathOp(SkPath path,
              SkClipOp op,
              bool antialias,
              UsePaintCache use_paint_cache = UsePaintCache::kEnabled)
-      : PaintOp(kType),
+      : PaintOpBaseInternal(kType),
         path(path),
         op(op),
         antialias(antialias),
@@ -373,14 +404,14 @@
   UsePaintCache use_cache = UsePaintCache::kDisabled;
 
  private:
-  ClipPathOp() : PaintOp(kType) {}
+  ClipPathOp() : PaintOpBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT ClipRectOp final : public PaintOp {
+class CC_PAINT_EXPORT ClipRectOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kClipRect;
   ClipRectOp(const SkRect& rect, SkClipOp op, bool antialias)
-      : PaintOp(kType), rect(rect), op(op), antialias(antialias) {}
+      : PaintOpBaseInternal(kType), rect(rect), op(op), antialias(antialias) {}
   static void Raster(const ClipRectOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
@@ -393,14 +424,17 @@
   bool antialias;
 
  private:
-  ClipRectOp() : PaintOp(kType) {}
+  ClipRectOp() : PaintOpBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT ClipRRectOp final : public PaintOp {
+class CC_PAINT_EXPORT ClipRRectOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kClipRRect;
   ClipRRectOp(const SkRRect& rrect, SkClipOp op, bool antialias)
-      : PaintOp(kType), rrect(rrect), op(op), antialias(antialias) {}
+      : PaintOpBaseInternal(kType),
+        rrect(rrect),
+        op(op),
+        antialias(antialias) {}
   static void Raster(const ClipRRectOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
@@ -414,13 +448,14 @@
   bool antialias;
 
  private:
-  ClipRRectOp() : PaintOp(kType) {}
+  ClipRRectOp() : PaintOpBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT ConcatOp final : public PaintOp {
+class CC_PAINT_EXPORT ConcatOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kConcat;
-  explicit ConcatOp(const SkM44& matrix) : PaintOp(kType), matrix(matrix) {}
+  explicit ConcatOp(const SkM44& matrix)
+      : PaintOpBaseInternal(kType), matrix(matrix) {}
   static void Raster(const ConcatOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
@@ -431,13 +466,13 @@
   SkM44 matrix;
 
  private:
-  ConcatOp() : PaintOp(kType) {}
+  ConcatOp() : PaintOpBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT CustomDataOp final : public PaintOp {
+class CC_PAINT_EXPORT CustomDataOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kCustomData;
-  explicit CustomDataOp(uint32_t id) : PaintOp(kType), id(id) {}
+  explicit CustomDataOp(uint32_t id) : PaintOpBaseInternal(kType), id(id) {}
   static void Raster(const CustomDataOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
@@ -449,15 +484,15 @@
   uint32_t id;
 
  private:
-  CustomDataOp() : PaintOp(kType) {}
+  CustomDataOp() : PaintOpBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT DrawColorOp final : public PaintOp {
+class CC_PAINT_EXPORT DrawColorOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawColor;
   static constexpr bool kIsDrawOp = true;
   DrawColorOp(SkColor4f color, SkBlendMode mode)
-      : PaintOp(kType), color(color), mode(mode) {}
+      : PaintOpBaseInternal(kType), color(color), mode(mode) {}
   static void Raster(const DrawColorOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
@@ -469,17 +504,19 @@
   SkBlendMode mode;
 
  private:
-  DrawColorOp() : PaintOp(kType) {}
+  DrawColorOp() : PaintOpBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT DrawDRRectOp final : public PaintOpWithFlags {
+class CC_PAINT_EXPORT DrawDRRectOp final : public PaintOpWithFlagsBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawDRRect;
   static constexpr bool kIsDrawOp = true;
   DrawDRRectOp(const SkRRect& outer,
                const SkRRect& inner,
                const PaintFlags& flags)
-      : PaintOpWithFlags(kType, flags), outer(outer), inner(inner) {}
+      : PaintOpWithFlagsBaseInternal(kType, flags),
+        outer(outer),
+        inner(inner) {}
   static void RasterWithFlags(const DrawDRRectOp* op,
                               const PaintFlags* flags,
                               SkCanvas* canvas,
@@ -494,10 +531,10 @@
   SkRRect inner;
 
  private:
-  DrawDRRectOp() : PaintOpWithFlags(kType) {}
+  DrawDRRectOp() : PaintOpWithFlagsBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT DrawImageOp final : public PaintOpWithFlags {
+class CC_PAINT_EXPORT DrawImageOp final : public PaintOpWithFlagsBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawImage;
   static constexpr bool kIsDrawOp = true;
@@ -535,7 +572,8 @@
   SkSize scale_adjustment = SkSize::Make(1.f, 1.f);
 };
 
-class CC_PAINT_EXPORT DrawImageRectOp final : public PaintOpWithFlags {
+class CC_PAINT_EXPORT DrawImageRectOp final
+    : public PaintOpWithFlagsBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawImageRect;
   static constexpr bool kIsDrawOp = true;
@@ -578,12 +616,12 @@
   SkSize scale_adjustment = SkSize::Make(1.f, 1.f);
 };
 
-class CC_PAINT_EXPORT DrawIRectOp final : public PaintOpWithFlags {
+class CC_PAINT_EXPORT DrawIRectOp final : public PaintOpWithFlagsBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawIRect;
   static constexpr bool kIsDrawOp = true;
   DrawIRectOp(const SkIRect& rect, const PaintFlags& flags)
-      : PaintOpWithFlags(kType, flags), rect(rect) {}
+      : PaintOpWithFlagsBaseInternal(kType, flags), rect(rect) {}
   static void RasterWithFlags(const DrawIRectOp* op,
                               const PaintFlags* flags,
                               SkCanvas* canvas,
@@ -596,10 +634,10 @@
   SkIRect rect;
 
  private:
-  DrawIRectOp() : PaintOpWithFlags(kType) {}
+  DrawIRectOp() : PaintOpWithFlagsBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT DrawLineOp final : public PaintOpWithFlags {
+class CC_PAINT_EXPORT DrawLineOp final : public PaintOpWithFlagsBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawLine;
   static constexpr bool kIsDrawOp = true;
@@ -609,7 +647,7 @@
              SkScalar y1,
              const PaintFlags& flags,
              bool draw_as_path = false)
-      : PaintOpWithFlags(kType, flags),
+      : PaintOpWithFlagsBaseInternal(kType, flags),
         x0(x0),
         y0(y0),
         x1(x1),
@@ -635,11 +673,11 @@
   bool draw_as_path;
 
  private:
-  DrawLineOp() : PaintOpWithFlags(kType) {}
+  DrawLineOp() : PaintOpWithFlagsBaseInternal(kType) {}
 };
 
 // TODO(crbug.com/340122178): figure out a better way to unify types.
-class CC_PAINT_EXPORT DrawLineLiteOp final : public PaintOp {
+class CC_PAINT_EXPORT DrawLineLiteOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawLineLite;
   static constexpr bool kIsDrawOp = true;
@@ -648,7 +686,7 @@
                  SkScalar x1,
                  SkScalar y1,
                  const CorePaintFlags& core_paint_flags)
-      : PaintOp(kType),
+      : PaintOpBaseInternal(kType),
         x0(x0),
         y0(y0),
         x1(x1),
@@ -670,11 +708,11 @@
   CorePaintFlags core_paint_flags;
 
  private:
-  DrawLineLiteOp() : PaintOp(kType) {}
+  DrawLineLiteOp() : PaintOpBaseInternal(kType) {}
 };
 
 // TODO(crbug.com/340122178): figure out a better way to unify types.
-class CC_PAINT_EXPORT DrawArcLiteOp final : public PaintOp {
+class CC_PAINT_EXPORT DrawArcLiteOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawArcLite;
   static constexpr bool kIsDrawOp = true;
@@ -682,7 +720,7 @@
                 SkScalar start_angle_degrees,
                 SkScalar sweep_angle_degrees,
                 const CorePaintFlags& core_paint_flags)
-      : PaintOp(kType),
+      : PaintOpBaseInternal(kType),
         oval(oval),
         start_angle_degrees(start_angle_degrees),
         sweep_angle_degrees(sweep_angle_degrees),
@@ -704,10 +742,10 @@
   CorePaintFlags core_paint_flags;
 
  private:
-  DrawArcLiteOp() : PaintOp(kType) {}
+  DrawArcLiteOp() : PaintOpBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT DrawArcOp final : public PaintOpWithFlags {
+class CC_PAINT_EXPORT DrawArcOp final : public PaintOpWithFlagsBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawArc;
   static constexpr bool kIsDrawOp = true;
@@ -715,7 +753,7 @@
             SkScalar start_angle_degrees,
             SkScalar sweep_angle_degrees,
             const PaintFlags& flags)
-      : PaintOpWithFlags(kType, flags),
+      : PaintOpWithFlagsBaseInternal(kType, flags),
         oval(oval),
         start_angle_degrees(start_angle_degrees),
         sweep_angle_degrees(sweep_angle_degrees) {}
@@ -738,15 +776,15 @@
   SkScalar sweep_angle_degrees;
 
  private:
-  DrawArcOp() : PaintOpWithFlags(kType) {}
+  DrawArcOp() : PaintOpWithFlagsBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT DrawOvalOp final : public PaintOpWithFlags {
+class CC_PAINT_EXPORT DrawOvalOp final : public PaintOpWithFlagsBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawOval;
   static constexpr bool kIsDrawOp = true;
   DrawOvalOp(const SkRect& oval, const PaintFlags& flags)
-      : PaintOpWithFlags(kType, flags), oval(oval) {}
+      : PaintOpWithFlagsBaseInternal(kType, flags), oval(oval) {}
   static void RasterWithFlags(const DrawOvalOp* op,
                               const PaintFlags* flags,
                               SkCanvas* canvas,
@@ -758,17 +796,17 @@
   SkRect oval;
 
  private:
-  DrawOvalOp() : PaintOpWithFlags(kType) {}
+  DrawOvalOp() : PaintOpWithFlagsBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT DrawPathOp final : public PaintOpWithFlags {
+class CC_PAINT_EXPORT DrawPathOp final : public PaintOpWithFlagsBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawPath;
   static constexpr bool kIsDrawOp = true;
   DrawPathOp(const SkPath& path,
              const PaintFlags& flags,
              UsePaintCache use_paint_cache = UsePaintCache::kEnabled)
-      : PaintOpWithFlags(kType, flags),
+      : PaintOpWithFlagsBaseInternal(kType, flags),
         path(path),
         sk_path_fill_type(static_cast<uint8_t>(path.getFillType())),
         use_cache(use_paint_cache) {}
@@ -791,10 +829,10 @@
   UsePaintCache use_cache = UsePaintCache::kDisabled;
 
  private:
-  DrawPathOp() : PaintOpWithFlags(kType) {}
+  DrawPathOp() : PaintOpWithFlagsBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT DrawRecordOp final : public PaintOp {
+class CC_PAINT_EXPORT DrawRecordOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawRecord;
   static constexpr bool kIsDrawOp = true;
@@ -829,12 +867,12 @@
   bool local_ctm = true;
 };
 
-class CC_PAINT_EXPORT DrawRectOp final : public PaintOpWithFlags {
+class CC_PAINT_EXPORT DrawRectOp final : public PaintOpWithFlagsBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawRect;
   static constexpr bool kIsDrawOp = true;
   DrawRectOp(const SkRect& rect, const PaintFlags& flags)
-      : PaintOpWithFlags(kType, flags), rect(rect) {}
+      : PaintOpWithFlagsBaseInternal(kType, flags), rect(rect) {}
   static void RasterWithFlags(const DrawRectOp* op,
                               const PaintFlags* flags,
                               SkCanvas* canvas,
@@ -846,15 +884,15 @@
   SkRect rect;
 
  private:
-  DrawRectOp() : PaintOpWithFlags(kType) {}
+  DrawRectOp() : PaintOpWithFlagsBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT DrawRRectOp final : public PaintOpWithFlags {
+class CC_PAINT_EXPORT DrawRRectOp final : public PaintOpWithFlagsBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawRRect;
   static constexpr bool kIsDrawOp = true;
   DrawRRectOp(const SkRRect& rrect, const PaintFlags& flags)
-      : PaintOpWithFlags(kType, flags), rrect(rrect) {}
+      : PaintOpWithFlagsBaseInternal(kType, flags), rrect(rrect) {}
   static void RasterWithFlags(const DrawRRectOp* op,
                               const PaintFlags* flags,
                               SkCanvas* canvas,
@@ -866,7 +904,7 @@
   SkRRect rrect;
 
  private:
-  DrawRRectOp() : PaintOpWithFlags(kType) {}
+  DrawRRectOp() : PaintOpWithFlagsBaseInternal(kType) {}
 };
 
 // This is used to draw non-composited scrolling contents. The display item
@@ -875,7 +913,8 @@
 // current clip of the canvas and the current scroll offset and will be applied
 // to the display item list. This PaintOp doesn't apply the overflow clip of
 // the scroller, but the client should emit ClipRectOp.
-class CC_PAINT_EXPORT DrawScrollingContentsOp final : public PaintOp {
+class CC_PAINT_EXPORT DrawScrollingContentsOp final
+    : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawScrollingContents;
   static constexpr bool kIsDrawOp = true;
@@ -902,7 +941,8 @@
   scoped_refptr<DisplayItemList> display_item_list;
 };
 
-class CC_PAINT_EXPORT DrawVerticesOp final : public PaintOpWithFlags {
+class CC_PAINT_EXPORT DrawVerticesOp final
+    : public PaintOpWithFlagsBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawVertices;
   static constexpr bool kIsDrawOp = true;
@@ -936,7 +976,7 @@
   DrawVerticesOp();
 };
 
-class CC_PAINT_EXPORT DrawSkottieOp final : public PaintOp {
+class CC_PAINT_EXPORT DrawSkottieOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawSkottie;
   static constexpr bool kIsDrawOp = true;
@@ -983,7 +1023,7 @@
   DrawSkottieOp();
 };
 
-class CC_PAINT_EXPORT DrawSlugOp final : public PaintOpWithFlags {
+class CC_PAINT_EXPORT DrawSlugOp final : public PaintOpWithFlagsBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawSlug;
   static constexpr bool kIsDrawOp = true;
@@ -1011,7 +1051,8 @@
   DrawSlugOp();
 };
 
-class CC_PAINT_EXPORT DrawTextBlobOp final : public PaintOpWithFlags {
+class CC_PAINT_EXPORT DrawTextBlobOp final
+    : public PaintOpWithFlagsBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kDrawTextBlob;
   static constexpr bool kIsDrawOp = true;
@@ -1046,10 +1087,10 @@
   DrawTextBlobOp();
 };
 
-class CC_PAINT_EXPORT NoopOp final : public PaintOp {
+class CC_PAINT_EXPORT NoopOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kNoop;
-  NoopOp() : PaintOp(kType) {}
+  NoopOp() : PaintOpBaseInternal(kType) {}
   static void Raster(const NoopOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params) {}
@@ -1058,10 +1099,10 @@
   HAS_SERIALIZATION_FUNCTIONS();
 };
 
-class CC_PAINT_EXPORT RestoreOp final : public PaintOp {
+class CC_PAINT_EXPORT RestoreOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kRestore;
-  RestoreOp() : PaintOp(kType) {}
+  RestoreOp() : PaintOpBaseInternal(kType) {}
   static void Raster(const RestoreOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
@@ -1070,10 +1111,11 @@
   HAS_SERIALIZATION_FUNCTIONS();
 };
 
-class CC_PAINT_EXPORT RotateOp final : public PaintOp {
+class CC_PAINT_EXPORT RotateOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kRotate;
-  explicit RotateOp(SkScalar degrees) : PaintOp(kType), degrees(degrees) {}
+  explicit RotateOp(SkScalar degrees)
+      : PaintOpBaseInternal(kType), degrees(degrees) {}
   static void Raster(const RotateOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
@@ -1084,13 +1126,13 @@
   SkScalar degrees;
 
  private:
-  RotateOp() : PaintOp(kType) {}
+  RotateOp() : PaintOpBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT SaveOp final : public PaintOp {
+class CC_PAINT_EXPORT SaveOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kSave;
-  SaveOp() : PaintOp(kType) {}
+  SaveOp() : PaintOpBaseInternal(kType) {}
   static void Raster(const SaveOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
@@ -1099,13 +1141,13 @@
   HAS_SERIALIZATION_FUNCTIONS();
 };
 
-class CC_PAINT_EXPORT SaveLayerOp final : public PaintOpWithFlags {
+class CC_PAINT_EXPORT SaveLayerOp final : public PaintOpWithFlagsBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kSaveLayer;
   explicit SaveLayerOp(const PaintFlags& flags)
-      : PaintOpWithFlags(kType, flags), bounds(kUnsetRect) {}
+      : PaintOpWithFlagsBaseInternal(kType, flags), bounds(kUnsetRect) {}
   SaveLayerOp(const SkRect& bounds, const PaintFlags& flags)
-      : PaintOpWithFlags(kType, flags), bounds(bounds) {}
+      : PaintOpWithFlagsBaseInternal(kType, flags), bounds(bounds) {}
   static void RasterWithFlags(const SaveLayerOp* op,
                               const PaintFlags* flags,
                               SkCanvas* canvas,
@@ -1123,18 +1165,18 @@
   SkRect bounds;
 
  private:
-  SaveLayerOp() : PaintOpWithFlags(kType) {}
+  SaveLayerOp() : PaintOpWithFlagsBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT SaveLayerAlphaOp final : public PaintOp {
+class CC_PAINT_EXPORT SaveLayerAlphaOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kSaveLayerAlpha;
   template <class F, class = std::enable_if_t<std::is_same_v<F, float>>>
   explicit SaveLayerAlphaOp(F alpha)
-      : PaintOp(kType), bounds(kUnsetRect), alpha(alpha) {}
+      : PaintOpBaseInternal(kType), bounds(kUnsetRect), alpha(alpha) {}
   template <class F, class = std::enable_if_t<std::is_same_v<F, float>>>
   SaveLayerAlphaOp(const SkRect& bounds, F alpha)
-      : PaintOp(kType), bounds(bounds), alpha(alpha) {}
+      : PaintOpBaseInternal(kType), bounds(bounds), alpha(alpha) {}
   static void Raster(const SaveLayerAlphaOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
@@ -1148,10 +1190,11 @@
   float alpha;
 
  private:
-  SaveLayerAlphaOp() : PaintOp(kType) {}
+  SaveLayerAlphaOp() : PaintOpBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT SaveLayerFiltersOp final : public PaintOpWithFlags {
+class CC_PAINT_EXPORT SaveLayerFiltersOp final
+    : public PaintOpWithFlagsBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kSaveLayerFilters;
   explicit SaveLayerFiltersOp(base::span<const sk_sp<PaintFilter>> filters,
@@ -1174,10 +1217,11 @@
   SaveLayerFiltersOp();
 };
 
-class CC_PAINT_EXPORT ScaleOp final : public PaintOp {
+class CC_PAINT_EXPORT ScaleOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kScale;
-  ScaleOp(SkScalar sx, SkScalar sy) : PaintOp(kType), sx(sx), sy(sy) {}
+  ScaleOp(SkScalar sx, SkScalar sy)
+      : PaintOpBaseInternal(kType), sx(sx), sy(sy) {}
   static void Raster(const ScaleOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
@@ -1189,13 +1233,14 @@
   SkScalar sy;
 
  private:
-  ScaleOp() : PaintOp(kType) {}
+  ScaleOp() : PaintOpBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT SetMatrixOp final : public PaintOp {
+class CC_PAINT_EXPORT SetMatrixOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kSetMatrix;
-  explicit SetMatrixOp(const SkM44& matrix) : PaintOp(kType), matrix(matrix) {}
+  explicit SetMatrixOp(const SkM44& matrix)
+      : PaintOpBaseInternal(kType), matrix(matrix) {}
   // This is the only op that needs the original ctm of the SkCanvas
   // used for raster (since kSetMatrix is relative to the recording origin and
   // shouldn't clobber the SkCanvas raster origin).
@@ -1212,13 +1257,14 @@
   SkM44 matrix;
 
  private:
-  SetMatrixOp() : PaintOp(kType) {}
+  SetMatrixOp() : PaintOpBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT SetNodeIdOp final : public PaintOp {
+class CC_PAINT_EXPORT SetNodeIdOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kSetNodeId;
-  explicit SetNodeIdOp(int node_id) : PaintOp(kType), node_id(node_id) {}
+  explicit SetNodeIdOp(int node_id)
+      : PaintOpBaseInternal(kType), node_id(node_id) {}
   static void Raster(const SetNodeIdOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
@@ -1229,13 +1275,14 @@
   int node_id;
 
  private:
-  SetNodeIdOp() : PaintOp(kType) {}
+  SetNodeIdOp() : PaintOpBaseInternal(kType) {}
 };
 
-class CC_PAINT_EXPORT TranslateOp final : public PaintOp {
+class CC_PAINT_EXPORT TranslateOp final : public PaintOpBaseInternal {
  public:
   static constexpr PaintOpType kType = PaintOpType::kTranslate;
-  TranslateOp(SkScalar dx, SkScalar dy) : PaintOp(kType), dx(dx), dy(dy) {}
+  TranslateOp(SkScalar dx, SkScalar dy)
+      : PaintOpBaseInternal(kType), dx(dx), dy(dy) {}
   static void Raster(const TranslateOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
@@ -1247,7 +1294,7 @@
   SkScalar dy;
 
  private:
-  TranslateOp() : PaintOp(kType) {}
+  TranslateOp() : PaintOpBaseInternal(kType) {}
 };
 
 #undef HAS_SERIALIZATION_FUNCTIONS
diff --git a/cc/trees/frame_rate_estimator.cc b/cc/trees/frame_rate_estimator.cc
index d2e4898..01d2203 100644
--- a/cc/trees/frame_rate_estimator.cc
+++ b/cc/trees/frame_rate_estimator.cc
@@ -5,8 +5,10 @@
 #include "cc/trees/frame_rate_estimator.h"
 
 #include "base/feature_list.h"
+#include "base/strings/stringprintf.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
 #include "cc/base/features.h"
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
 
@@ -43,6 +45,15 @@
 }
 
 void FrameRateEstimator::WillDraw(base::TimeTicks now) {
+  TRACE_EVENT1(
+      "cc,benchmark", "FrameRateEstimator::WillDraw", "Info",
+      base::StringPrintf("num_did_not_produce_frame_since_last_draw: %" PRIu64
+                         "\nin_video_conference_mode: %d\ninput_priority_mode: "
+                         "%d\nkNumDidNotProduceFrameBeforeThrottle: %d",
+                         num_did_not_produce_frame_since_last_draw_,
+                         in_video_conference_mode_, input_priority_mode_,
+                         features::kNumDidNotProduceFrameBeforeThrottle.Get()));
+
   num_did_not_produce_frame_since_last_draw_ = 0u;
   if (!in_video_conference_mode_ || input_priority_mode_) {
     return;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 6f28150..a14c069 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -3381,6 +3381,23 @@
 
 void LayerTreeHostImpl::DidNotProduceFrame(const viz::BeginFrameAck& ack,
                                            FrameSkippedReason reason) {
+  TRACE_EVENT2(
+      "cc,benchmark", "LayerTreeHostImpl::DidNotProduceFrame",
+      "FrameSkippedReason",
+      [](FrameSkippedReason reason) {
+        switch (reason) {
+          case FrameSkippedReason::kRecoverLatency:
+            return "kRecoverLatency";
+          case FrameSkippedReason::kNoDamage:
+            return "kNoDamage";
+          case FrameSkippedReason::kWaitingOnMain:
+            return "kWaitingOnMain";
+          case FrameSkippedReason::kDrawThrottled:
+            return "kDrawThrottled";
+        }
+        return "";
+      }(reason),
+      "Frame Sequence Number", ack.frame_id.sequence_number);
   frame_rate_estimator_.DidNotProduceFrame();
   if (layer_tree_frame_sink_) {
     static const bool feature_allowed = base::FeatureList::IsEnabled(
diff --git a/chrome/VERSION b/chrome/VERSION
index 6904b33..7ee5af02 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=133
 MINOR=0
-BUILD=6901
+BUILD=6902
 PATCH=0
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni
index 58b4b2f1..db76eaba 100644
--- a/chrome/android/chrome_junit_test_java_sources.gni
+++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -363,6 +363,7 @@
   "junit/src/org/chromium/chrome/browser/sync/LocalDataDescriptionTest.java",
   "junit/src/org/chromium/chrome/browser/sync/SyncErrorNotifierTest.java",
   "junit/src/org/chromium/chrome/browser/sync/ui/SyncErrorMessageImpressionTrackerTest.java",
+  "junit/src/org/chromium/chrome/browser/sync/ui/bookmark_batch_upload_card/BookmarkBatchUploadCardMediatorTest.java",
   "junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java",
   "junit/src/org/chromium/chrome/browser/tab/TabArchiveSettingsTest.java",
   "junit/src/org/chromium/chrome/browser/tab/TabAttributesTest.java",
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java
index 4e72982..996d356c 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java
@@ -189,13 +189,6 @@
                         resetTabStrip();
                     }
 
-                    // TODO(crbug/41496693): Delete this logic once tab groups with one tab are
-                    // launched.
-                    @Override
-                    public void willCloseTab(Tab tab, boolean didCloseAlone) {
-                        resetTabStrip();
-                    }
-
                     @Override
                     public void didAddTab(
                             Tab tab,
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediatorUnitTest.java
index 5ce6299..1d65dca 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediatorUnitTest.java
@@ -560,27 +560,6 @@
     }
 
     @Test
-    public void tabClosure_NotLastTabInGroup_Selection_SingleTabGroupsDisabled() {
-        initAndAssertProperties(mTab2);
-
-        doReturn(mTab3).when(mTabGroupModelFilter).getGroupLastShownTab(TAB2_ROOT_ID);
-        doReturn(false).when(mTabGroupModelFilter).isTabInTabGroup(mTab2);
-        doReturn(false).when(mTabGroupModelFilter).isTabInTabGroup(mTab3);
-
-        // Mock closing tab 2, and tab 3 then gets selected. They are in the same group assume that
-        // that Tab 3 is the last tab in the group.
-        mTabModelObserverArgumentCaptor.getValue().willCloseTab(mTab2, true);
-        verifyResetStrip(false, null);
-
-        mTabModelObserverArgumentCaptor
-                .getValue()
-                .didSelectTab(mTab3, TabSelectionType.FROM_CLOSE, TAB2_ID);
-
-        // Strip should not be reset again.
-        verifyNeverReset();
-    }
-
-    @Test
     public void tabClosure_NotLastTabInGroup_Selection_SingleTabGroupsEnabled() {
         initAndAssertProperties(mTab2);
 
@@ -591,7 +570,6 @@
 
         // Mock closing tab 2, and tab 3 then gets selected. They are in the same group assume that
         // that Tab 3 is the last tab in the group, but tab groups of size 1 are supported.
-        mTabModelObserverArgumentCaptor.getValue().willCloseTab(mTab2, true);
         mTabModelObserverArgumentCaptor
                 .getValue()
                 .didSelectTab(mTab3, TabSelectionType.FROM_CLOSE, TAB2_ID);
@@ -601,41 +579,10 @@
     }
 
     @Test
-    public void tabClosure_NotLastTabInGroup_NoSelection_SingleTabGroupsDisabled() {
-        initAndAssertProperties(mTab2);
-
-        doReturn(mTab2).when(mTabGroupModelFilter).getGroupLastShownTab(TAB3_ROOT_ID);
-        doReturn(false).when(mTabGroupModelFilter).isTabInTabGroup(mTab2);
-        doReturn(false).when(mTabGroupModelFilter).isTabInTabGroup(mTab3);
-
-        // Mock closing tab 3, and tab 2 remains selected.
-        mTabModelObserverArgumentCaptor.getValue().willCloseTab(mTab3, true);
-
-        // Strip should reset since since we don't have a group anymore.
-        verifyResetStrip(false, null);
-    }
-
-    @Test
-    public void tabClosure_NotLastTabInGroup_NoSelection_SingleTabGroupsEnabled() {
-        initAndAssertProperties(mTab2);
-
-        doReturn(mTab2).when(mTabGroupModelFilter).getGroupLastShownTab(TAB3_ROOT_ID);
-        doReturn(true).when(mTabGroupModelFilter).isTabInTabGroup(mTab2);
-        doReturn(false).when(mTabGroupModelFilter).isTabInTabGroup(mTab3);
-
-        // Mock closing tab 3, and tab 2 remains selected.
-        mTabModelObserverArgumentCaptor.getValue().willCloseTab(mTab3, true);
-
-        // Strip should not be reset since we are still in this group.
-        verifyNeverReset();
-    }
-
-    @Test
     public void tabClosure_LastTabInGroup_GroupUiNotVisible() {
         initAndAssertProperties(mTab1);
 
         // Mock closing tab 1, and tab 2 then gets selected. They are in different group.
-        mTabModelObserverArgumentCaptor.getValue().willCloseTab(mTab1, true);
         when(mTabModelSelector.getCurrentTab()).thenReturn(mTab2);
         mTabModelObserverArgumentCaptor
                 .getValue()
@@ -653,12 +600,10 @@
 
         // Mock closing tab 2 and tab, then tab 1 gets selected. They are in different group. Right
         // now tab group UI is visible.
-        mTabModelObserverArgumentCaptor.getValue().willCloseTab(mTab2, true);
         mTabModelObserverArgumentCaptor
                 .getValue()
                 .didSelectTab(mTab3, TabSelectionType.FROM_CLOSE, TAB2_ID);
         doReturn(new ArrayList<>()).when(mTabGroupModelFilter).getRelatedTabList(TAB3_ID);
-        mTabModelObserverArgumentCaptor.getValue().willCloseTab(mTab3, true);
         mTabModelObserverArgumentCaptor
                 .getValue()
                 .didSelectTab(mTab1, TabSelectionType.FROM_CLOSE, TAB3_ID);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerCoordinator.java
index c21e722b..f032571 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerCoordinator.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.bookmarks;
 
+import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Context;
 import android.view.LayoutInflater;
@@ -14,6 +15,7 @@
 import androidx.annotation.LayoutRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.LifecycleOwner;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.recyclerview.widget.RecyclerView.ItemAnimator;
 import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
@@ -221,7 +223,9 @@
                 onScrollListener -> mRecyclerView.addOnScrollListener(onScrollListener);
         mMediator =
                 new BookmarkManagerMediator(
-                        context,
+                        (Activity) context,
+                        (LifecycleOwner) context,
+                        mModalDialogManager,
                         mBookmarkModel,
                         mBookmarkOpener,
                         mSelectableListLayout,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediator.java
index cb7d12f0..2f9a097 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediator.java
@@ -6,6 +6,7 @@
 
 import static org.chromium.components.browser_ui.widget.BrowserUiListMenuUtils.buildMenuListItem;
 
+import android.app.Activity;
 import android.content.Context;
 import android.text.TextUtils;
 
@@ -14,6 +15,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
 import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.LifecycleOwner;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
 
@@ -60,6 +62,7 @@
 import org.chromium.ui.accessibility.AccessibilityState;
 import org.chromium.ui.listmenu.ListMenu;
 import org.chromium.ui.listmenu.ListMenuItemProperties;
+import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
 import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -156,7 +159,7 @@
                                 // local bookmarks.
                                 if (mBookmarkBatchUploadCardCoordinator != null) {
                                     mBookmarkBatchUploadCardCoordinator
-                                            .hideBatchUploadCardAndUpdate();
+                                            .immediatelyHideBatchUploadCardAndUpdateItsVisibility();
                                 }
                             }
                         }
@@ -390,7 +393,9 @@
     private boolean mShoppingFilterAvailable;
 
     BookmarkManagerMediator(
-            Context context,
+            Activity activity,
+            LifecycleOwner lifecycleOwner,
+            ModalDialogManager modalDialogManager,
             BookmarkModel bookmarkModel,
             BookmarkOpener bookmarkOpener,
             SelectableListLayout<BookmarkId> selectableListLayout,
@@ -410,7 +415,7 @@
             BooleanSupplier canShowSigninPromo,
             Consumer<OnScrollListener> onScrollListenerConsumer,
             BookmarkMoveSnackbarManager bookmarkMoveSnackbarManager) {
-        mContext = context;
+        mContext = activity;
         mBookmarkModel = bookmarkModel;
         mBookmarkModel.addObserver(mBookmarkModelObserver);
         mBookmarkOpener = bookmarkOpener;
@@ -441,7 +446,9 @@
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.UNO_PHASE_2_FOLLOW_UP)) {
             mBookmarkBatchUploadCardCoordinator =
                     new BookmarkBatchUploadCardCoordinator(
-                            mContext,
+                            activity,
+                            lifecycleOwner,
+                            modalDialogManager,
                             mProfile.getOriginalProfile(),
                             mSnackbarManager,
                             this::updateBatchUploadCard);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetServiceImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetServiceImpl.java
index 6276e49..ec85fe0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetServiceImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetServiceImpl.java
@@ -29,6 +29,7 @@
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.AppHooks;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.bookmarks.BookmarkModel;
 import org.chromium.chrome.browser.bookmarks.BookmarkModelObserver;
@@ -181,6 +182,8 @@
             mRemainingTaskCount = 1;
             mBookmarkModel =
                     BookmarkModel.getForProfile(ProfileManager.getLastUsedRegularProfile());
+            mBookmarkModel.setPartnerBookmarkIteratorSupplier(
+                    () -> AppHooks.get().getPartnerBookmarkIterator());
             mBookmarkModel.finishLoadingBookmarkModel(
                     new Runnable() {
                         @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/ReorderDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/ReorderDelegate.java
index 221a748..c7ba57b7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/ReorderDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/ReorderDelegate.java
@@ -68,9 +68,6 @@
     // Reorder State.
     private final ObservableSupplierImpl<Boolean> mInReorderModeSupplier =
             new ObservableSupplierImpl<>(/* initialValue= */ false);
-    // TODO(crbug.com/381285152): Cleanup mReorderingForTabDrop - duplicate of
-    // ReorderType.EXTERNAL_VIEW_IN_STRIP.
-    private boolean mReorderingForTabDrop;
 
     @IntDef({ReorderType.VIEW_IN_STRIP, ReorderType.VIEW_DRAG, ReorderType.EXTERNAL_VIEW_IN_STRIP})
     @Retention(RetentionPolicy.SOURCE)
@@ -104,7 +101,8 @@
     private ReorderStrategy mActiveStrategy;
     private final TabReorderStrategy mTabStrategy = new TabReorderStrategy();
     private final GroupReorderStrategy mGroupStrategy = new GroupReorderStrategy();
-    @Nullable private SourceViewDragDropReorderStrategy mDragDropStrategy;
+    @Nullable private SourceViewDragDropReorderStrategy mSourceViewDragDropReorderStrategy;
+    @Nullable private ExternalViewDragDropReorderStrategy mExternalViewDragDropReorderStrategy;
 
     // Auto-scroll State.
     private long mLastReorderScrollTime;
@@ -123,14 +121,7 @@
     }
 
     boolean getReorderingForTabDrop() {
-        return mReorderingForTabDrop;
-    }
-
-    void setReorderingForTabDrop(boolean reorderingForTabDrop) {
-        if (mReorderingForTabDrop != reorderingForTabDrop) {
-            mReorderingForTabDrop = reorderingForTabDrop;
-            if (mReorderingForTabDrop) onReorderingForTabDrop();
-        }
+        return getInReorderMode() && mActiveStrategy == mExternalViewDragDropReorderStrategy;
     }
 
     float getLastReorderX() {
@@ -156,10 +147,14 @@
 
     private ReorderStrategy getReorderStrategy(
             StripLayoutView interactingView, @ReorderType int reorderType) {
-        if (mDragDropStrategy != null
+        if (mSourceViewDragDropReorderStrategy != null
                 && interactingView instanceof StripLayoutTab
                 && reorderType == ReorderType.VIEW_DRAG) {
-            return mDragDropStrategy;
+            return mSourceViewDragDropReorderStrategy;
+        } else if (interactingView instanceof StripLayoutTab
+                && reorderType == ReorderType.EXTERNAL_VIEW_IN_STRIP) {
+            assert mExternalViewDragDropReorderStrategy != null;
+            return mExternalViewDragDropReorderStrategy;
         } else if (interactingView instanceof StripLayoutTab) {
             return mTabStrategy;
         } else if (interactingView instanceof StripLayoutGroupTitle) {
@@ -172,25 +167,25 @@
     // TODO(crbug.com/381285152): Remove get/set viewBeingDragged once DragDropReorderStrategy is
     // complete.
     StripLayoutView getViewBeingDragged() {
-        if (mDragDropStrategy == null) return null;
-        return mDragDropStrategy.mViewBeingDragged;
+        if (mSourceViewDragDropReorderStrategy == null) return null;
+        return mSourceViewDragDropReorderStrategy.mViewBeingDragged;
     }
 
     void setViewBeingDragged(StripLayoutView view) {
-        if (mDragDropStrategy == null) return;
-        mDragDropStrategy.mViewBeingDragged = view;
+        if (mSourceViewDragDropReorderStrategy == null) return;
+        mSourceViewDragDropReorderStrategy.mViewBeingDragged = view;
     }
 
     // TODO(crbug.com/381285152): Remove get/set dragLastOffsetX once DragDropReorderStrategy is
     // complete.
     float getDragLastOffsetX() {
-        if (mDragDropStrategy == null) return 0f;
-        return mDragDropStrategy.mLastOffsetX;
+        if (mSourceViewDragDropReorderStrategy == null) return 0f;
+        return mSourceViewDragDropReorderStrategy.mLastOffsetX;
     }
 
     void setDragLastOffsetX(float offsetX) {
-        if (mDragDropStrategy == null) return;
-        mDragDropStrategy.mLastOffsetX = offsetX;
+        if (mSourceViewDragDropReorderStrategy == null) return;
+        mSourceViewDragDropReorderStrategy.mLastOffsetX = offsetX;
     }
 
     // ============================================================================================
@@ -224,9 +219,10 @@
         mContainerView = containerView;
 
         mModel = mTabGroupModelFilter.getTabModel();
-
         if (tabDragSource != null) {
-            mDragDropStrategy = new SourceViewDragDropReorderStrategy(tabDragSource);
+            mSourceViewDragDropReorderStrategy =
+                    new SourceViewDragDropReorderStrategy(tabDragSource);
+            mExternalViewDragDropReorderStrategy = new ExternalViewDragDropReorderStrategy();
         }
         mInitialized = true;
     }
@@ -235,7 +231,11 @@
     // Reorder API
     // ============================================================================================
 
-    /** See {@link ReorderStrategy#startReorderMode} */
+    /**
+     * See {@link ReorderStrategy#startReorderMode}. Additional params:
+     *
+     * @param reorderType The type {@link ReorderType} of reorder to start.
+     */
     void startReorderMode(
             StripLayoutTab[] stripTabs,
             StripLayoutGroupTitle[] stripGroupTitles,
@@ -388,6 +388,19 @@
         return true;
     }
 
+    private void setTrailingMarginForTab(
+            StripLayoutTab stripTab,
+            StripLayoutGroupTitle[] groupTitles,
+            boolean shouldHaveTrailingMargin,
+            @NonNull ArrayList<Animator> animationList) {
+        final Tab tab = mModel.getTabById(stripTab.getTabId());
+        if (tab == null) return;
+        final StripLayoutGroupTitle groupTitle =
+                StripLayoutUtils.findGroupTitle(groupTitles, tab.getRootId());
+
+        setTrailingMarginForTab(stripTab, groupTitle, shouldHaveTrailingMargin, animationList);
+    }
+
     private void resetTabGroupMargins(
             StripLayoutGroupTitle[] groupTitles,
             StripLayoutTab[] stripTabs,
@@ -398,13 +411,8 @@
         //  don't use trailing margins to demarcate tab group bounds.
         for (int i = 0; i < stripTabs.length; i++) {
             final StripLayoutTab stripTab = stripTabs[i];
-            final Tab tab = mModel.getTabById(stripTab.getTabId());
-            if (tab == null) continue;
-            final StripLayoutGroupTitle groupTitle =
-                    StripLayoutUtils.findGroupTitle(groupTitles, tab.getRootId());
-
             setTrailingMarginForTab(
-                    stripTab, groupTitle, /* shouldHaveTrailingMargin= */ false, animationList);
+                    stripTab, groupTitles, /* shouldHaveTrailingMargin= */ false, animationList);
         }
         mScrollDelegate.setReorderStartMargin(/* newStartMargin= */ 0.f);
     }
@@ -454,8 +462,6 @@
                 StripLayoutGroupTitle[] groupTitles,
                 StripLayoutTab[] stripTabs,
                 float deltaX) {
-            if (!getInReorderMode() || mInteractingTab == null || mReorderingForTabDrop) return;
-
             int curIndex = StripLayoutUtils.findIndexForTab(stripTabs, mInteractingTab.getTabId());
             if (curIndex == TabModel.INVALID_TAB_INDEX) return;
 
@@ -507,47 +513,7 @@
         @Override
         public void stopReorderMode(
                 StripLayoutGroupTitle[] groupTitles, StripLayoutTab[] stripTabs) {
-            assert getInReorderMode()
-                    : "Tried to stop reorder mode, without first starting reorder mode.";
-            ArrayList<Animator> animationList = new ArrayList<>();
-
-            // 1. Reset the state variables.
-            mReorderScrollState = REORDER_SCROLL_NONE;
-            setInReorderMode(false);
-
-            // 2. Reset the interacting view (clear any offset and reattach the container).
-            mAnimationHost.finishAnimationsAndPushTabUpdates();
-            if (mInteractingTab != null) {
-                // TODO(crbug.com/372546700): mInteractingTab may be null if reordering for tab
-                // drop.
-                animationList.add(
-                        CompositorAnimator.ofFloatProperty(
-                                mAnimationHost.getAnimationHandler(),
-                                mInteractingTab,
-                                StripLayoutView.X_OFFSET,
-                                mInteractingTab.getOffsetX(),
-                                0f,
-                                ANIM_TAB_MOVE_MS));
-
-                // Skip reattachment for tab drop to avoid exposing bottom indicator underneath the
-                // tab container.
-                if (!mReorderingForTabDrop || !mInteractingTab.getFolioAttached()) {
-                    updateTabAttachState(mInteractingTab, /* attached= */ true, animationList);
-                }
-            }
-
-            // 3. Clear any tab group margins.
-            resetTabGroupMargins(groupTitles, stripTabs, animationList);
-
-            // 4. Clear the interacting view.
-            setInteractingTab(null);
-
-            // 5. Reset the tab drop state. Must occur after the rest of the state is reset, since
-            // some logic depends on these values.
-            mReorderingForTabDrop = false;
-
-            // 6. Start animations.
-            mAnimationHost.startAnimations(animationList, /* listener= */ null);
+            handleStopReorderMode(groupTitles, stripTabs);
         }
 
         @Override
@@ -556,6 +522,44 @@
         }
     }
 
+    private void handleStopReorderMode(
+            StripLayoutGroupTitle[] groupTitles, StripLayoutTab[] stripTabs) {
+        assert getInReorderMode()
+                : "Tried to stop reorder mode, without first starting reorder mode.";
+        ArrayList<Animator> animationList = new ArrayList<>();
+
+        // 1. Reset the state variables.
+        mReorderScrollState = REORDER_SCROLL_NONE;
+        setInReorderMode(false);
+
+        // 2. Reset the interacting view (clear any offset and reattach the container).
+        mAnimationHost.finishAnimationsAndPushTabUpdates();
+        // mInteractingTab may be null if reordering for external view drag drop.
+        if (mInteractingTab != null) {
+            animationList.add(
+                    CompositorAnimator.ofFloatProperty(
+                            mAnimationHost.getAnimationHandler(),
+                            mInteractingTab,
+                            StripLayoutView.X_OFFSET,
+                            mInteractingTab.getOffsetX(),
+                            0f,
+                            ANIM_TAB_MOVE_MS));
+
+            if (!mInteractingTab.getFolioAttached()) {
+                updateTabAttachState(mInteractingTab, /* attached= */ true, animationList);
+            }
+        }
+
+        // 3. Clear any tab group margins.
+        resetTabGroupMargins(groupTitles, stripTabs, animationList);
+
+        // 4. Clear the interacting view.
+        setInteractingTab(null);
+
+        // 5. Start animations.
+        mAnimationHost.startAnimations(animationList, /* listener= */ null);
+    }
+
     void prepareStripForReorder(float effectiveTabWidth, float startX) {
         mAnimationHost.finishAnimationsAndPushTabUpdates();
         mLastReorderScrollTime = INVALID_TIME;
@@ -870,21 +874,9 @@
     }
 
     // ============================================================================================
-    // Drag and drop reorder - drag external view onto / out of and within strip.
-    // ============================================================================================
-
-    void onReorderingForTabDrop() {
-        // TODO(crbug.com/381285152): Implement separate strategy for Drag and Drop on destination
-        //  tab strip. This is only needed because we reuse the TabReorderStrategy#stopReorder for
-        //  DnD, but can likely be replaced by implementing a DnD-specific ReorderStrategy.
-        mActiveStrategy = mTabStrategy;
-    }
-
-    // ============================================================================================
     // Drag and drop reorder - start dragging strip view. Subsequently drag out of,
     // within and back onto strip.
     // ============================================================================================
-
     private class SourceViewDragDropReorderStrategy implements ReorderStrategy {
         // Drag helpers
         private final TabDragSource mTabDragSource;
@@ -964,6 +956,63 @@
     }
 
     // ============================================================================================
+    // Drag and drop reorder - drag external view onto / out-of strip and reorder within strip.
+    // ============================================================================================
+    private class ExternalViewDragDropReorderStrategy implements ReorderStrategy {
+
+        /**
+         * Initiate reorder when external view is dragged onto strip. interactingView here is the
+         * view on the strip being hovered on by the dragged view.
+         */
+        @Override
+        public void startReorderMode(
+                StripLayoutTab[] stripTabs,
+                StripLayoutGroupTitle[] stripGroupTitles,
+                @NonNull StripLayoutView interactingView,
+                float effectiveTabWidth,
+                PointF startPoint,
+                @ReorderType int reorderType) {
+            // 1. Set initial state and add edge margins.
+            setInteractingTab((StripLayoutTab) interactingView);
+            setInReorderMode(true);
+            prepareStripForReorder(effectiveTabWidth, startPoint.x);
+            setEdgeMarginsForReorder(stripTabs[0], stripTabs[stripTabs.length - 1]);
+
+            // 2. Add a trailing margin to the interacting tab to indicate where the tab will be
+            // inserted should the drag be dropped.
+            ArrayList<Animator> animationList = new ArrayList<>();
+            setTrailingMarginForTab(
+                    (StripLayoutTab) interactingView,
+                    stripGroupTitles,
+                    /* shouldHaveTrailingMargin= */ true,
+                    animationList);
+
+            // 3. Kick-off animations and request an update.
+            mAnimationHost.startAnimations(animationList, null);
+        }
+
+        @Override
+        public void updateReorderPosition(
+                StripLayoutView[] stripViews,
+                StripLayoutGroupTitle[] groupTitles,
+                StripLayoutTab[] stripTabs,
+                float deltaX) {
+            // TODO(crbug.com/381285152): Implement.
+        }
+
+        @Override
+        public void stopReorderMode(
+                StripLayoutGroupTitle[] groupTitles, StripLayoutTab[] stripTabs) {
+            handleStopReorderMode(groupTitles, stripTabs);
+        }
+
+        @Override
+        public StripLayoutView getInteractingView() {
+            return mInteractingTab;
+        }
+    }
+
+    // ============================================================================================
     // Animation helpers
     // ============================================================================================
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
index 287c817c..0f9f31c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
@@ -1851,7 +1851,8 @@
                 // Intentionally start the reorder at the initial long-press x. The difference from
                 // the current event (accumulatedDeltaX in step 3) will then "snap" the interacting
                 // view to its expected position.
-                startDragOrReorder(mDelayedReorderInitialX, y, mDelayedReorderView);
+                startReorderMode(
+                        mDelayedReorderInitialX, y, mDelayedReorderView, ReorderType.VIEW_DRAG);
             }
         }
 
@@ -1992,7 +1993,7 @@
             } else {
                 resetResizeTimeout(false);
 
-                startDragOrReorder(x, y, clickedTab);
+                startReorderMode(x, y, clickedTab, ReorderType.VIEW_DRAG);
             }
         } else {
             StripLayoutGroupTitle groupTitle = (StripLayoutGroupTitle) stripView;
@@ -2003,7 +2004,7 @@
             } else if (ChromeFeatureList.isEnabled(ChromeFeatureList.TAB_STRIP_GROUP_REORDER)) {
                 // Should be obsolete, since context menu has launched. Code path will be
                 // unreachable, then removed once the context menu flag has been cleaned up.
-                startDragOrReorder(x, y, groupTitle);
+                startReorderMode(x, y, groupTitle, ReorderType.VIEW_IN_STRIP);
             }
         }
     }
@@ -2121,10 +2122,28 @@
         anchorRectProvider.getRect().offset(xOffset, toolbarCoordinates[1]);
     }
 
-    private void startDragOrReorder(float x, float y, StripLayoutView clickedView) {
-        if (clickedView != null) {
-            // Attempt to initiate drag-drop, fallback to reorder within strip.
-            startReorderMode(x, y, clickedView, ReorderType.VIEW_DRAG);
+    private void startReorderMode(
+            float x, float y, StripLayoutView interactingView, @ReorderType int reorderType) {
+        // Allow the user to drag the selected tab out of the tab strip.
+        if (interactingView != null) {
+            if (mReorderDelegate.getInReorderMode()) return;
+            // Attempt to start reordering. If the interacting view is a StripLayoutTab,
+            // only continue if it is valid (non-null, non-dying, non-placeholder) and
+            // the tab state is initialized.
+            if (interactingView instanceof StripLayoutTab interactingTab
+                    && (interactingTab.isDying()
+                            || interactingTab.getTabId() == Tab.INVALID_TAB_ID
+                            || !mTabStateInitialized)) {
+                return;
+            }
+
+            mReorderDelegate.startReorderMode(
+                    mStripTabs,
+                    mStripGroupTitles,
+                    interactingView,
+                    getEffectiveTabWidth(),
+                    new PointF(x, y),
+                    reorderType);
         } else {
             // Broadcast to start moving the window instance as the user has long pressed on the
             // open space of the tab strip.
@@ -3860,53 +3879,6 @@
         startReorderMode(x, 0, getTabAtPosition(x), ReorderType.VIEW_IN_STRIP);
     }
 
-    private void startReorderMode(
-            float x, float y, StripLayoutView interactingView, @ReorderType int reorderType) {
-        if (mReorderDelegate.getInReorderMode() || interactingView == null) return;
-
-        // Attempt to start reordering. If the interacting view is a StripLayoutTab, only continue
-        // if it is valid (non-null, non-dying, non-placeholder) and the tab state is initialized.
-        if (interactingView instanceof StripLayoutTab interactingTab
-                && (interactingTab.isDying()
-                        || interactingTab.getTabId() == Tab.INVALID_TAB_ID
-                        || !mTabStateInitialized)) {
-            return;
-        }
-        mReorderDelegate.startReorderMode(
-                mStripTabs,
-                mStripGroupTitles,
-                interactingView,
-                getEffectiveTabWidth(),
-                new PointF(x, y),
-                reorderType);
-    }
-
-    void updateStripForExternalTabDrop(float startX) {
-        // 1. StartX indicates the position where the tab drag entered the destination tab strip.
-        // Adjust by a half tab-width so that we target the nearest tab gap.
-        startX = adjustXForTabDrop(startX);
-
-        // 2. Mark the "interacting" tab. This is not the DnD dragged tab, but rather the tab in the
-        // strip that is currently being hovered by the DnD drag.
-        StripLayoutTab hoveredTab = getTabAtPosition(startX);
-        if (hoveredTab == null) hoveredTab = mStripTabs[mStripTabs.length - 1];
-        mReorderDelegate.setInteractingTab(hoveredTab);
-
-        // 3. Set initial state.
-        mReorderDelegate.setInReorderMode(true);
-        mReorderDelegate.setReorderingForTabDrop(true);
-        mReorderDelegate.prepareStripForReorder(getEffectiveTabWidth(), startX);
-        mReorderDelegate.setEdgeMarginsForReorder(mStripTabs[0], mStripTabs[mStripTabs.length - 1]);
-
-        // 4. Add a tab group margin to the "interacting" tab to indicate where the tab will be
-        // inserted should the drag be dropped.
-        ArrayList<Animator> animationList = new ArrayList<>();
-        setTrailingMarginForTab(hoveredTab, /* shouldHaveTrailingMargin= */ true, animationList);
-
-        // 5. Kick-off animations and request an update.
-        startAnimations(animationList);
-    }
-
     void stopReorderModeForTesting() {
         mReorderDelegate.stopReorderMode(mStripGroupTitles, mStripTabs);
     }
@@ -4521,15 +4493,25 @@
     }
 
     void prepareForTabDrop(
-            long time,
-            float currX,
-            float lastX,
-            boolean isSourceStrip,
-            boolean draggedTabIncognito) {
+            float currX, float lastX, boolean isSourceStrip, boolean draggedTabIncognito) {
         if (isSourceStrip) {
             dragActiveClickedTabOntoStrip(lastX, /* startReorder= */ true);
-        } else if (mIncognito == draggedTabIncognito) {
-            updateStripForExternalTabDrop(currX);
+        } else {
+            // Destination strip (ie: view dragged onto another strip)
+            // 1. If strip model does not match dragged view's, no-op.
+            if (mIncognito != draggedTabIncognito) return;
+
+            // 2. StartX indicates where the external drag enters the  tab strip.
+            // Adjust by a half tab-width so that we target the nearest tab gap.
+            float startX = adjustXForTabDrop(currX);
+
+            // 3. Mark the "interacting" view. This is not the DnD dragged tab, but rather the tab
+            // in the strip that is currently being hovered by the DnD drag.
+            StripLayoutTab hoveredTab = getTabAtPosition(startX);
+            if (hoveredTab == null) hoveredTab = mStripTabs[mStripTabs.length - 1];
+
+            // 4. Start reorder - prepare strip to indicate drop target.
+            startReorderMode(startX, /* y= */ 0.f, hoveredTab, ReorderType.EXTERNAL_VIEW_IN_STRIP);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java
index 958c115..7d76faec 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java
@@ -362,12 +362,7 @@
         }
         mStripLayoutHelperSupplier
                 .get()
-                .prepareForTabDrop(
-                        LayoutManagerImpl.time(),
-                        xPx * mPxToDp,
-                        mLastXDp,
-                        isDragSource,
-                        isDraggedTabIncognito());
+                .prepareForTabDrop(xPx * mPxToDp, mLastXDp, isDragSource, isDraggedTabIncognito());
         return true;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java
index cda9ff57..99feb2e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java
@@ -5,6 +5,8 @@
 package org.chromium.chrome.browser.ntp;
 
 import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
 
 import org.chromium.base.ResettersForTesting;
 import org.chromium.base.metrics.RecordHistogram;
@@ -32,6 +34,8 @@
 import org.chromium.chrome.browser.ui.signin.SyncPromoController;
 import org.chromium.chrome.browser.ui.signin.SyncPromoController.SyncPromoState;
 import org.chromium.chrome.browser.ui.signin.account_picker.AccountPickerBottomSheetStrings;
+import org.chromium.chrome.browser.ui.signin.signin_promo.RecentTabsSigninPromoDelegate;
+import org.chromium.chrome.browser.ui.signin.signin_promo.SigninPromoCoordinator;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
 import org.chromium.components.signin.AccountsChangeObserver;
 import org.chromium.components.signin.identitymanager.ConsentLevel;
@@ -63,6 +67,7 @@
     private final Tab mActiveTab;
     private final TabModelSelector mTabModelSelector;
     private final Runnable mShowHistoryManager;
+    private final SigninPromoCoordinator mSigninPromoCoordinator;
 
     private TabModel mTabModel;
     private @SyncPromoState int mPromoState = SyncPromoState.NO_PROMO;
@@ -74,6 +79,7 @@
     private RecentlyClosedTabManager mRecentlyClosedTabManager;
     private SigninManager mSignInManager;
     private UpdatedCallback mUpdatedCallback;
+    private View mSigninPromoView;
     private boolean mIsDestroyed;
 
     private final ProfileDataCache mProfileDataCache;
@@ -130,6 +136,19 @@
                         SigninAccessPoint.RECENT_TABS,
                         SyncConsentActivityLauncherImpl.get(),
                         SigninAndHistorySyncActivityLauncherImpl.get());
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.UNO_PHASE_2_FOLLOW_UP)) {
+            mSigninPromoCoordinator =
+                    new SigninPromoCoordinator(
+                            context,
+                            profile,
+                            new RecentTabsSigninPromoDelegate(
+                                    context,
+                                    profile,
+                                    SigninAndHistorySyncActivityLauncherImpl.get(),
+                                    this::updatePromoState));
+        } else {
+            mSigninPromoCoordinator = null;
+        }
         mSyncService = SyncServiceFactory.getForProfile(mProfile);
 
         mRecentlyClosedTabManager.setEntriesUpdatedRunnable(this::updateRecentlyClosedEntries);
@@ -143,7 +162,11 @@
         mSignInManager.addSignInStateObserver(this);
         mProfileDataCache.addObserver(this);
         AccountManagerFacadeProvider.getInstance().addObserver(this);
-        updatePromoState();
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.UNO_PHASE_2_FOLLOW_UP)) {
+            updatePromoState();
+        } else {
+            updatePromoStateLegacy();
+        }
 
         SessionsInvalidationManager.get(mProfile).onRecentTabsPageOpened();
     }
@@ -184,6 +207,9 @@
         recordEntries("Bulk", mBulkSessionIdsRestored);
 
         mSyncService.removeSyncStateChangedListener(this);
+        if (mSigninPromoCoordinator != null) {
+            mSigninPromoCoordinator.destroy();
+        }
 
         mSignInManager.removeSignInStateObserver(this);
         mSignInManager = null;
@@ -432,6 +458,11 @@
     }
 
     private @SyncPromoState int calculatePromoState() {
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.UNO_PHASE_2_FOLLOW_UP)) {
+            return mSigninPromoCoordinator.canShowPromo()
+                    ? SyncPromoState.PROMO_FOR_SIGNED_OUT_STATE
+                    : SyncPromoState.NO_PROMO;
+        }
         if (ChromeFeatureList.isEnabled(
                 ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS)) {
             // If ReplaceSyncPromosWithSignInPromos is enabled, there's only one promo type.
@@ -469,7 +500,10 @@
         return SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE;
     }
 
-    private void updatePromoState() {
+    private void updatePromoStateLegacy() {
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.UNO_PHASE_2_FOLLOW_UP)) {
+            return;
+        }
         final @SyncPromoState int newState = calculatePromoState();
         if (newState == mPromoState) return;
 
@@ -489,6 +523,14 @@
         mSyncPromoController.setUpSyncPromoView(mProfileDataCache, view, null);
     }
 
+    View getSigninPromoView(ViewGroup parent) {
+        if (mSigninPromoView == null) {
+            mSigninPromoView = mSigninPromoCoordinator.buildPromoView(parent);
+            mSigninPromoCoordinator.setView(mSigninPromoView);
+        }
+        return mSigninPromoView;
+    }
+
     // SignInStateObserver implementation.
     @Override
     public void onSignedIn() {
@@ -525,12 +567,21 @@
     }
 
     private void update() {
-        updatePromoState();
+        updatePromoStateLegacy();
         if (mIsDestroyed) return;
         updateForeignSessions();
         onUpdateDone();
     }
 
+    private void updatePromoState() {
+        final @SyncPromoState int newState = calculatePromoState();
+        if (newState == mPromoState) return;
+        mPromoState = newState;
+
+        if (mIsDestroyed) return;
+        onUpdateDone();
+    }
+
     private TabModel getTabModel() {
         // When RecentTabsManager is created for a new tab then {@link mActiveTab} is being
         // created and will not be present in a {@link TabModel} of {@link mTabModelSelector}.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
index d64b154..f6a4475 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
@@ -487,6 +487,20 @@
         }
     }
 
+    /** A group containing the personalized sync promo. */
+    class SigninPromoGroup extends PromoGroup {
+        @Override
+        public @ChildType int getChildType() {
+            return ChildType.PERSONALIZED_SIGNIN_PROMO;
+        }
+
+        @Override
+        View getChildView(
+                int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
+            return mRecentTabsManager.getSigninPromoView(parent);
+        }
+    }
+
     /** A group containing the sync promo. */
     class SyncPromoGroup extends PromoGroup {
         @Override
@@ -1066,7 +1080,11 @@
                 }
                 break;
             case SyncPromoState.PROMO_FOR_SIGNED_OUT_STATE:
-                addGroup(new PersonalizedSyncPromoGroup(ChildType.PERSONALIZED_SIGNIN_PROMO));
+                if (ChromeFeatureList.isEnabled(ChromeFeatureList.UNO_PHASE_2_FOLLOW_UP)) {
+                    addGroup(new SigninPromoGroup());
+                } else {
+                    addGroup(new PersonalizedSyncPromoGroup(ChildType.PERSONALIZED_SIGNIN_PROMO));
+                }
                 break;
             case SyncPromoState.PROMO_FOR_SIGNED_IN_STATE:
                 addGroup(new PersonalizedSyncPromoGroup(ChildType.PERSONALIZED_SYNC_PROMO));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java
index 72844b8..d2f1a5bc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java
@@ -152,8 +152,6 @@
                 // not great to dynamically remove the preference in this way.
             case SiteSettingsCategory.Type.ADS:
                 return SiteSettingsCategory.adsCategoryEnabled();
-            case SiteSettingsCategory.Type.ANTI_ABUSE:
-                return ChromeFeatureList.isEnabled(ChromeFeatureList.PRIVATE_STATE_TOKENS);
             case SiteSettingsCategory.Type.AUTO_DARK_WEB_CONTENT:
                 return ChromeFeatureList.isEnabled(
                         ChromeFeatureList.DARKEN_WEBSITES_CHECKBOX_IN_THEMES_SETTING);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/bookmark_batch_upload_card/BookmarkBatchUploadCardCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/bookmark_batch_upload_card/BookmarkBatchUploadCardCoordinator.java
index 9a96e6a..90ce828 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/bookmark_batch_upload_card/BookmarkBatchUploadCardCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/bookmark_batch_upload_card/BookmarkBatchUploadCardCoordinator.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.sync.ui.bookmark_batch_upload_card;
 
 import android.app.Activity;
-import android.content.Context;
 import android.view.View;
 
 import androidx.lifecycle.LifecycleOwner;
@@ -14,7 +13,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.ui.UiUtils;
-import org.chromium.ui.modaldialog.ModalDialogManagerHolder;
+import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 
@@ -25,7 +24,9 @@
     private PropertyModelChangeProcessor mPropertyModelChangeProcessor;
 
     public BookmarkBatchUploadCardCoordinator(
-            Context context,
+            Activity activity,
+            LifecycleOwner lifecycleOwner,
+            ModalDialogManager modalDialogManager,
             Profile profile,
             SnackbarManager snackbarManager,
             Runnable batchUploadCardChangeAction) {
@@ -38,16 +39,16 @@
                         .with(
                                 BookmarkBatchUploadCardProperties.ICON,
                                 UiUtils.getTintedDrawable(
-                                        context,
+                                        activity,
                                         R.drawable.ic_cloud_upload_24dp,
                                         R.color.default_icon_color_accent1_tint_list))
                         .build();
 
         mMediator =
                 new BookmarkBatchUploadCardMediator(
-                        (Activity) context,
-                        (LifecycleOwner) context,
-                        (ModalDialogManagerHolder) context,
+                        activity,
+                        lifecycleOwner,
+                        modalDialogManager,
                         profile,
                         mModel,
                         snackbarManager,
@@ -68,8 +69,8 @@
                         mModel, view, BookmarkBatchUploadCardBinder::bind);
     }
 
-    public void hideBatchUploadCardAndUpdate() {
-        mMediator.hideBatchUploadCardAndUpdate();
+    public void immediatelyHideBatchUploadCardAndUpdateItsVisibility() {
+        mMediator.immediatelyHideBatchUploadCardAndUpdateItsVisibility();
     }
 
     public boolean shouldShowBatchUploadCard() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/bookmark_batch_upload_card/BookmarkBatchUploadCardMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/bookmark_batch_upload_card/BookmarkBatchUploadCardMediator.java
index 30ed8d8..47f230d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/bookmark_batch_upload_card/BookmarkBatchUploadCardMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/bookmark_batch_upload_card/BookmarkBatchUploadCardMediator.java
@@ -28,7 +28,6 @@
 import org.chromium.components.sync.SyncService;
 import org.chromium.components.sync.TransportState;
 import org.chromium.ui.modaldialog.ModalDialogManager;
-import org.chromium.ui.modaldialog.ModalDialogManagerHolder;
 import org.chromium.ui.modelutil.PropertyModel;
 
 import java.util.HashMap;
@@ -40,7 +39,7 @@
             new DefaultLifecycleObserver() {
                 @Override
                 public void onResume(LifecycleOwner lifecycleOwner) {
-                    hideBatchUploadCardAndUpdate();
+                    immediatelyHideBatchUploadCardAndUpdateItsVisibility();
                 }
 
                 @Override
@@ -65,8 +64,7 @@
      * @param activity The {@link Activity} associated with the card.
      * @param lifecycleOwner {@link LifecycleOwner} that can be used to listen for activity
      *     destruction.
-     * @param modalDialogManagerHolder {@link ModalDialogManagerHolder} that can be used to display
-     *     the dialog.
+     * @param modalDialogManager {@link ModalDialogManager} that can be used to display the dialog.
      * @param profile {@link Profile} that is associated with the card.
      * @param model {@link PropertyModel} that is associated with the card.
      * @param snackbarManager {@link SnackbarManager} used to display snackbars.
@@ -75,7 +73,7 @@
     public BookmarkBatchUploadCardMediator(
             Activity activity,
             LifecycleOwner lifecycleOwner,
-            ModalDialogManagerHolder modalDialogManagerHolder,
+            ModalDialogManager modalDialogManager,
             Profile profile,
             PropertyModel model,
             SnackbarManager snackbarManager,
@@ -93,7 +91,7 @@
         mReauthenticatorBridge =
                 ReauthenticatorBridge.create(
                         activity, mProfile, DeviceAuthSource.BOOKMARK_BATCH_UPLOAD);
-        mDialogManager = modalDialogManagerHolder.getModalDialogManager();
+        mDialogManager = modalDialogManager;
 
         lifecycleOwner.getLifecycle().addObserver(mLifeCycleObserver);
 
@@ -114,10 +112,12 @@
         return mShouldBeVisible;
     }
 
-    /** Hides the batch upload card and updates the batch upload card view. */
-    public void hideBatchUploadCardAndUpdate() {
-        // Temporarily hide, it will become visible again once getLocalDataDescriptions() completes,
-        // which is triggered from updateBatchUploadCard().
+    /**
+     * To ensure a smooth user experience, the batch upload card is immediately hidden before any
+     * asynchronous updates occur. This prevents a potential delay in hiding the card if the updated
+     * visibility state is set to 'off', which could lead to an inconsistent UI.
+     */
+    public void immediatelyHideBatchUploadCardAndUpdateItsVisibility() {
         mShouldBeVisible = false;
         mBatchUploadCardChangeAction.run();
         updateBatchUploadCard();
@@ -162,7 +162,7 @@
                                 Snackbar.TYPE_ACTION,
                                 Snackbar.UMA_BOOKMARK_BATCH_UPLOAD)
                         .setSingleLine(false));
-        hideBatchUploadCardAndUpdate();
+        immediatelyHideBatchUploadCardAndUpdateItsVisibility();
     }
 
     private void updateBatchUploadCard() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlagsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlagsTest.java
index 96b7f93e..223241a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlagsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlagsTest.java
@@ -61,7 +61,6 @@
                     ChromeFeatureList.sDrawKeyNativeEdgeToEdge,
                     ChromeFeatureList.sEdgeToEdgeBottomChin,
                     ChromeFeatureList.sEdgeToEdgeWebOptIn,
-                    ChromeFeatureList.sNewTabPageAndroidTriggerForPrerender2,
                     ChromeFeatureList.sPostGetMyMemoryStateToBackground,
                     ChromeFeatureList.sPrefetchBrowserInitiatedTriggers,
                     ChromeFeatureList.sSafetyHubMagicStack,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentTabsPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentTabsPageTest.java
index 87ae5f1..2ed7f1bf 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentTabsPageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentTabsPageTest.java
@@ -81,7 +81,10 @@
 /** Instrumentation tests for {@link RecentTabsPage}. */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-@EnableFeatures({ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS})
+@EnableFeatures({
+    ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS,
+    ChromeFeatureList.UNO_PHASE_2_FOLLOW_UP
+})
 public class RecentTabsPageTest {
     private static final int COLOR_ID = TabGroupColorId.YELLOW;
     private static final int COLOR_ID_2 = TabGroupColorId.RED;
@@ -485,6 +488,16 @@
     }
 
     @Test
+    @MediumTest
+    @Feature({"RecentTabsPage", "RenderTest"})
+    public void testSigninPromoView() throws Exception {
+        mSigninTestRule.addAccount(TestAccounts.ACCOUNT1);
+        mPage = loadRecentTabsPage();
+
+        mRenderTestRule.render(mPage.getView(), "signin_promo");
+    }
+
+    @Test
     @SmallTest
     @DisableFeatures(ChromeFeatureList.TAB_STRIP_LAYOUT_OPTIMIZATION)
     public void testTabStripHeightChangeCallback() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/BottomSheetSigninAndHistorySyncIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/BottomSheetSigninAndHistorySyncIntegrationTest.java
index fb253db..1d27308 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/BottomSheetSigninAndHistorySyncIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/BottomSheetSigninAndHistorySyncIntegrationTest.java
@@ -240,10 +240,10 @@
         verifyCollapsedBottomSheetAndSignin(TestAccounts.AADC_ADULT_ACCOUNT);
 
         // Verify that the history opt-in dialog is shown and decline.
-        onViewWaiting(withId(R.id.history_sync_illustration)).check(matches(isDisplayed()));
+        onViewWaiting(withId(R.id.history_sync_illustration), /* checkRootDialog= */ true)
+                .check(matches(isDisplayed()));
         // The user has just signed in, so the footer shouldn't show the email.
-        onViewWaiting(withId(R.id.history_sync_footer))
-                .inRoot(isDialog())
+        onViewWaiting(withId(R.id.history_sync_footer), /* checkRootDialog= */ true)
                 .check(
                         matches(
                                 allOf(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
index 36b9e01..82955e8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
@@ -1235,24 +1235,11 @@
         settingsActivity.finish();
     }
 
-    /** Test that showing the Site Settings menu does not contain the "Anti-abuse" row. */
-    @Test
-    @SmallTest
-    @Feature({"Preferences"})
-    @DisableFeatures(ChromeFeatureList.PRIVATE_STATE_TOKENS)
-    public void testSiteSettingsMenuWithPrivateStateTokensDisabled() {
-        final SettingsActivity settingsActivity = SiteSettingsTestUtils.startSiteSettingsMenu("");
-        SiteSettings websitePreferences = (SiteSettings) settingsActivity.getMainFragment();
-        assertNull(websitePreferences.findPreference("anti_abuse"));
-        settingsActivity.finish();
-    }
-
     /** Test that showing the Site Settings menu contains the "Anti-abuse" row. */
     @Test
     @SmallTest
     @Feature({"Preferences"})
-    @EnableFeatures(ChromeFeatureList.PRIVATE_STATE_TOKENS)
-    public void testSiteSettingsMenuWithPrivateStateTokensEnabled() {
+    public void testSiteSettingsMenuForAntiAbuse() {
         final SettingsActivity settingsActivity = SiteSettingsTestUtils.startSiteSettingsMenu("");
         SiteSettings websitePreferences = (SiteSettings) settingsActivity.getMainFragment();
         assertNotNull(websitePreferences.findPreference("anti_abuse"));
@@ -1296,7 +1283,6 @@
     @Test
     @SmallTest
     @Feature({"Preferences"})
-    @EnableFeatures(ChromeFeatureList.PRIVATE_STATE_TOKENS)
     public void testOnlyExpectedPreferencesAntiAbuse() {
         testExpectedPreferences(
                 SiteSettingsCategory.Type.ANTI_ABUSE,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java
index 10197c7d..0d72d04 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java
@@ -10,6 +10,7 @@
 import static androidx.test.espresso.intent.Intents.intended;
 import static androidx.test.espresso.intent.Intents.intending;
 import static androidx.test.espresso.matcher.RootMatchers.isDialog;
+import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
 import static androidx.test.espresso.matcher.ViewMatchers.hasSibling;
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
@@ -42,6 +43,7 @@
 import android.widget.TextView;
 
 import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
 import androidx.appcompat.app.AlertDialog;
 import androidx.appcompat.widget.PopupMenu;
 import androidx.fragment.app.FragmentTransaction;
@@ -272,9 +274,10 @@
     }
 
     @Test
-    @SmallTest
-    @Feature({"Sync"})
-    public void testSyncAccountDataTypes() {
+    @LargeTest
+    @EnableFeatures({ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS})
+    @DisableFeatures({ChromeFeatureList.LINKED_SERVICES_SETTING})
+    public void testAccountSettingsView() {
         // The types that should be default-enabled in transport mode depend on various flags.
         Set<String> expectedEnabledTypes =
                 new HashSet<>(
@@ -296,6 +299,7 @@
 
         mSyncTestRule.setUpAccountAndSignInForTesting();
         ManageSyncSettings fragment = startManageSyncPreferences();
+
         Collection<ChromeSwitchPreference> dataTypes = getAccountDataTypes(fragment).values();
         for (ChromeSwitchPreference dataType : dataTypes) {
             Assert.assertEquals(
@@ -304,6 +308,38 @@
                     dataType.isChecked());
             Assert.assertTrue(dataType.isEnabled());
         }
+
+        onView(withText(R.string.account_section_header)).check(matches(isDisplayed()));
+
+        scrollToAndVerifyPresence(R.string.account_section_history_toggle);
+
+        scrollToAndVerifyPresence(R.string.account_section_bookmarks_toggle);
+
+        scrollToAndVerifyPresence(R.string.account_section_reading_list_toggle);
+
+        scrollToAndVerifyPresence(R.string.account_section_addresses_toggle);
+
+        scrollToAndVerifyPresence(R.string.account_section_passwords_toggle);
+
+        scrollToAndVerifyPresence(R.string.account_section_payments_toggle);
+
+        scrollToAndVerifyPresence(R.string.account_section_settings_toggle);
+
+        scrollToAndVerifyPresence(R.string.account_section_footer);
+
+        scrollToAndVerifyPresence(R.string.sign_in_google_activity_controls_title);
+        onView(withText(R.string.account_advanced_header)).check(matches(isDisplayed()));
+        onView(withText(R.string.sign_in_google_activity_controls_summary))
+                .check(matches(isDisplayed()));
+
+        scrollToAndVerifyPresence(R.string.sync_encryption);
+
+        scrollToAndVerifyPresence(R.string.account_data_dashboard_title);
+        onView(withText(R.string.account_data_dashboard_subtitle)).check(matches(isDisplayed()));
+
+        scrollToAndVerifyPresence(R.string.manage_your_google_account);
+
+        scrollToAndVerifyPresence(R.string.account_android_device_accounts);
     }
 
     @Test
@@ -2184,4 +2220,10 @@
         ChromeRenderTestRule.sanitize(fragment.getView());
         mRenderTestRule.render(fragment.getView(), skiaGoldId);
     }
+
+    private void scrollToAndVerifyPresence(@StringRes int textId) {
+        onView(withId(R.id.recycler_view))
+                .perform(RecyclerViewActions.scrollTo(hasDescendant(withText(textId))));
+        onView(withText(textId)).check(matches(isDisplayed()));
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerCoordinatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerCoordinatorTest.java
index 36287cf..ff678a4 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerCoordinatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerCoordinatorTest.java
@@ -23,6 +23,7 @@
 import org.mockito.junit.MockitoRule;
 import org.robolectric.annotation.Config;
 
+import org.chromium.base.Promise;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Features;
@@ -104,6 +105,7 @@
         doReturn(mIdentityManager).when(mSigninManager).getIdentityManager();
         doReturn(mIdentityManager).when(mIdentityServicesProvider).getIdentityManager(any());
         AccountManagerFacadeProvider.setInstanceForTests(mAccountManagerFacade);
+        doReturn(new Promise<>()).when(mAccountManagerFacade).getCoreAccountInfos();
         BookmarkModel.setInstanceForTesting(mBookmarkModel);
         ShoppingServiceFactory.setShoppingServiceForTesting(mShoppingService);
         ReauthenticatorBridge.setInstanceForTesting(mReauthenticatorMock);
@@ -149,4 +151,18 @@
         assertNotNull(BookmarkManagerCoordinator.buildVisualImprovedBookmarkRow(parent));
         assertNotNull(mCoordinator.buildSearchBoxRow(parent));
     }
+
+    @Test
+    @EnableFeatures(ChromeFeatureList.UNO_PHASE_2_FOLLOW_UP)
+    public void testCreateViewUNOPhase2FollowUpEnabled() {
+        FrameLayout parent = new FrameLayout(mActivity);
+        assertNotNull(mCoordinator.buildPersonalizedPromoView(parent));
+        assertNotNull(mCoordinator.buildLegacyPromoView(parent));
+        assertNotNull(mCoordinator.buildBatchUploadCardView(parent));
+        assertNotNull(mCoordinator.buildSectionHeaderView(parent));
+        assertNotNull(BookmarkManagerCoordinator.buildDividerView(parent));
+        assertNotNull(BookmarkManagerCoordinator.buildCompactImprovedBookmarkRow(parent));
+        assertNotNull(BookmarkManagerCoordinator.buildVisualImprovedBookmarkRow(parent));
+        assertNotNull(mCoordinator.buildSearchBoxRow(parent));
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediatorTest.java
index 3fc6f2a..ba16028 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediatorTest.java
@@ -38,6 +38,7 @@
 
 import androidx.annotation.ColorInt;
 import androidx.annotation.StringRes;
+import androidx.lifecycle.LifecycleOwner;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
 import androidx.test.ext.junit.rules.ActivityScenarioRule;
@@ -57,6 +58,7 @@
 import org.robolectric.shadows.ShadowLooper;
 
 import org.chromium.base.Callback;
+import org.chromium.base.Promise;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.task.TaskTraits;
 import org.chromium.base.task.test.ShadowPostTask;
@@ -77,6 +79,7 @@
 import org.chromium.chrome.browser.commerce.PriceTrackingUtilsJni;
 import org.chromium.chrome.browser.commerce.ShoppingServiceFactory;
 import org.chromium.chrome.browser.commerce.ShoppingServiceFactoryJni;
+import org.chromium.chrome.browser.device_reauth.BiometricStatus;
 import org.chromium.chrome.browser.device_reauth.ReauthenticatorBridge;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -114,6 +117,8 @@
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
 import org.chromium.components.signin.identitymanager.IdentityManager;
+import org.chromium.components.sync.DataType;
+import org.chromium.components.sync.LocalDataDescription;
 import org.chromium.components.sync.SyncFeatureMap;
 import org.chromium.components.sync.SyncService;
 import org.chromium.components.sync.SyncService.SyncStateChangedListener;
@@ -123,6 +128,7 @@
 import org.chromium.ui.base.TestActivity;
 import org.chromium.ui.listmenu.BasicListMenu;
 import org.chromium.ui.listmenu.ListMenuItemProperties;
+import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modelutil.ListObservable;
 import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
 import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
@@ -133,7 +139,9 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Set;
 import java.util.function.BooleanSupplier;
 import java.util.function.Consumer;
 
@@ -159,6 +167,7 @@
 
     @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.LENIENT);
 
+    @Mock private ModalDialogManager mModalDialogManager;
     @Mock private BookmarkModel mBookmarkModel;
     @Mock private BookmarkOpener mBookmarkOpener;
     @Mock private SelectableListLayout<BookmarkId> mSelectableListLayout;
@@ -425,6 +434,7 @@
         doReturn(mIdentityManager).when(mSigninManager).getIdentityManager();
         doReturn(mIdentityManager).when(mIdentityServicesProvider).getIdentityManager(any());
         AccountManagerFacadeProvider.setInstanceForTests(mAccountManagerFacade);
+        doReturn(new Promise<>()).when(mAccountManagerFacade).getCoreAccountInfos();
 
         // Setup image fetching.
         doAnswer(
@@ -489,6 +499,8 @@
         mMediator =
                 new BookmarkManagerMediator(
                         mActivity,
+                        (LifecycleOwner) mActivity,
+                        mModalDialogManager,
                         mBookmarkModel,
                         mBookmarkOpener,
                         mSelectableListLayout,
@@ -1618,6 +1630,225 @@
                 R.string.local_bookmarks_section_header, entry.getSectionHeaderData().titleRes);
     }
 
+    @Test
+    @EnableFeatures(ChromeFeatureList.UNO_PHASE_2_FOLLOW_UP)
+    public void testRootLevelFolders_batchUploadCardPresentWhenLocalBookmarksExist() {
+        doReturn(true).when(mBookmarkModel).areAccountBookmarkFoldersActive();
+        BookmarkId accountReadingListId = new BookmarkId(mId++, BookmarkType.READING_LIST);
+        BookmarkItem accountReadingListItem =
+                new BookmarkItem(
+                        accountReadingListId,
+                        "Reading list",
+                        null,
+                        /* isFolder= */ true,
+                        mRootFolderId,
+                        /* isEditable= */ false,
+                        /* isManaged= */ false,
+                        /* dateAdded= */ 0,
+                        /* read= */ false,
+                        /* dateLastOpened= */ 0,
+                        /* isAccountBookmark= */ true);
+        doReturn(accountReadingListItem).when(mBookmarkModel).getBookmarkById(accountReadingListId);
+        doReturn(
+                        Arrays.asList(
+                                accountReadingListId,
+                                mDesktopFolderId,
+                                mMobileFolderId,
+                                mOtherFolderId,
+                                mReadingListFolderId))
+                .when(mBookmarkModel)
+                .getTopLevelFolderIds();
+
+        doAnswer(
+                        args -> {
+                            HashMap<Integer, LocalDataDescription> localDataDescription =
+                                    new HashMap<>();
+                            localDataDescription.put(
+                                    DataType.PASSWORDS,
+                                    new LocalDataDescription(0, new String[] {}, 0));
+                            localDataDescription.put(
+                                    DataType.BOOKMARKS,
+                                    new LocalDataDescription(1, new String[] {"example.com"}, 1));
+                            localDataDescription.put(
+                                    DataType.READING_LIST,
+                                    new LocalDataDescription(0, new String[] {}, 0));
+                            args.getArgument(1, Callback.class).onResult(localDataDescription);
+                            return null;
+                        })
+                .when(mSyncService)
+                .getLocalDataDescriptions(
+                        eq(Set.of(DataType.BOOKMARKS, DataType.PASSWORDS, DataType.READING_LIST)),
+                        any(Callback.class));
+        mMediator
+                .getBookmarkBatchUploadCardCoordinator()
+                .immediatelyHideBatchUploadCardAndUpdateItsVisibility();
+
+        mBookmarkUiPrefs.setBookmarkRowSortOrder(BookmarkRowSortOrder.ALPHABETICAL);
+        finishLoading();
+
+        mMediator.openFolder(mRootFolderId);
+
+        assertEquals(9, mModelList.size());
+        verifyCurrentBookmarkIds(
+                null, // Search bar
+                null, // Account heading
+                accountReadingListId,
+                null, //  Local heading.
+                null, // batch upload card
+                mDesktopFolderId,
+                mMobileFolderId,
+                mOtherFolderId,
+                mReadingListFolderId);
+
+        assertEquals(ViewType.BATCH_UPLOAD_CARD, mModelList.get(4).type);
+    }
+
+    @Test
+    @EnableFeatures(ChromeFeatureList.UNO_PHASE_2_FOLLOW_UP)
+    public void testRootLevelFolders_batchUploadCardPresentWhenLocalReadingListItemsExist() {
+        doReturn(true).when(mBookmarkModel).areAccountBookmarkFoldersActive();
+        BookmarkId accountReadingListId = new BookmarkId(mId++, BookmarkType.READING_LIST);
+        BookmarkItem accountReadingListItem =
+                new BookmarkItem(
+                        accountReadingListId,
+                        "Reading list",
+                        null,
+                        /* isFolder= */ true,
+                        mRootFolderId,
+                        /* isEditable= */ false,
+                        /* isManaged= */ false,
+                        /* dateAdded= */ 0,
+                        /* read= */ false,
+                        /* dateLastOpened= */ 0,
+                        /* isAccountBookmark= */ true);
+        doReturn(accountReadingListItem).when(mBookmarkModel).getBookmarkById(accountReadingListId);
+        doReturn(
+                        Arrays.asList(
+                                accountReadingListId,
+                                mDesktopFolderId,
+                                mMobileFolderId,
+                                mOtherFolderId,
+                                mReadingListFolderId))
+                .when(mBookmarkModel)
+                .getTopLevelFolderIds();
+
+        doAnswer(
+                        args -> {
+                            HashMap<Integer, LocalDataDescription> localDataDescription =
+                                    new HashMap<>();
+                            localDataDescription.put(
+                                    DataType.PASSWORDS,
+                                    new LocalDataDescription(0, new String[] {}, 0));
+                            localDataDescription.put(
+                                    DataType.BOOKMARKS,
+                                    new LocalDataDescription(0, new String[] {}, 0));
+                            localDataDescription.put(
+                                    DataType.READING_LIST,
+                                    new LocalDataDescription(1, new String[] {"example.com"}, 1));
+                            args.getArgument(1, Callback.class).onResult(localDataDescription);
+                            return null;
+                        })
+                .when(mSyncService)
+                .getLocalDataDescriptions(
+                        eq(Set.of(DataType.BOOKMARKS, DataType.PASSWORDS, DataType.READING_LIST)),
+                        any(Callback.class));
+        mMediator
+                .getBookmarkBatchUploadCardCoordinator()
+                .immediatelyHideBatchUploadCardAndUpdateItsVisibility();
+
+        mBookmarkUiPrefs.setBookmarkRowSortOrder(BookmarkRowSortOrder.ALPHABETICAL);
+        finishLoading();
+
+        mMediator.openFolder(mRootFolderId);
+
+        assertEquals(9, mModelList.size());
+        verifyCurrentBookmarkIds(
+                null, // Search bar
+                null, // Account heading
+                accountReadingListId,
+                null, //  Local heading.
+                null, // batch upload card
+                mDesktopFolderId,
+                mMobileFolderId,
+                mOtherFolderId,
+                mReadingListFolderId);
+
+        assertEquals(ViewType.BATCH_UPLOAD_CARD, mModelList.get(4).type);
+    }
+
+    @Test
+    @EnableFeatures(ChromeFeatureList.UNO_PHASE_2_FOLLOW_UP)
+    public void testRootLevelFolders_batchUploadCardDoesNotPresentWhenOnlyLocalPasswordsExist() {
+        doReturn(true).when(mBookmarkModel).areAccountBookmarkFoldersActive();
+        BookmarkId accountReadingListId = new BookmarkId(mId++, BookmarkType.READING_LIST);
+        BookmarkItem accountReadingListItem =
+                new BookmarkItem(
+                        accountReadingListId,
+                        "Reading list",
+                        null,
+                        /* isFolder= */ true,
+                        mRootFolderId,
+                        /* isEditable= */ false,
+                        /* isManaged= */ false,
+                        /* dateAdded= */ 0,
+                        /* read= */ false,
+                        /* dateLastOpened= */ 0,
+                        /* isAccountBookmark= */ true);
+        doReturn(accountReadingListItem).when(mBookmarkModel).getBookmarkById(accountReadingListId);
+        doReturn(
+                        Arrays.asList(
+                                accountReadingListId,
+                                mDesktopFolderId,
+                                mMobileFolderId,
+                                mOtherFolderId,
+                                mReadingListFolderId))
+                .when(mBookmarkModel)
+                .getTopLevelFolderIds();
+
+        when(mReauthenticatorMock.getBiometricAvailabilityStatus())
+                .thenReturn(BiometricStatus.BIOMETRICS_AVAILABLE);
+        doAnswer(
+                        args -> {
+                            HashMap<Integer, LocalDataDescription> localDataDescription =
+                                    new HashMap<>();
+                            localDataDescription.put(
+                                    DataType.PASSWORDS,
+                                    new LocalDataDescription(1, new String[] {"example.com"}, 1));
+                            localDataDescription.put(
+                                    DataType.BOOKMARKS,
+                                    new LocalDataDescription(0, new String[] {}, 0));
+                            localDataDescription.put(
+                                    DataType.READING_LIST,
+                                    new LocalDataDescription(0, new String[] {}, 0));
+                            args.getArgument(1, Callback.class).onResult(localDataDescription);
+                            return null;
+                        })
+                .when(mSyncService)
+                .getLocalDataDescriptions(
+                        eq(Set.of(DataType.BOOKMARKS, DataType.PASSWORDS, DataType.READING_LIST)),
+                        any(Callback.class));
+        mMediator
+                .getBookmarkBatchUploadCardCoordinator()
+                .immediatelyHideBatchUploadCardAndUpdateItsVisibility();
+
+        mBookmarkUiPrefs.setBookmarkRowSortOrder(BookmarkRowSortOrder.ALPHABETICAL);
+        finishLoading();
+
+        mMediator.openFolder(mRootFolderId);
+
+        assertEquals(8, mModelList.size());
+        // Make sure that batch upload card does not present.
+        verifyCurrentBookmarkIds(
+                null, // Search bar
+                null, // Account heading
+                accountReadingListId,
+                null, //  Local heading.
+                mDesktopFolderId,
+                mMobileFolderId,
+                mOtherFolderId,
+                mReadingListFolderId);
+    }
+
     // Tests directly related to a regression.
 
     @Test
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
index 71e6cbb..9ff923f 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
@@ -2183,7 +2183,7 @@
         StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
 
         // Start reorder for tab drop between the 2nd and 3rd tab.
-        mStripLayoutHelper.updateStripForExternalTabDrop(300.f);
+        mStripLayoutHelper.prepareForTabDrop(/* currX= */ 300.f, /* lastX= */ 0f, false, false);
 
         // Test tab outline should show for the foregrounded tab in destination window during tab
         // drop.
@@ -2764,7 +2764,7 @@
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         // Start reorder for tab drop between the 1st and 2nd tab.
-        mStripLayoutHelper.updateStripForExternalTabDrop(150.f);
+        mStripLayoutHelper.prepareForTabDrop(/* currX= */ 150.f, /* lastX= */ 0f, false, false);
 
         float expectedEndWidth =
                 expectedStartWidth
@@ -2786,7 +2786,7 @@
         ReorderDelegate reorderDelegateSpy = spy(mStripLayoutHelper.getReorderDelegateForTesting());
 
         // Start and stop reorder mode for tab drop.
-        mStripLayoutHelper.updateStripForExternalTabDrop(10.f);
+        mStripLayoutHelper.prepareForTabDrop(/* currX= */ 10.f, /* lastX= */ 0f, false, false);
         mStripLayoutHelper.stopReorderModeForTesting();
 
         // Verify: folio reattachment animation does not run for tab drop.
@@ -4434,7 +4434,7 @@
         float expectedOffsetX = 123.45f;
         mStripLayoutHelper.setActiveClickedTabAtIndexForTesting(0);
         mStripLayoutHelper.setLastOffsetXForTesting(expectedOffsetX);
-        mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0f, 0f, true, false);
+        mStripLayoutHelper.prepareForTabDrop(0f, 0f, true, false);
 
         // Verify we continue reorder mode with the correct x-offset.
         assertFalse(
@@ -4460,7 +4460,7 @@
         // Drag tab out of strip.
         float expectedOffsetX = 123.45f;
         mStripLayoutHelper.setActiveClickedTabAtIndexForTesting(0);
-        mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0f, 0f, true, false);
+        mStripLayoutHelper.prepareForTabDrop(0f, 0f, true, false);
         StripLayoutTab draggedTab = mStripLayoutHelper.getInteractingTabForTesting();
         draggedTab.setOffsetX(expectedOffsetX);
         mStripLayoutHelper.clearForTabDrop(TIMESTAMP, true, false);
@@ -4497,7 +4497,7 @@
         // Drag tab out of strip.
         StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
         mStripLayoutHelper.setTabAtPositionForTesting(tabs[1]);
-        mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0f, 0f, true, false);
+        mStripLayoutHelper.prepareForTabDrop(0f, 0f, true, false);
         mStripLayoutHelper.clearForTabDrop(TIMESTAMP, true, false);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
@@ -4571,7 +4571,7 @@
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         // Prepare for tab drop.
-        mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0.f, 0.f, false, false);
+        mStripLayoutHelper.prepareForTabDrop(0.f, 0.f, false, false);
         // Start gap will be tabWidth(265) / 2 = 132.5
         mStripLayoutHelper.setScrollOffsetForTesting(-132);
 
@@ -4624,7 +4624,7 @@
         groupTabs(1, 3);
 
         // Prepare for tab drop.
-        mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0.f, 0.f, false, false);
+        mStripLayoutHelper.prepareForTabDrop(0.f, 0.f, false, false);
 
         // Verify.
         StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
@@ -4660,7 +4660,7 @@
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         // Prepare for tab drop.
-        mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0.f, 0.f, false, false);
+        mStripLayoutHelper.prepareForTabDrop(0.f, 0.f, false, false);
         mStripLayoutHelper.finishAnimations();
         // Verify initial trailing margins before hover.
         StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
@@ -4703,7 +4703,7 @@
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         // Prepare for tab drop.
-        mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0.f, 0.f, false, false);
+        mStripLayoutHelper.prepareForTabDrop(0.f, 0.f, false, false);
         // Start gap will be tabWidth(265) / 2 = 132.5
         mStripLayoutHelper.setScrollOffsetForTesting(-132);
         mStripLayoutHelper.finishAnimations();
@@ -4745,7 +4745,7 @@
                 SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT);
 
         // Prepare and verify no interaction.
-        mStripLayoutHelper.prepareForTabDrop(TIMESTAMP, 0.f, 0.f, false, !isIncognito);
+        mStripLayoutHelper.prepareForTabDrop(0.f, 0.f, false, !isIncognito);
         assertFalse(
                 "Shouldn't start reorder when dragged tab Incognito state is different.",
                 mStripLayoutHelper.getInReorderModeForTesting());
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java
index 4fd11ac8..bf11110 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java
@@ -551,7 +551,7 @@
         // Verify appropriate events are generated.
         // Strip prepares for drop on drag enter.
         verify(mSourceStripLayoutHelper, times(1))
-                .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean(), anyBoolean());
+                .prepareForTabDrop(anyFloat(), anyFloat(), anyBoolean(), anyBoolean());
         // Stop reorder on drop.
         verify(mSourceStripLayoutHelper, times(1)).onUpOrCancel(anyLong());
         // Verify tab is not moved.
@@ -589,7 +589,7 @@
         // Verify appropriate events are generated.
         // Strip prepares for drop on drag enter.
         verify(mSourceStripLayoutHelper, times(1))
-                .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean(), anyBoolean());
+                .prepareForTabDrop(anyFloat(), anyFloat(), anyBoolean(), anyBoolean());
         // Strip clears state for drop on drag exit.
         verify(mSourceStripLayoutHelper, times(1))
                 .clearForTabDrop(anyLong(), anyBoolean(), anyBoolean());
@@ -620,7 +620,7 @@
         // Verify appropriate events are generated.
         // Strip prepares for drop on drag enter.
         verify(mSourceStripLayoutHelper, times(1))
-                .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean(), anyBoolean());
+                .prepareForTabDrop(anyFloat(), anyFloat(), anyBoolean(), anyBoolean());
         // Strip clears state for drop on drag exit.
         verify(mSourceStripLayoutHelper, times(1))
                 .clearForTabDrop(anyLong(), anyBoolean(), anyBoolean());
@@ -671,7 +671,7 @@
         // Verify appropriate events are generated.
         // Strip prepares for drop on drag enter.
         verify(mSourceStripLayoutHelper, times(1))
-                .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean(), anyBoolean());
+                .prepareForTabDrop(anyFloat(), anyFloat(), anyBoolean(), anyBoolean());
         // Strip clears state for drop on drag exit.
         verify(mSourceStripLayoutHelper, times(1))
                 .clearForTabDrop(anyLong(), anyBoolean(), anyBoolean());
@@ -829,7 +829,7 @@
         verify(mSourceStripLayoutHelper, times(1)).clearTabDragState();
         // Verify destination strip calls.
         verify(mDestStripLayoutHelper)
-                .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean(), anyBoolean());
+                .prepareForTabDrop(anyFloat(), anyFloat(), anyBoolean(), anyBoolean());
         verify(mDestStripLayoutHelper).onUpOrCancel(anyLong());
 
         assertNull(ShadowToast.getLatestToast());
@@ -915,13 +915,13 @@
         // Verify appropriate events are generated.
         // Source strip prepares for drop on drag enter.
         verify(mSourceStripLayoutHelper, times(1))
-                .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean(), anyBoolean());
+                .prepareForTabDrop(anyFloat(), anyFloat(), anyBoolean(), anyBoolean());
         // Source strip clears state for drop on drag exit.
         verify(mSourceStripLayoutHelper, times(1))
                 .clearForTabDrop(anyLong(), anyBoolean(), anyBoolean());
         // Destination strip prepares for drop on drag enter.
         verify(mDestStripLayoutHelper, times(1))
-                .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean(), anyBoolean());
+                .prepareForTabDrop(anyFloat(), anyFloat(), anyBoolean(), anyBoolean());
         // Destination strip clears state for drop on drag exit.
         verify(mDestStripLayoutHelper, times(1))
                 .clearForTabDrop(anyLong(), anyBoolean(), anyBoolean());
@@ -957,7 +957,7 @@
         // Verify appropriate events are generated.
         // Strip prepares for drop on drag enter. Entered twice.
         verify(mSourceStripLayoutHelper, times(2))
-                .prepareForTabDrop(anyLong(), anyFloat(), anyFloat(), anyBoolean(), anyBoolean());
+                .prepareForTabDrop(anyFloat(), anyFloat(), anyBoolean(), anyBoolean());
         // Stop reorder on drop.
         verify(mSourceStripLayoutHelper, times(1)).onUpOrCancel(anyLong());
         // Verify tab is not moved.
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/sync/ui/bookmark_batch_upload_card/BookmarkBatchUploadCardMediatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/sync/ui/bookmark_batch_upload_card/BookmarkBatchUploadCardMediatorTest.java
new file mode 100644
index 0000000..6095643f
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/sync/ui/bookmark_batch_upload_card/BookmarkBatchUploadCardMediatorTest.java
@@ -0,0 +1,202 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.sync.ui.bookmark_batch_upload_card;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+
+import android.app.Activity;
+
+import androidx.lifecycle.LifecycleOwner;
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import org.chromium.base.Callback;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.Features.EnableFeatures;
+import org.chromium.chrome.browser.device_reauth.ReauthenticatorBridge;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
+import org.chromium.chrome.browser.sync.SyncServiceFactory;
+import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
+import org.chromium.components.signin.identitymanager.IdentityManager;
+import org.chromium.components.sync.DataType;
+import org.chromium.components.sync.LocalDataDescription;
+import org.chromium.components.sync.SyncFeatureMap;
+import org.chromium.components.sync.SyncService;
+import org.chromium.ui.base.TestActivity;
+import org.chromium.ui.modaldialog.ModalDialogManager;
+import org.chromium.ui.modelutil.PropertyModel;
+
+import java.util.HashMap;
+import java.util.Set;
+
+/** Unit tests for {@link BookmarkBatchUploadCardMediator}. */
+@RunWith(BaseRobolectricTestRunner.class)
+@EnableFeatures({
+    SyncFeatureMap.SYNC_ENABLE_BOOKMARKS_IN_TRANSPORT_MODE,
+    ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS,
+    ChromeFeatureList.UNO_PHASE_2_FOLLOW_UP
+})
+public class BookmarkBatchUploadCardMediatorTest {
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    @Rule
+    public ActivityScenarioRule<TestActivity> mActivityScenarioRule =
+            new ActivityScenarioRule<>(TestActivity.class);
+
+    @Mock private ModalDialogManager mModalDialogManager;
+    @Mock private Profile mProfile;
+    @Mock private PropertyModel mModel;
+    @Mock private SnackbarManager mSnackbarManager;
+    @Mock private ReauthenticatorBridge mReauthenticatorMock;
+    @Mock private SyncService mSyncService;
+    @Mock private IdentityServicesProvider mIdentityServicesProvider;
+    @Mock private IdentityManager mIdentityManager;
+
+    private Activity mActivity;
+    private BookmarkBatchUploadCardMediator mMediator;
+
+    @Before
+    public void setUp() {
+        // Setup service mocks.
+        IdentityServicesProvider.setInstanceForTests(mIdentityServicesProvider);
+        SyncServiceFactory.setInstanceForTesting(mSyncService);
+        ReauthenticatorBridge.setInstanceForTesting(mReauthenticatorMock);
+        doReturn(mProfile).when(mProfile).getOriginalProfile();
+        doReturn(mIdentityManager).when(mIdentityServicesProvider).getIdentityManager(any());
+    }
+
+    @Test
+    public void testBatchUploadCardDoesNotPresentWhenLocalBookmarksExist() {
+        doAnswer(
+                        args -> {
+                            HashMap<Integer, LocalDataDescription> localDataDescription =
+                                    new HashMap<>();
+                            localDataDescription.put(
+                                    DataType.PASSWORDS,
+                                    new LocalDataDescription(0, new String[] {}, 0));
+                            localDataDescription.put(
+                                    DataType.BOOKMARKS,
+                                    new LocalDataDescription(0, new String[] {}, 0));
+                            localDataDescription.put(
+                                    DataType.READING_LIST,
+                                    new LocalDataDescription(0, new String[] {}, 0));
+                            args.getArgument(1, Callback.class).onResult(localDataDescription);
+                            return null;
+                        })
+                .when(mSyncService)
+                .getLocalDataDescriptions(
+                        eq(Set.of(DataType.BOOKMARKS, DataType.PASSWORDS, DataType.READING_LIST)),
+                        any(Callback.class));
+
+        mActivityScenarioRule
+                .getScenario()
+                .onActivity(
+                        (activity) -> {
+                            mMediator =
+                                    new BookmarkBatchUploadCardMediator(
+                                            activity,
+                                            (LifecycleOwner) activity,
+                                            mModalDialogManager,
+                                            mProfile,
+                                            mModel,
+                                            mSnackbarManager,
+                                            () -> {});
+                        });
+        Assert.assertFalse(mMediator.shouldBeVisible());
+    }
+
+    @Test
+    public void testBatchUploadCardPresentWhenLocalBookmarksExist() {
+        doAnswer(
+                        args -> {
+                            HashMap<Integer, LocalDataDescription> localDataDescription =
+                                    new HashMap<>();
+                            localDataDescription.put(
+                                    DataType.PASSWORDS,
+                                    new LocalDataDescription(0, new String[] {}, 0));
+                            localDataDescription.put(
+                                    DataType.BOOKMARKS,
+                                    new LocalDataDescription(1, new String[] {"example.com"}, 1));
+                            localDataDescription.put(
+                                    DataType.READING_LIST,
+                                    new LocalDataDescription(0, new String[] {}, 0));
+                            args.getArgument(1, Callback.class).onResult(localDataDescription);
+                            return null;
+                        })
+                .when(mSyncService)
+                .getLocalDataDescriptions(
+                        eq(Set.of(DataType.BOOKMARKS, DataType.PASSWORDS, DataType.READING_LIST)),
+                        any(Callback.class));
+
+        mActivityScenarioRule
+                .getScenario()
+                .onActivity(
+                        (activity) -> {
+                            mMediator =
+                                    new BookmarkBatchUploadCardMediator(
+                                            activity,
+                                            (LifecycleOwner) activity,
+                                            mModalDialogManager,
+                                            mProfile,
+                                            mModel,
+                                            mSnackbarManager,
+                                            () -> {});
+                        });
+        Assert.assertTrue(mMediator.shouldBeVisible());
+    }
+
+    @Test
+    public void testBatchUploadCardPresentWhenLocalReadingListEntriesExist() {
+        doAnswer(
+                        args -> {
+                            HashMap<Integer, LocalDataDescription> localDataDescription =
+                                    new HashMap<>();
+                            localDataDescription.put(
+                                    DataType.PASSWORDS,
+                                    new LocalDataDescription(0, new String[] {}, 0));
+                            localDataDescription.put(
+                                    DataType.BOOKMARKS,
+                                    new LocalDataDescription(0, new String[] {}, 0));
+                            localDataDescription.put(
+                                    DataType.READING_LIST,
+                                    new LocalDataDescription(1, new String[] {"example.com"}, 1));
+                            args.getArgument(1, Callback.class).onResult(localDataDescription);
+                            return null;
+                        })
+                .when(mSyncService)
+                .getLocalDataDescriptions(
+                        eq(Set.of(DataType.BOOKMARKS, DataType.PASSWORDS, DataType.READING_LIST)),
+                        any(Callback.class));
+
+        mActivityScenarioRule
+                .getScenario()
+                .onActivity(
+                        (activity) -> {
+                            mMediator =
+                                    new BookmarkBatchUploadCardMediator(
+                                            activity,
+                                            (LifecycleOwner) activity,
+                                            mModalDialogManager,
+                                            mProfile,
+                                            mModel,
+                                            mSnackbarManager,
+                                            () -> {});
+                        });
+        Assert.assertTrue(mMediator.shouldBeVisible());
+    }
+}
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 7bd839a..49170ad 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -842,12 +842,12 @@
           other {These extensions are no longer supported. Chromium recommends that you remove them.}}
         </message>
         <message name="IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_DISABLED_SUBTITLE" desc="Subtitle text displayed in the manifest v2 deprecation message for a specific extension during the disabled stage.">
-          Chromium recommends that you remove it. <ph name="BEGIN_LINK">&lt;a href="$1" target="_blank"&gt;</ph>Learn more about supported extensions<ph name="END_LINK">&lt;/a&gt;</ph>
+          Chromium recommends that you remove it. <ph name="BEGIN_LINK">&lt;a href="$1" aria-description="$2" target="_blank"&gt;</ph>Learn more about supported extensions<ph name="END_LINK">&lt;/a&gt;</ph>
         </message>
         <message name="IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_DISABLED_SUBTITLE" desc="Subtitle text displayed in the manifest v2 deprecation panel for the disabled stage.">
           {NUM_EXTENSIONS, plural,
-            =1 {Chromium recommends that you remove it. <ph name="BEGIN_LINK">&lt;a href="$1" target="_blank"&gt;</ph>Learn more about supported extensions<ph name="END_LINK">&lt;/a&gt;</ph>}
-            other {Chromium recommends that you remove them. <ph name="BEGIN_LINK">&lt;a href="$1" target="_blank"&gt;</ph>Learn more about supported extensions<ph name="END_LINK">&lt;/a&gt;</ph>}
+            =1 {Chromium recommends that you remove it. <ph name="BEGIN_LINK">&lt;a href="$1" aria-description="$2" target="_blank"&gt;</ph>Learn more about supported extensions<ph name="END_LINK">&lt;/a&gt;</ph>}
+            other {Chromium recommends that you remove them. <ph name="BEGIN_LINK">&lt;a href="$1" aria-description="$2" target="_blank"&gt;</ph>Learn more about supported extensions<ph name="END_LINK">&lt;/a&gt;</ph>}
           }
         </message>
         <message name="IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_REMOVE_BUTTON_ACC_LABEL" desc="The (accessible) label for the button to remove an extension.">
diff --git a/chrome/app/chromium_strings_grd/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_DISABLED_SUBTITLE.png.sha1 b/chrome/app/chromium_strings_grd/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_DISABLED_SUBTITLE.png.sha1
index f1ce84eb..cfbdd2be 100644
--- a/chrome/app/chromium_strings_grd/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_DISABLED_SUBTITLE.png.sha1
+++ b/chrome/app/chromium_strings_grd/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_DISABLED_SUBTITLE.png.sha1
@@ -1 +1 @@
-51109250ee9a597255bee808eec128056ffcbd3b
\ No newline at end of file
+3f74352f1dca03d122fe6d76cbafc9c56b9d3e20
\ No newline at end of file
diff --git a/chrome/app/chromium_strings_grd/IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_DISABLED_SUBTITLE.png.sha1 b/chrome/app/chromium_strings_grd/IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_DISABLED_SUBTITLE.png.sha1
index 40bcb35..41fd2a4 100644
--- a/chrome/app/chromium_strings_grd/IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_DISABLED_SUBTITLE.png.sha1
+++ b/chrome/app/chromium_strings_grd/IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_DISABLED_SUBTITLE.png.sha1
@@ -1 +1 @@
-03a18e35b9c9240c115fd21b4bd198d5d1043a00
\ No newline at end of file
+5dad491f9445f728fb9889b8df0948f5b0c238ca
\ No newline at end of file
diff --git a/chrome/app/extensions_strings.grdp b/chrome/app/extensions_strings.grdp
index 87701e4..7549a62 100644
--- a/chrome/app/extensions_strings.grdp
+++ b/chrome/app/extensions_strings.grdp
@@ -616,8 +616,8 @@
   </message>
   <message name="IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_WARNING_SUBTITLE" desc="Subtitle text displayed in the manifest v2 deprecation panel for the warning stage.">
     {NUM_EXTENSIONS, plural,
-      =1 {Remove or replace it with similar extensions from the <ph name="BEGIN_LINK">&lt;a href="$1" target="_blank"&gt;</ph>Chrome Web Store<ph name="END_LINK">&lt;/a&gt;</ph>.}
-      other {Remove or replace them with similar extensions from the <ph name="BEGIN_LINK">&lt;a href="$1" target="_blank"&gt;</ph>Chrome Web Store<ph name="END_LINK">&lt;/a&gt;</ph>}
+      =1 {Remove or replace it with similar extensions from the <ph name="BEGIN_LINK">&lt;a href="$1" aria-description="$2" target="_blank"&gt;</ph>Chrome Web Store<ph name="END_LINK">&lt;/a&gt;</ph>.}
+      other {Remove or replace them with similar extensions from the <ph name="BEGIN_LINK">&lt;a href="$1" aria-description="$2" target="_blank"&gt;</ph>Chrome Web Store<ph name="END_LINK">&lt;/a&gt;</ph>}
     }
   </message>
   <message name="IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_DISABLED_HEADER" desc="Header text displayed in the manifest v2 deprecation panel for the disabled stage.">
@@ -630,7 +630,7 @@
     This extension may soon no longer be supported
   </message>
   <message name="IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_WARNING_SUBTITLE" desc="Subtitle text displayed in the manifest v2 deprecation message for a specific extension during the warning stage.">
-    Remove or replace it with similar extensions from the <ph name="BEGIN_LINK">&lt;a href="$1" target="_blank"&gt;</ph>Chrome Web Store<ph name="END_LINK">&lt;/a&gt;</ph>
+    Remove or replace it with similar extensions from the <ph name="BEGIN_LINK">&lt;a href="$1" aria-description="$2" target="_blank"&gt;</ph>Chrome Web Store<ph name="END_LINK">&lt;/a&gt;</ph>
   </message>
   <message name="IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_DISABLED_HEADER" desc="Header text displayed in the manifest v2 deprecation message for a specific extension during the disabled stage.">
     This extension was turned off because it is no longer supported
diff --git a/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_WARNING_SUBTITLE.png.sha1 b/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_WARNING_SUBTITLE.png.sha1
index 64ee341..ac03adeb 100644
--- a/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_WARNING_SUBTITLE.png.sha1
+++ b/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_WARNING_SUBTITLE.png.sha1
@@ -1 +1 @@
-bb129a1552f68c320d75411ffd7894db6f775090
\ No newline at end of file
+900c2a4208ad2fac571bfb55b8848dddf4bac822
\ No newline at end of file
diff --git a/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_WARNING_SUBTITLE.png.sha1 b/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_WARNING_SUBTITLE.png.sha1
index ad2ca8d9..0d76a95 100644
--- a/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_WARNING_SUBTITLE.png.sha1
+++ b/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_WARNING_SUBTITLE.png.sha1
@@ -1 +1 @@
-f8da40787e3b7451de3ecc2c81152309ea16c00b
\ No newline at end of file
+9d48a07784a56cb7520a07d18f7bf20180b85384
\ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index ac7e239..059f686 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -9047,6 +9047,12 @@
       <message name="IDS_BOOKMARKS_ALL_BOOKMARKS_OPEN_SIDE_PANEL" desc="The bookmarks bar menu item which opens the side panel">
         Open Side Panel to see All Bookmarks
       </message>
+      <message name="IDS_BOOKMARKS_ACCOUNT_BOOKMARKS" desc="The header used for account bookmarks">
+        In your Google Account
+      </message>
+      <message name="IDS_BOOKMARKS_DEVICE_BOOKMARKS" desc="The header used for device bookmarks">
+        Only on this device
+      </message>
       <message name="IDS_BOOKMARKS_LABEL_TRACKED_PRODUCTS" desc="Label on a button within the bookmarks side panel for filtering bookmarks by price tracking data.">
         Tracked products
       </message>
diff --git a/chrome/app/generated_resources_grd/IDS_BOOKMARKS_ACCOUNT_BOOKMARKS.png.sha1 b/chrome/app/generated_resources_grd/IDS_BOOKMARKS_ACCOUNT_BOOKMARKS.png.sha1
new file mode 100644
index 0000000..7ce1058
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_BOOKMARKS_ACCOUNT_BOOKMARKS.png.sha1
@@ -0,0 +1 @@
+2d3850a07d3e002a7ed83b79e6bc0563aacdf8b0
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_BOOKMARKS_DEVICE_BOOKMARKS.png.sha1 b/chrome/app/generated_resources_grd/IDS_BOOKMARKS_DEVICE_BOOKMARKS.png.sha1
new file mode 100644
index 0000000..7ce1058
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_BOOKMARKS_DEVICE_BOOKMARKS.png.sha1
@@ -0,0 +1 @@
+2d3850a07d3e002a7ed83b79e6bc0563aacdf8b0
\ No newline at end of file
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index 34d54eb..9f8fc4d 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -821,12 +821,12 @@
           other {These extensions are no longer supported. Chrome recommends that you remove them.}}
         </message>
         <message name="IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_DISABLED_SUBTITLE" desc="Subtitle text displayed in the manifest v2 deprecation message for a specific extension during the disabled stage.">
-          Chrome recommends that you remove it. <ph name="BEGIN_LINK">&lt;a href="$1" target="_blank"&gt;</ph>Learn more about supported extensions<ph name="END_LINK">&lt;/a&gt;</ph>
+          Chrome recommends that you remove it. <ph name="BEGIN_LINK">&lt;a href="$1" aria-description="$2" target="_blank"&gt;</ph>Learn more about supported extensions<ph name="END_LINK">&lt;/a&gt;</ph>
         </message>
         <message name="IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_DISABLED_SUBTITLE" desc="Subtitle text displayed in the manifest v2 deprecation panel for the disabled stage.">
           {NUM_EXTENSIONS, plural,
-            =1 {Chrome recommends that you remove it. <ph name="BEGIN_LINK">&lt;a href="$1" target="_blank"&gt;</ph>Learn more about supported extensions<ph name="END_LINK">&lt;/a&gt;</ph>}
-            other {Chrome recommends that you remove them. <ph name="BEGIN_LINK">&lt;a href="$1" target="_blank"&gt;</ph>Learn more about supported extensions<ph name="END_LINK">&lt;/a&gt;</ph>}
+            =1 {Chrome recommends that you remove it. <ph name="BEGIN_LINK">&lt;a href="$1" aria-description="$2" target="_blank"&gt;</ph>Learn more about supported extensions<ph name="END_LINK">&lt;/a&gt;</ph>}
+            other {Chrome recommends that you remove them. <ph name="BEGIN_LINK">&lt;a href="$1" aria-description="$2" target="_blank"&gt;</ph>Learn more about supported extensions<ph name="END_LINK">&lt;/a&gt;</ph>}
           }
         </message>
         <message name="IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_REMOVE_BUTTON_ACC_LABEL" desc="The (accessible) label for the button to remove an extension.">
diff --git a/chrome/app/google_chrome_strings_grd/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_DISABLED_SUBTITLE.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_DISABLED_SUBTITLE.png.sha1
index f1ce84eb..cfbdd2be 100644
--- a/chrome/app/google_chrome_strings_grd/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_DISABLED_SUBTITLE.png.sha1
+++ b/chrome/app/google_chrome_strings_grd/IDS_EXTENSIONS_MV2_DEPRECATION_MESSAGE_DISABLED_SUBTITLE.png.sha1
@@ -1 +1 @@
-51109250ee9a597255bee808eec128056ffcbd3b
\ No newline at end of file
+3f74352f1dca03d122fe6d76cbafc9c56b9d3e20
\ No newline at end of file
diff --git a/chrome/app/google_chrome_strings_grd/IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_DISABLED_SUBTITLE.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_DISABLED_SUBTITLE.png.sha1
index 726efdc..41fd2a4 100644
--- a/chrome/app/google_chrome_strings_grd/IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_DISABLED_SUBTITLE.png.sha1
+++ b/chrome/app/google_chrome_strings_grd/IDS_EXTENSIONS_MV2_DEPRECATION_PANEL_DISABLED_SUBTITLE.png.sha1
@@ -1 +1 @@
-f96407801d32947cdd8f677ddcc91a713d9a2de6
\ No newline at end of file
+5dad491f9445f728fb9889b8df0948f5b0c238ca
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index cb71845f..7b82313 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3493,6 +3493,10 @@
       "accessibility/embedded_a11y_extension_loader.h",
       "accessibility/invert_bubble_prefs.cc",
       "accessibility/invert_bubble_prefs.h",
+      "accessibility/live_caption/live_caption_controller_factory.cc",
+      "accessibility/live_caption/live_caption_controller_factory.h",
+      "accessibility/live_caption/live_caption_speech_recognition_host.cc",
+      "accessibility/live_caption/live_caption_speech_recognition_host.h",
       "accessibility/live_translate_controller_factory.cc",
       "accessibility/live_translate_controller_factory.h",
       "accessibility/phrase_segmentation/dependency_parser_model_loader.cc",
@@ -3702,6 +3706,8 @@
       "lifetime/application_lifetime_desktop.h",
       "lifetime/browser_close_manager.cc",
       "lifetime/browser_close_manager.h",
+      "media/audio_ducker.cc",
+      "media/audio_ducker.h",
       "media/cast_mirroring_service_host.cc",
       "media/cast_mirroring_service_host.h",
       "media/cast_mirroring_service_host_factory.cc",
@@ -4514,15 +4520,6 @@
           [ "//chrome/browser/ui/webui/signin:profile_impl" ]
     }
 
-    if (!is_chromeos_lacros) {
-      sources += [
-        "accessibility/live_caption/live_caption_controller_factory.cc",
-        "accessibility/live_caption/live_caption_controller_factory.h",
-        "accessibility/live_caption/live_caption_speech_recognition_host.cc",
-        "accessibility/live_caption/live_caption_speech_recognition_host.h",
-      ]
-    }
-
     if (!is_win) {
       # On Windows, the hashes are embedded in //chrome:chrome_initial rather
       # than here in :chrome_dll.
@@ -5795,8 +5792,6 @@
 
   if (is_chromeos_lacros) {
     sources += [
-      "accessibility/live_caption/live_caption_surface.cc",
-      "accessibility/live_caption/live_caption_surface.h",
       "apps/digital_goods/digital_goods_factory_stub.cc",
       "apps/digital_goods/digital_goods_factory_stub.h",
       "apps/digital_goods/digital_goods_lacros.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 17ecd3717..19c4936 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -307,7 +307,6 @@
 #include "chromeos/ash/components/assistant/buildflags.h"
 #include "chromeos/ash/components/memory/swap_configuration.h"
 #include "chromeos/ash/components/standalone_browser/channel_util.h"
-#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
 #include "chromeos/ash/components/standalone_browser/lacros_selection.h"
 #include "chromeos/ash/components/standalone_browser/standalone_browser_features.h"
 #include "chromeos/ash/services/assistant/public/cpp/features.h"
@@ -1021,8 +1020,6 @@
      std::size(kZinkEnableRecommended), nullptr},
     {"for all apps", kZinkEnableAll, std::size(kZinkEnableAll), nullptr}};
 
-const char kLacrosAvailabilityIgnoreInternalName[] =
-    "lacros-availability-ignore";
 const char kLacrosWaylandLoggingInternalName[] = "lacros-wayland-logging";
 const char kArcEnableVirtioBlkForDataInternalName[] =
     "arc-enable-virtio-blk-for-data";
@@ -1044,19 +1041,6 @@
 const char kLacrosSelectionPolicyIgnoreInternalName[] =
     "lacros-selection-ignore";
 
-const FeatureEntry::Choice kLacrosAvailabilityPolicyChoices[] = {
-    {flags_ui::kGenericExperimentChoiceDefault, "", ""},
-    {ash::standalone_browser::kLacrosAvailabilityPolicyUserChoice,
-     ash::standalone_browser::kLacrosAvailabilityPolicySwitch,
-     ash::standalone_browser::kLacrosAvailabilityPolicyUserChoice},
-    {ash::standalone_browser::kLacrosAvailabilityPolicyLacrosDisabled,
-     ash::standalone_browser::kLacrosAvailabilityPolicySwitch,
-     ash::standalone_browser::kLacrosAvailabilityPolicyLacrosDisabled},
-    {ash::standalone_browser::kLacrosAvailabilityPolicyLacrosOnly,
-     ash::standalone_browser::kLacrosAvailabilityPolicySwitch,
-     ash::standalone_browser::kLacrosAvailabilityPolicyLacrosOnly},
-};
-
 const char kArcEnableAttestationFlag[] = "arc-enable-attestation";
 
 #endif  // BUILDFLAG(IS_CHROMEOS)
@@ -4793,9 +4777,6 @@
         FEATURE_VALUE_TYPE(ash::features::kEnableBrightnessControlInSettings),
     },
     // Used to carry the policy value crossing the Chrome process lifetime.
-    {ash::standalone_browser::kLacrosAvailabilityPolicyInternalName, "", "",
-     kOsCrOS, MULTI_VALUE_TYPE(kLacrosAvailabilityPolicyChoices)},
-    // Used to carry the policy value crossing the Chrome process lifetime.
     {kLacrosWaylandLoggingInternalName,
      flag_descriptions::kLacrosWaylandLoggingName,
      flag_descriptions::kLacrosWaylandLoggingDescription, kOsCrOS,
@@ -4816,10 +4797,6 @@
      flag_descriptions::kLacrosSelectionPolicyIgnoreName,
      flag_descriptions::kLacrosSelectionPolicyIgnoreDescription, kOsCrOS,
      SINGLE_VALUE_TYPE(ash::switches::kLacrosSelectionPolicyIgnore)},
-    {kLacrosAvailabilityIgnoreInternalName,
-     flag_descriptions::kLacrosAvailabilityIgnoreName,
-     flag_descriptions::kLacrosAvailabilityIgnoreDescription, kOsCrOS,
-     SINGLE_VALUE_TYPE(ash::switches::kLacrosAvailabilityIgnore)},
     {"list-all-display-modes", flag_descriptions::kListAllDisplayModesName,
      flag_descriptions::kListAllDisplayModesDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(display::features::kListAllDisplayModes)},
@@ -6989,16 +6966,6 @@
 #endif  // BUILDFLAG(IS_ANDROID)
 
 #if !BUILDFLAG(IS_ANDROID)
-    {"shopping-icon-color-variant",
-     commerce::flag_descriptions::kShoppingIconColorVariantName,
-     commerce::flag_descriptions::kShoppingIconColorVariantDescription,
-     kOsDesktop, FEATURE_VALUE_TYPE(commerce::kShoppingIconColorVariant)},
-
-    {"price-tracking-icon-colors",
-     commerce::flag_descriptions::kPriceTrackingIconColorsDescription,
-     commerce::flag_descriptions::kPriceTrackingIconColorsDescription,
-     kOsDesktop, FEATURE_VALUE_TYPE(commerce::kPriceTrackingIconColors)},
-
     {"enable-retail-coupons", flag_descriptions::kRetailCouponsName,
      flag_descriptions::kRetailCouponsDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(commerce::kRetailCoupons)},
@@ -8938,6 +8905,10 @@
      flag_descriptions::kFedCmButtonModeDescription, kOsAll,
      FEATURE_VALUE_TYPE(features::kFedCmButtonMode)},
 
+    {"fedcm-delegation", flag_descriptions::kFedCmDelegationName,
+     flag_descriptions::kFedCmDelegationDescription, kOsAll,
+     FEATURE_VALUE_TYPE(features::kFedCmDelegation)},
+
     {"fedcm-idp-registration", flag_descriptions::kFedCmIdPRegistrationName,
      flag_descriptions::kFedCmIdPRegistrationDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kFedCmIdPRegistration)},
@@ -9575,6 +9546,11 @@
      flag_descriptions::kProjectorGm3Description, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kProjectorGm3)},
 
+    {"projector-use-dvs-playback-endpoint",
+     flag_descriptions::kProjectorUseDVSPlaybackEndpointName,
+     flag_descriptions::kProjectorUseDVSPlaybackEndpointDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kProjectorUseDVSPlaybackEndpoint)},
+
     {"enable-annotator-mode", flag_descriptions::kAnnotatorModeName,
      flag_descriptions::kAnnotatorModeDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kAnnotatorMode)},
@@ -11990,13 +11966,6 @@
     return true;
   }
 
-  // Skip lacros-availability-policy always. This is a pseudo entry
-  // and used to carry the policy value crossing the Chrome's lifetime.
-  if (!strcmp(ash::standalone_browser::kLacrosAvailabilityPolicyInternalName,
-              entry.internal_name)) {
-    return true;
-  }
-
   // Skip lacros-selection if it is controlled by LacrosSelection policy.
   if (!strcmp(kLacrosSelectionInternalName, entry.internal_name)) {
     return ash::standalone_browser::GetCachedLacrosSelectionPolicy() !=
diff --git a/chrome/browser/accessibility/live_caption/live_caption_surface.cc b/chrome/browser/accessibility/live_caption/live_caption_surface.cc
deleted file mode 100644
index f2181a8..0000000
--- a/chrome/browser/accessibility/live_caption/live_caption_surface.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/accessibility/live_caption/live_caption_surface.h"
-
-#include <optional>
-
-#include "base/functional/callback_forward.h"
-#include "base/unguessable_token.h"
-#include "build/build_config.h"
-#include "chrome/browser/accessibility/caption_bubble_context_browser.h"
-#include "chrome/browser/accessibility/live_caption/live_caption_controller_factory.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "components/live_caption/live_caption_controller.h"
-#include "components/live_caption/views/caption_bubble_model.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/page.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_user_data.h"
-#include "ui/views/widget/widget.h"
-
-namespace captions {
-
-WEB_CONTENTS_USER_DATA_KEY_IMPL(LiveCaptionSurface);
-
-// static
-LiveCaptionSurface* LiveCaptionSurface::GetOrCreateForWebContents(
-    content::WebContents* web_contents) {
-  // No-op if a surface is already attached.
-  CreateForWebContents(web_contents);
-
-  return FromWebContents(web_contents);
-}
-
-LiveCaptionSurface::LiveCaptionSurface(content::WebContents* web_contents)
-    : content::WebContentsUserData<LiveCaptionSurface>(*web_contents),
-      content::WebContentsObserver(web_contents),
-      session_id_(base::UnguessableToken::Create()) {}
-
-LiveCaptionSurface::~LiveCaptionSurface() = default;
-
-void LiveCaptionSurface::BindToSurfaceClient(
-    mojo::PendingReceiver<media::mojom::SpeechRecognitionSurface> receiver,
-    mojo::PendingRemote<media::mojom::SpeechRecognitionSurfaceClient> remote) {
-  receivers_.Add(this, std::move(receiver));
-  clients_.Add(std::move(remote));
-}
-
-void LiveCaptionSurface::Activate() {
-  if (!web_contents()) {
-    return;
-  }
-
-  // Activate the web contents and the browser window that the web contents is
-  // in. Order matters: web contents needs to be active in order for the widget
-  // getter to work.
-  Browser* browser = chrome::FindBrowserWithTab(web_contents());
-  if (!browser) {
-    return;
-  }
-
-  TabStripModel* tab_strip_model = browser->tab_strip_model();
-  DCHECK(tab_strip_model);
-
-  const int index = tab_strip_model->GetIndexOfWebContents(web_contents());
-  if (index == TabStripModel::kNoTab) {
-    return;
-  }
-
-  tab_strip_model->ActivateTabAt(index);
-  views::Widget* context_widget = views::Widget::GetTopLevelWidgetForNativeView(
-      web_contents()->GetNativeView());
-  if (context_widget) {
-    context_widget->Activate();
-  }
-}
-
-void LiveCaptionSurface::GetBounds(GetBoundsCallback callback) {
-  if (!web_contents()) {
-    std::move(callback).Run(std::nullopt);
-    return;
-  }
-
-  views::Widget* context_widget = views::Widget::GetTopLevelWidgetForNativeView(
-      web_contents()->GetNativeView());
-  if (!context_widget) {
-    std::move(callback).Run(std::nullopt);
-    return;
-  }
-
-  std::move(callback).Run(context_widget->GetClientAreaBoundsInScreen());
-}
-
-void LiveCaptionSurface::MediaEffectivelyFullscreenChanged(
-    bool /*is_fullscreen*/) {
-  for (const auto& client : clients_) {
-    client->OnFullscreenToggled();
-  }
-}
-
-void LiveCaptionSurface::PrimaryPageChanged(content::Page& /*page*/) {
-  for (const auto& client : clients_) {
-    client->OnSessionEnded();
-  }
-}
-
-base::UnguessableToken LiveCaptionSurface::session_id() const {
-  return session_id_;
-}
-
-}  // namespace captions
diff --git a/chrome/browser/accessibility/live_caption/live_caption_surface.h b/chrome/browser/accessibility/live_caption/live_caption_surface.h
deleted file mode 100644
index 592dc3e..0000000
--- a/chrome/browser/accessibility/live_caption/live_caption_surface.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ACCESSIBILITY_LIVE_CAPTION_LIVE_CAPTION_SURFACE_H_
-#define CHROME_BROWSER_ACCESSIBILITY_LIVE_CAPTION_LIVE_CAPTION_SURFACE_H_
-
-#include "base/unguessable_token.h"
-#include "build/build_config.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_user_data.h"
-#include "media/mojo/mojom/speech_recognition.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
-#include "mojo/public/cpp/bindings/remote_set.h"
-
-namespace content {
-class Page;
-class WebContents;
-}  // namespace content
-
-namespace captions {
-
-// Represents the document as a user-facing surface that produces live captions.
-// This interface allows remote processes to manipulate the document as required
-// for live caption rendering (e.g. by bringing it into focus).
-//
-// An instance of this object is owned by a `WebContents` and its lifetime is
-// bound to the `WebContents`' lifetime. Up to one instance of this class can
-// be instantiated for a single `WebContents`.
-class LiveCaptionSurface
-    : public media::mojom::SpeechRecognitionSurface,
-      public content::WebContentsUserData<LiveCaptionSurface>,
-      public content::WebContentsObserver {
- public:
-  LiveCaptionSurface(const LiveCaptionSurface&) = delete;
-  LiveCaptionSurface& operator=(const LiveCaptionSurface&) = delete;
-  ~LiveCaptionSurface() override;
-
-  // static
-  static LiveCaptionSurface* GetOrCreateForWebContents(
-      content::WebContents* web_contents);
-
-  // Set up coordintation with a new surface client in Ash.
-  void BindToSurfaceClient(
-      mojo::PendingReceiver<media::mojom::SpeechRecognitionSurface> receiver,
-      mojo::PendingRemote<media::mojom::SpeechRecognitionSurfaceClient> remote);
-
-  // media::mojom::SpeechRecognitionSurface:
-  void Activate() override;
-  void GetBounds(GetBoundsCallback callback) override;
-
-  // content::WebContentsObserver:
-  void MediaEffectivelyFullscreenChanged(bool is_fullscreen) override;
-  void PrimaryPageChanged(content::Page& page) override;
-
-  // Returns a unique identifier for the current web contents.
-  base::UnguessableToken session_id() const;
-
- private:
-  friend content::WebContentsUserData<LiveCaptionSurface>;
-  WEB_CONTENTS_USER_DATA_KEY_DECL();
-
-  explicit LiveCaptionSurface(content::WebContents* web_contents);
-
-  const base::UnguessableToken session_id_;
-
-  mojo::ReceiverSet<media::mojom::SpeechRecognitionSurface> receivers_;
-  mojo::RemoteSet<media::mojom::SpeechRecognitionSurfaceClient> clients_;
-};
-
-}  // namespace captions
-
-#endif  // CHROME_BROWSER_ACCESSIBILITY_LIVE_CAPTION_LIVE_CAPTION_SURFACE_H_
diff --git a/chrome/browser/ai/ai_language_model.cc b/chrome/browser/ai/ai_language_model.cc
index 2721c788..7881008 100644
--- a/chrome/browser/ai/ai_language_model.cc
+++ b/chrome/browser/ai/ai_language_model.cc
@@ -9,6 +9,7 @@
 #include <sstream>
 
 #include "base/check_op.h"
+#include "base/feature_list.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_forward.h"
 #include "base/notreached.h"
@@ -30,6 +31,23 @@
 #include "third_party/blink/public/mojom/ai/ai_manager.mojom-shared.h"
 #include "third_party/blink/public/mojom/ai/model_streaming_responder.mojom.h"
 
+namespace features {
+
+// Indicates the streaming behavior of this session.
+// If it's true, each streaming response will contain the full content that's
+// generated so far. e.g.
+// - This is
+// - This is a test
+// - This is a test response.
+// If it's false, the response will be streamed back chunk by chunk. e.g.
+// - This is
+// - a test
+// - response.
+BASE_FEATURE(kAILanguageModelForceStreamingFullResponse,
+             "AILanguageModelForceStreamingFullResponse",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+}  // namespace features
 namespace {
 
 using optimization_guide::proto::PromptApiMetadata;
@@ -177,7 +195,8 @@
       &AIContextBoundObject::RemoveFromSet, base::Unretained(this)));
 
   auto metadata = ParseMetadata(session_->GetOnDeviceFeatureMetadata());
-  is_streaming_chunk_by_chunk_ = metadata.is_streaming_chunk_by_chunk();
+  is_on_device_session_streaming_chunk_by_chunk_ =
+      metadata.is_streaming_chunk_by_chunk();
 
   if (context.has_value()) {
     // If the context is provided, it will be used in this session.
@@ -286,14 +305,26 @@
 
   auto response = optimization_guide::ParsedAnyMetadata<
       optimization_guide::proto::StringValue>(result.response->response);
-  if (is_streaming_chunk_by_chunk_) {
+  std::string streaming_result = response->value();
+  bool should_stream_full_response = base::FeatureList::IsEnabled(
+      features::kAILanguageModelForceStreamingFullResponse);
+  if (is_on_device_session_streaming_chunk_by_chunk_) {
+    // We need this for the context adding.
     current_response_ += response->value();
+    if (should_stream_full_response) {
+      // Adapting the chunk-by-chunk mode to the current-response mode.
+      streaming_result = current_response_;
+    }
   } else {
+    if (!should_stream_full_response) {
+      // Adapting the current-response mode to the chunk-by-chunk mode.
+      streaming_result = response->value().substr(current_response_.size());
+    }
     current_response_ = response->value();
   }
 
   if (response->has_value()) {
-    responder->OnStreaming(current_response_);
+    responder->OnStreaming(streaming_result);
   }
   if (result.response->is_complete) {
     // TODO(crbug.com/351935390): instead of calculating this from the
diff --git a/chrome/browser/ai/ai_language_model.h b/chrome/browser/ai/ai_language_model.h
index 4664b6c..80c43942 100644
--- a/chrome/browser/ai/ai_language_model.h
+++ b/chrome/browser/ai/ai_language_model.h
@@ -8,6 +8,7 @@
 #include <deque>
 #include <optional>
 
+#include "base/feature_list.h"
 #include "base/functional/callback_forward.h"
 #include "base/memory/weak_ptr.h"
 #include "base/types/expected.h"
@@ -23,6 +24,12 @@
 #include "third_party/blink/public/mojom/ai/ai_manager.mojom-forward.h"
 #include "third_party/blink/public/mojom/ai/model_streaming_responder.mojom-forward.h"
 
+namespace features {
+
+BASE_DECLARE_FEATURE(kAILanguageModelForceStreamingFullResponse);
+
+}  // namespace features
+
 class AIManager;
 
 // The implementation of `blink::mojom::AILanguageModel`, which exposes the APIs
@@ -172,7 +179,7 @@
   base::raw_ref<AIContextBoundObjectSet> context_bound_object_set_;
   base::raw_ref<AIManager> ai_manager_;
 
-  bool is_streaming_chunk_by_chunk_;
+  bool is_on_device_session_streaming_chunk_by_chunk_;
   // The accumulated current response to simulate the old streaming behavior
   // that always returns all the response generated so far.
   std::string current_response_;
diff --git a/chrome/browser/ai/ai_language_model_unittest.cc b/chrome/browser/ai/ai_language_model_unittest.cc
index 98b8eeed..d2b37832 100644
--- a/chrome/browser/ai/ai_language_model_unittest.cc
+++ b/chrome/browser/ai/ai_language_model_unittest.cc
@@ -159,8 +159,9 @@
 }  // namespace
 
 class AILanguageModelTest : public AITestUtils::AITestBase,
-                            public testing::WithParamInterface<
-                                /*is_model_streaming_chunk_by_chunk=*/bool> {
+                            public testing::WithParamInterface<testing::tuple<
+                                /*is_model_streaming_chunk_by_chunk=*/bool,
+                                /*is_api_streaming_chunk_by_chunk=*/bool>> {
  public:
   struct Options {
     blink::mojom::AILanguageModelSamplingParamsPtr sampling_params = nullptr;
@@ -176,16 +177,26 @@
   };
 
   void SetUp() override {
-    AITestUtils::AITestBase::SetUp();
-    scoped_feature_list_.InitWithFeaturesAndParameters(
-        {base::test::FeatureRefAndParams(
+    std::vector<base::test::FeatureRefAndParams> enabled_features{
+        base::test::FeatureRefAndParams(
             features::kAILanguageModelOverrideConfiguration,
-            {{"max_top_k", base::NumberToString(kOverrideMaxTopK)}})},
-        {});
+            {{"max_top_k", base::NumberToString(kOverrideMaxTopK)}})};
+    std::vector<base::test::FeatureRef> disabled_features{};
+    if (IsAPIStreamingChunkByChunk()) {
+      disabled_features.push_back(
+          features::kAILanguageModelForceStreamingFullResponse);
+    } else {
+      enabled_features.push_back(base::test::FeatureRefAndParams(
+          features::kAILanguageModelForceStreamingFullResponse, {}));
+    }
+    AITestUtils::AITestBase::SetUp();
+    scoped_feature_list_.InitWithFeaturesAndParameters(enabled_features,
+                                                       disabled_features);
   }
 
  protected:
-  bool IsModelStreamingChunkByChunk() { return GetParam(); }
+  bool IsModelStreamingChunkByChunk() { return std::get<0>(GetParam()); }
+  bool IsAPIStreamingChunkByChunk() { return std::get<1>(GetParam()); }
 
   // The helper function that creates a `AILanguageModel` and executes the
   // prompt.
@@ -261,6 +272,7 @@
                     EXPECT_THAT(ToString(request_metadata),
                                 options.expected_context);
                   });
+
           EXPECT_CALL(*session, ExecuteModel(_, _))
               .WillOnce(
                   [&](const google::protobuf::MessageLite& request_metadata,
@@ -269,8 +281,7 @@
                               callback) {
                     EXPECT_THAT(ToString(request_metadata),
                                 options.expected_prompt);
-                    callback.Run(CreateExecutionResult(kTestResponse,
-                                                       /*is_complete=*/true));
+                    StreamResponse(callback);
                   });
           return session;
         })
@@ -298,8 +309,7 @@
                               callback) {
                     EXPECT_THAT(ToString(request_metadata),
                                 options.expected_prompt);
-                    callback.Run(CreateExecutionResult(kTestResponse,
-                                                       /*is_complete=*/true));
+                    StreamResponse(callback);
                   });
           return session;
         });
@@ -436,15 +446,46 @@
             });
   }
 
+  void StreamResponse(
+      optimization_guide::OptimizationGuideModelExecutionResultStreamingCallback
+          callback) {
+    std::string responses[3];
+    std::string response = std::string(kTestResponse);
+    if (IsModelStreamingChunkByChunk()) {
+      responses[0] = response.substr(0, 1);
+      responses[1] = response.substr(1);
+      responses[2] = "";
+    } else {
+      responses[0] = response.substr(0, 1);
+      responses[1] = kTestResponse;
+      responses[2] = kTestResponse;
+    }
+    callback.Run(CreateExecutionResult(responses[0],
+                                       /*is_complete=*/false));
+    callback.Run(CreateExecutionResult(responses[1],
+                                       /*is_complete=*/false));
+    callback.Run(CreateExecutionResult(responses[2],
+                                       /*is_complete=*/true));
+  }
+
   void TestPromptCall(mojo::Remote<blink::mojom::AILanguageModel>& mock_session,
                       std::string& prompt,
                       bool should_overflow_context) {
     AITestUtils::MockModelStreamingResponder mock_responder;
 
     base::RunLoop responder_run_loop;
+    std::string response = std::string(kTestResponse);
     EXPECT_CALL(mock_responder, OnStreaming(_))
+        .Times(3)
         .WillOnce(testing::Invoke([&](const std::string& text) {
-          EXPECT_THAT(text, kTestResponse);
+          EXPECT_THAT(text, response.substr(0, 1));
+        }))
+        .WillOnce(testing::Invoke([&](const std::string& text) {
+          EXPECT_THAT(text, IsAPIStreamingChunkByChunk() ? response.substr(1)
+                                                         : kTestResponse);
+        }))
+        .WillOnce(testing::Invoke([&](const std::string& text) {
+          EXPECT_THAT(text, IsAPIStreamingChunkByChunk() ? "" : kTestResponse);
         }));
 
     EXPECT_CALL(mock_responder, OnCompletion(_))
@@ -460,14 +501,21 @@
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         AILanguageModelTest,
-                         testing::Bool(),
-                         [](const testing::TestParamInfo<bool>& info) {
-                           return info.param
-                                      ? "IsModelStreamingChunkByChunk"
-                                      : "IsModelStreamingWithCurrentResponse";
-                         });
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    AILanguageModelTest,
+    testing::Combine(testing::Bool(), testing::Bool()),
+    [](const testing::TestParamInfo<testing::tuple<bool, bool>>& info) {
+      std::string description = "";
+      description += std::get<0>(info.param)
+                         ? "IsModelStreamingChunkByChunk"
+                         : "IsModelStreamingWithCurrentResponse";
+      description += "_";
+      description += std::get<1>(info.param)
+                         ? "IsAPIStreamingChunkByChunk"
+                         : "IsAPIStreamingWithCurrentResponse";
+      return description;
+    });
 
 TEST_P(AILanguageModelTest, PromptDefaultSession) {
   RunPromptTest(AILanguageModelTest::Options{
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index 2a72d77c..15cf1cfe 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -367,7 +367,6 @@
     testonly = true
 
     deps = [
-      "//chrome/browser/ash/accessibility/live_caption:interactive_ui_tests",
       "//chrome/browser/ash/app_list:interactive_ui_tests",
       "//chrome/browser/ash/child_accounts:interactive_ui_tests",
       "//chrome/browser/ash/file_manager:interactive_ui_tests",
diff --git a/chrome/browser/ash/accessibility/live_caption/BUILD.gn b/chrome/browser/ash/accessibility/live_caption/BUILD.gn
index bc1369b..52e5ba1 100644
--- a/chrome/browser/ash/accessibility/live_caption/BUILD.gn
+++ b/chrome/browser/ash/accessibility/live_caption/BUILD.gn
@@ -50,33 +50,3 @@
     "//components/live_caption:constants",
   ]
 }
-
-if (!is_chromeos_device) {
-  source_set("interactive_ui_tests") {
-    testonly = true
-
-    defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
-
-    sources = [ "live_caption_ui_remote_driver_browsertest.cc" ]
-
-    deps = [
-      "//ash/constants",
-      "//base",
-      "//base/test:test_support",
-      "//chrome/browser",
-      "//chrome/browser/profiles:profile",
-      "//chrome/browser/ui",
-      "//chrome/test:test_support_ui",
-      "//components/live_caption",
-      "//components/live_caption:constants",
-      "//components/soda",
-      "//content/test:test_support",
-      "//mojo/public/cpp/bindings",
-      "//testing/gmock",
-      "//testing/gtest",
-      "//ui/events",
-      "//ui/gfx",
-      "//ui/views",
-    ]
-  }
-}
diff --git a/chrome/browser/ash/accessibility/live_caption/live_caption_ui_remote_driver_browsertest.cc b/chrome/browser/ash/accessibility/live_caption/live_caption_ui_remote_driver_browsertest.cc
deleted file mode 100644
index 5d2c2cf..0000000
--- a/chrome/browser/ash/accessibility/live_caption/live_caption_ui_remote_driver_browsertest.cc
+++ /dev/null
@@ -1,392 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This test lives in ::ash (v.s. the live_caption component) because it
-// exercises as much of the UI stack as possible, which includes e.g. enabling
-// Ash-specific features.
-
-#include "components/live_caption/live_caption_ui_remote_driver.h"
-
-#include "ash/constants/ash_features.h"
-#include "base/memory/raw_ptr.h"
-#include "base/run_loop.h"
-#include "base/test/bind.h"
-#include "base/test/scoped_feature_list.h"
-#include "chrome/browser/accessibility/live_caption/live_caption_controller_factory.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "components/live_caption/caption_bubble_controller.h"
-#include "components/live_caption/live_caption_controller.h"
-#include "components/live_caption/pref_names.h"
-#include "components/live_caption/views/caption_bubble.h"
-#include "components/live_caption/views/caption_bubble_controller_views.h"
-#include "components/soda/soda_installer.h"
-#include "content/public/test/browser_test.h"
-#include "media/mojo/mojom/speech_recognition_result.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "mojo/public/cpp/bindings/self_owned_receiver.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/base_event_utils.h"
-#include "ui/events/event.h"
-#include "ui/events/event_constants.h"
-#include "ui/events/types/event_type.h"
-#include "ui/gfx/geometry/insets.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/views/controls/button/button.h"
-#include "ui/views/widget/widget.h"
-
-namespace ash {
-namespace {
-
-using media::mojom::SpeechRecognitionRecognizerClient;
-using media::mojom::SpeechRecognitionSurface;
-using media::mojom::SpeechRecognitionSurfaceClient;
-using testing::_;
-
-class MockSurface : public SpeechRecognitionSurface {
- public:
-  MockSurface() = default;
-  ~MockSurface() override = default;
-
-  MockSurface(const MockSurface&) = delete;
-  MockSurface& operator=(const MockSurface&) = delete;
-
-  // Establish ourselves as the implementation of the surface, and grab a handle
-  // to the remote surface client. For good measure, hold the given recognizer
-  // client remote, since its self-owned implementation will destroy itself
-  // unless we do.
-  void Bind(mojo::PendingReceiver<SpeechRecognitionSurface> receiver,
-            mojo::PendingRemote<SpeechRecognitionSurfaceClient> surface_client,
-            mojo::PendingRemote<SpeechRecognitionRecognizerClient>
-                recognizer_client) {
-    receiver_.Bind(std::move(receiver));
-    surface_client_.Bind(std::move(surface_client));
-    recognizer_client_.Bind(std::move(recognizer_client));
-  }
-
-  mojo::Remote<SpeechRecognitionRecognizerClient>& remote_recognizer_client() {
-    return recognizer_client_;
-  }
-
-  // media::mojom::SpeechRecognitionSurface:
-  MOCK_METHOD(void, Activate, (), (override));
-  MOCK_METHOD(void,
-              GetBounds,
-              (SpeechRecognitionSurface::GetBoundsCallback),
-              (override));
-
- private:
-  mojo::Receiver<SpeechRecognitionSurface> receiver_{this};
-  mojo::Remote<SpeechRecognitionSurfaceClient> surface_client_;
-
-  // Must hold this to keep the UI driver alive.
-  mojo::Remote<SpeechRecognitionRecognizerClient> recognizer_client_;
-};
-
-class LiveCaptionUiRemoteDriverTest : public InProcessBrowserTest {
- public:
-  LiveCaptionUiRemoteDriverTest()
-      : scoped_feature_list_(features::kOnDeviceSpeechRecognition) {}
-  ~LiveCaptionUiRemoteDriverTest() override = default;
-
-  LiveCaptionUiRemoteDriverTest(const LiveCaptionUiRemoteDriverTest&) = delete;
-  LiveCaptionUiRemoteDriverTest& operator=(
-      const LiveCaptionUiRemoteDriverTest&) = delete;
-
-  void SetUpOnMainThread() override {
-    InProcessBrowserTest::SetUpOnMainThread();
-
-    browser()->profile()->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled,
-                                                 true);
-
-    // Don't actually try to download SODA.
-    speech::SodaInstaller::GetInstance()->NeverDownloadSodaForTesting();
-
-    // Create bubble UI and grab a handle to it.
-    controller_ = captions::LiveCaptionControllerFactory::GetForProfile(
-        browser()->profile());
-    base::RunLoop().RunUntilIdle();
-  }
-
-  // Test-only getters.
-
-  captions::CaptionBubbleControllerViews* bubble_controller() const {
-    return static_cast<captions::CaptionBubbleControllerViews*>(
-        controller_->caption_bubble_controller_for_testing());
-  }
-
-  captions::CaptionBubble* bubble() {
-    return bubble_controller()->GetCaptionBubbleForTesting();
-  }
-
-  bool IsWidgetVisible() const {
-    return bubble_controller() &&
-           bubble_controller()->IsWidgetVisibleForTesting();
-  }
-
-  std::string GetBubbleText() const {
-    return bubble_controller()
-               ? bubble_controller()->GetBubbleLabelTextForTesting()
-               : "";
-  }
-
-  // Create a new UI driver that communicates with the provided mock surface.
-  // The driver will destroy itself its connection to the surface drops.
-  captions::LiveCaptionUiRemoteDriver* NewUiDriverForSurface(
-      MockSurface* surface,
-      bool stub_bounds) {
-    // Bind the fake lacros ends of the Mojo pipes.
-    mojo::PendingReceiver<media::mojom::SpeechRecognitionRecognizerClient>
-        client_receiver;
-    mojo::PendingReceiver<media::mojom::SpeechRecognitionSurfaceClient>
-        surface_client_receiver;
-    mojo::PendingRemote<media::mojom::SpeechRecognitionSurface> surface_remote;
-    surface->Bind(surface_remote.InitWithNewPipeAndPassReceiver(),
-                  surface_client_receiver.InitWithNewPipeAndPassRemote(),
-                  client_receiver.InitWithNewPipeAndPassRemote());
-
-    // Sending an initial transcription will trigger a bounds query that must be
-    // replied to. The expectation is optionally added here since it is used in
-    // many tests.
-    if (stub_bounds) {
-      EXPECT_CALL(*surface, GetBounds(_))
-          .WillOnce(
-              [&](auto cb) { std::move(cb).Run(gfx::Rect(1, 1, 600, 800)); })
-          .RetiresOnSaturation();
-    }
-
-    // Create a driver and bind the Ash ends of the Mojo pipes.
-    auto driver = std::make_unique<captions::LiveCaptionUiRemoteDriver>(
-        controller_, std::move(surface_client_receiver),
-        std::move(surface_remote), "session-id");
-    captions::LiveCaptionUiRemoteDriver* raw_driver = driver.get();
-
-    mojo::MakeSelfOwnedReceiver(std::move(driver), std::move(client_receiver));
-    return raw_driver;
-  }
-
-  // Emulate new transcriptions being generated for the given surface and wait
-  // until the recognizer client has responded.
-  bool EmitTranscribedText(MockSurface* surface, const std::string& text) {
-    bool result = false;
-    surface->remote_recognizer_client()->OnSpeechRecognitionRecognitionEvent(
-        media::SpeechRecognitionResult(text, /*is_final=*/false),
-        base::BindLambdaForTesting([&](bool r) { result = r; }));
-    base::RunLoop().RunUntilIdle();
-    return result;
-  }
-
-  // Emulate clicking the given button with the mouse.
-  void ClickButton(views::Button* button) {
-    button->OnMousePressed(ui::MouseEvent(
-        ui::EventType::kMousePressed, gfx::Point(0, 0), gfx::Point(0, 0),
-        ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0));
-    button->OnMouseReleased(ui::MouseEvent(
-        ui::EventType::kMouseReleased, gfx::Point(0, 0), gfx::Point(0, 0),
-        ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0));
-  }
-
- protected:
-  raw_ptr<captions::LiveCaptionController, DanglingUntriaged> controller_;
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-// Test that captions sent from lacros are shown in the bubble.
-IN_PROC_BROWSER_TEST_F(LiveCaptionUiRemoteDriverTest, DisplaysText) {
-  MockSurface surface;
-  NewUiDriverForSurface(&surface, /*stub_bounds=*/true);
-
-  // Emitting text should cause the bubble to appear.
-  EXPECT_TRUE(EmitTranscribedText(&surface, "Test text"));
-  EXPECT_TRUE(IsWidgetVisible());
-  EXPECT_EQ("Test text", GetBubbleText());
-
-  // Emitting empty text should cause the bubble to disappear.
-  EXPECT_TRUE(EmitTranscribedText(&surface, ""));
-  EXPECT_FALSE(IsWidgetVisible());
-
-  // Bubble should be shown again when non-empty text is emitted.
-  EXPECT_TRUE(EmitTranscribedText(&surface, "Test text 2"));
-  EXPECT_TRUE(IsWidgetVisible());
-  EXPECT_EQ("Test text 2", GetBubbleText());
-}
-
-// Test that two media sources are both handled by the bubble.
-IN_PROC_BROWSER_TEST_F(LiveCaptionUiRemoteDriverTest, MultipleSources) {
-  MockSurface surface_1;
-  NewUiDriverForSurface(&surface_1, /*stub_bounds=*/true);
-
-  MockSurface surface_2;
-  NewUiDriverForSurface(&surface_2, /*stub_bounds=*/false);
-
-  // Text from surface 1 should be shown.
-  EXPECT_TRUE(EmitTranscribedText(&surface_1, "Surface 1 text"));
-  EXPECT_TRUE(IsWidgetVisible());
-  EXPECT_EQ("Surface 1 text", GetBubbleText());
-
-  // Text from surface 2 should replace surface 1's text because it is newer.
-  EXPECT_TRUE(EmitTranscribedText(&surface_2, "Surface 2 text"));
-  EXPECT_TRUE(IsWidgetVisible());
-  EXPECT_EQ("Surface 2 text", GetBubbleText());
-
-  // Back to surface 1.
-  EXPECT_TRUE(EmitTranscribedText(&surface_1, "More surface 1 text"));
-  EXPECT_TRUE(IsWidgetVisible());
-  EXPECT_EQ("More surface 1 text", GetBubbleText());
-}
-
-// Test that bubble is placed in correct position.
-IN_PROC_BROWSER_TEST_F(LiveCaptionUiRemoteDriverTest, BubblePosition) {
-  MockSurface surface;
-  NewUiDriverForSurface(&surface, /*stub_bounds=*/false);
-
-  // Set browser window to a known size and have the surface report the size.
-  const gfx::Rect window_bounds(10, 10, 800, 600);
-  browser()->window()->SetBounds(window_bounds);
-  EXPECT_CALL(surface, GetBounds(_))
-      .WillOnce([&](auto cb) { std::move(cb).Run(window_bounds); })
-      .RetiresOnSaturation();
-  base::RunLoop().RunUntilIdle();
-  const gfx::Rect context_rect = views::Widget::GetWidgetForNativeWindow(
-                                     browser()->window()->GetNativeWindow())
-                                     ->GetClientAreaBoundsInScreen();
-
-  // Trigger positioning via first emission of text.
-  EXPECT_TRUE(EmitTranscribedText(&surface, "Test text"));
-  EXPECT_TRUE(IsWidgetVisible());
-
-  // Reuses the positioning logic from
-  // `CaptionBubbleControllerViewsTest::BubblePositioning`.
-  const int bubble_width = 536;
-  const int bubble_y_offset = 20;
-  const gfx::Insets bubble_margins(6);
-  const gfx::Rect bubble_bounds = bubble_controller()
-                                      ->GetCaptionWidgetForTesting()
-                                      ->GetWindowBoundsInScreen();
-
-  // There may be some rounding errors as we do floating point math with ints.
-  // Check that points are almost the same.
-  EXPECT_LT(
-      abs(bubble_bounds.CenterPoint().x() - context_rect.CenterPoint().x()), 2);
-  EXPECT_EQ(bubble_bounds.bottom(), context_rect.bottom() - bubble_y_offset);
-  EXPECT_EQ(bubble()->GetBoundsInScreen().width(), bubble_width);
-  EXPECT_EQ(bubble()->margins(), bubble_margins);
-}
-
-// Test that an error is shown when reported by the surface.
-IN_PROC_BROWSER_TEST_F(LiveCaptionUiRemoteDriverTest, DisplaysError) {
-  MockSurface surface;
-  NewUiDriverForSurface(&surface, /*stub_bounds=*/true);
-
-  // Bubble should be shown initially.
-  EXPECT_TRUE(EmitTranscribedText(&surface, "Test text"));
-  EXPECT_TRUE(IsWidgetVisible());
-  ASSERT_NE(nullptr, bubble_controller());
-  EXPECT_FALSE(bubble_controller()->IsGenericErrorMessageVisibleForTesting());
-
-  // Error should trigger error message.
-  surface.remote_recognizer_client()->OnSpeechRecognitionError();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(IsWidgetVisible());
-  ASSERT_NE(nullptr, bubble_controller());
-  EXPECT_TRUE(bubble_controller()->IsGenericErrorMessageVisibleForTesting());
-
-  // Receiving new text during an error should cause the error to disappear.
-  EXPECT_TRUE(EmitTranscribedText(&surface, "More test text"));
-  EXPECT_TRUE(IsWidgetVisible());
-  ASSERT_NE(nullptr, bubble_controller());
-  EXPECT_FALSE(bubble_controller()->IsGenericErrorMessageVisibleForTesting());
-}
-
-// Test that the bubble is hidden when a stream end is reported.
-IN_PROC_BROWSER_TEST_F(LiveCaptionUiRemoteDriverTest, StreamEnd) {
-  MockSurface surface;
-  NewUiDriverForSurface(&surface, /*stub_bounds=*/true);
-
-  // Emitting text should cause the bubble to appear.
-  EXPECT_TRUE(EmitTranscribedText(&surface, "Test text"));
-  EXPECT_TRUE(IsWidgetVisible());
-
-  // Send stream end signal.
-  surface.remote_recognizer_client()->OnSpeechRecognitionStopped();
-  base::RunLoop().RunUntilIdle();
-
-  // Bubble should have disappeared.
-  ASSERT_NE(nullptr, bubble_controller());
-  EXPECT_FALSE(IsWidgetVisible());
-}
-
-// Test that closing the bubble ends transcription until a navigation.
-IN_PROC_BROWSER_TEST_F(LiveCaptionUiRemoteDriverTest, CloseBubble) {
-  MockSurface surface_1, surface_2, surface_3;
-  auto* driver_1 = NewUiDriverForSurface(&surface_1, /*stub_bounds=*/true);
-  NewUiDriverForSurface(&surface_2, /*stub_bounds=*/false);
-  NewUiDriverForSurface(&surface_3, /*stub_bounds=*/false);
-
-  // Emitting text should cause the bubble to appear.
-  EXPECT_TRUE(EmitTranscribedText(&surface_1, "Test text"));
-  EXPECT_TRUE(IsWidgetVisible());
-
-  // Close the bubble.
-  ASSERT_NE(nullptr, bubble());
-  ClickButton(bubble()->GetCloseButtonForTesting());
-  EXPECT_FALSE(IsWidgetVisible());
-
-  // Emitting further text should fail.
-  EXPECT_FALSE(EmitTranscribedText(&surface_1, "More test text"));
-  EXPECT_FALSE(IsWidgetVisible());
-
-  // Emitting text from a different stream in the same closed session should
-  // also fail.
-  EXPECT_FALSE(EmitTranscribedText(&surface_2, "Surface 2 text"));
-  EXPECT_FALSE(IsWidgetVisible());
-
-  // Emulate a navigation (i.e. session end).
-  driver_1->OnSessionEnded();
-
-  // Text from a new page should not cause the bubble to reappear because
-  // closing the bubble disables the feature.
-  EXPECT_FALSE(EmitTranscribedText(&surface_3, "New page text"));
-  EXPECT_FALSE(IsWidgetVisible());
-}
-
-// Test that the back to tab message is delivered.
-IN_PROC_BROWSER_TEST_F(LiveCaptionUiRemoteDriverTest, BackToTab) {
-  MockSurface surface_1;
-  MockSurface surface_2;
-  NewUiDriverForSurface(&surface_1, /*stub_bounds=*/true);
-  NewUiDriverForSurface(&surface_2, /*stub_bounds=*/false);
-
-  // We expect these activate calls when we toggle back and forth.
-  EXPECT_CALL(surface_1, Activate()).Times(2).RetiresOnSaturation();
-  EXPECT_CALL(surface_2, Activate()).RetiresOnSaturation();
-
-  // Emit text from surface 1 to activate its model. Then use the "back to tab"
-  // UI.
-  EXPECT_TRUE(EmitTranscribedText(&surface_1, "Surface 1 text"));
-  ClickButton(bubble()->GetBackToTabButtonForTesting());
-
-  // Emit text from surface 2 to activate its model.
-  EXPECT_TRUE(EmitTranscribedText(&surface_2, "Surface 2 text"));
-  ClickButton(bubble()->GetBackToTabButtonForTesting());
-
-  // Emit text from surface 1 again to reactivate its model.
-  EXPECT_TRUE(EmitTranscribedText(&surface_1, "More surface 1 text"));
-  ClickButton(bubble()->GetBackToTabButtonForTesting());
-
-  // Surface 1 should be activated twice, and surface 2 once.
-  base::RunLoop().RunUntilIdle();
-}
-
-}  // namespace
-}  // namespace ash
diff --git a/chrome/browser/ash/crosapi/BUILD.gn b/chrome/browser/ash/crosapi/BUILD.gn
index a28b88a..d5559c4 100644
--- a/chrome/browser/ash/crosapi/BUILD.gn
+++ b/chrome/browser/ash/crosapi/BUILD.gn
@@ -180,8 +180,6 @@
     "remoting_ash.h",
     "resource_manager_ash.cc",
     "resource_manager_ash.h",
-    "rootfs_lacros_loader.cc",
-    "rootfs_lacros_loader.h",
     "screen_ai_downloader_ash.cc",
     "screen_ai_downloader_ash.h",
     "screen_manager_ash.cc",
@@ -604,7 +602,6 @@
 
   sources = [
     "audio_service_ash_unittest.cc",
-    "browser_loader_unittest.cc",
     "browser_util_unittest.cc",
     "cec_private_ash_unittest.cc",
     "cert_provisioning_ash_unittest.cc",
@@ -633,7 +630,6 @@
     "parent_access_ash_unittest.cc",
     "payment_app_instance_ash_unittest.cc",
     "primary_profile_creation_waiter_unittest.cc",
-    "rootfs_lacros_loader_unittest.cc",
     "screen_ai_downloader_ash_unittest.cc",
     "search_controller_ash_unittest.cc",
     "stateful_lacros_loader_unittest.cc",
diff --git a/chrome/browser/ash/crosapi/browser_loader.cc b/chrome/browser/ash/crosapi/browser_loader.cc
index 321028f..8ae9df0 100644
--- a/chrome/browser/ash/crosapi/browser_loader.cc
+++ b/chrome/browser/ash/crosapi/browser_loader.cc
@@ -14,25 +14,17 @@
 #include "base/files/file_util.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
-#include "base/metrics/histogram_functions.h"
 #include "base/ranges/algorithm.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/task/task_traits.h"
-#include "base/task/thread_pool.h"
 #include "base/values.h"
 #include "chrome/browser/ash/crosapi/lacros_selection_loader.h"
 #include "chrome/browser/ash/crosapi/lacros_selection_loader_factory.h"
-#include "chrome/browser/ash/crosapi/rootfs_lacros_loader.h"
 #include "chrome/browser/ash/crosapi/stateful_lacros_loader.h"
-#include "chrome/browser/browser_process.h"
 #include "chromeos/ash/components/cryptohome/system_salt_getter.h"
 #include "components/component_updater/ash/component_manager_ash.h"
 
 namespace crosapi {
 
 namespace {
-// There are 2 lacros selections, rootfs lacros and stateful lacros.
-constexpr size_t kLacrosSelectionTypes = 2;
 
 class LacrosSelectionLoaderFactoryImpl : public LacrosSelectionLoaderFactory {
  public:
@@ -47,10 +39,6 @@
 
   ~LacrosSelectionLoaderFactoryImpl() override = default;
 
-  std::unique_ptr<LacrosSelectionLoader> CreateRootfsLacrosLoader() override {
-    return std::make_unique<RootfsLacrosLoader>();
-  }
-
   std::unique_ptr<LacrosSelectionLoader> CreateStatefulLacrosLoader() override {
     return std::make_unique<StatefulLacrosLoader>(component_manager_);
   }
@@ -59,10 +47,6 @@
   scoped_refptr<component_updater::ComponentManagerAsh> component_manager_;
 };
 
-bool IsUnloading(LacrosSelectionLoader* loader) {
-  return loader && loader->IsUnloading();
-}
-
 }  // namespace
 
 BrowserLoader::BrowserLoader(
@@ -75,362 +59,22 @@
 
 BrowserLoader::~BrowserLoader() = default;
 
-BrowserLoader::LacrosSelectionVersion::LacrosSelectionVersion(
-    LacrosSelection selection,
-    base::Version version)
-    : selection(selection), version(std::move(version)) {
-  CHECK_NE(selection, LacrosSelection::kDeployedLocally);
-}
-
-// static.
-bool BrowserLoader::WillLoadStatefulComponentBuilds() {
-  // If the lacros chrome path is specified BrowserLoader will always attempt to
-  // load lacros from this path and component manager builds are ignored.
-  const base::FilePath lacros_chrome_path =
-      base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
-          ash::switches::kLacrosChromePath);
-  if (!lacros_chrome_path.empty())
-    return false;
-
-  // If the lacros selection is forced by the user or by policy to rootfs it
-  // will always be loaded and stateful component manager builds are ignored.
-  std::optional<ash::standalone_browser::LacrosSelection> lacros_selection =
-      ash::standalone_browser::DetermineLacrosSelection();
-  if (lacros_selection == ash::standalone_browser::LacrosSelection::kRootfs) {
-    return false;
-  }
-
-  return true;
-}
-
-void BrowserLoader::SelectRootfsLacros(LoadCompletionCallback callback,
-                                       LacrosSelectionSource source) {
-  CHECK(rootfs_lacros_loader_);
-
-  LOG(WARNING) << "rootfs lacros is selected by " << source;
-
-  rootfs_lacros_loader_->Load(
-      base::BindOnce(&BrowserLoader::OnLoadComplete, weak_factory_.GetWeakPtr(),
-                     std::move(callback), LacrosSelection::kRootfs),
-      source == LacrosSelectionSource::kForced);
-}
-
-void BrowserLoader::SelectStatefulLacros(LoadCompletionCallback callback,
-                                         LacrosSelectionSource source) {
-  CHECK(stateful_lacros_loader_);
-
-  LOG(WARNING) << "stateful lacros is selected by " << source;
-
-  stateful_lacros_loader_->Load(
-      base::BindOnce(&BrowserLoader::OnLoadComplete, weak_factory_.GetWeakPtr(),
-                     std::move(callback), LacrosSelection::kStateful),
-      source == LacrosSelectionSource::kForced);
-
-  // Unmount the rootfs lacros-chrome when using stateful lacros-chrome.
-  // This will keep stateful lacros-chrome only mounted and not hold the rootfs
-  // lacros-chrome mount until an `Unload`.
-  if (rootfs_lacros_loader_) {
-    rootfs_lacros_loader_->Unload(
-        base::BindOnce(&BrowserLoader::OnUnloadCompleted,
-                       weak_factory_.GetWeakPtr(), LacrosSelection::kRootfs));
-  }
-}
-
-void BrowserLoader::Load(LoadCompletionCallback callback) {
-  // Load should NOT be called after Unload is requested to BrowserLoader.
-  CHECK(!is_unload_requested_);
-
-  // If either of rootfs or stateful lacros loader is still unloading, wait
-  // until the unload completion.
-  if (IsUnloading(rootfs_lacros_loader_.get()) ||
-      IsUnloading(stateful_lacros_loader_.get())) {
-    LOG(WARNING) << "Wait load until unload completes";
-    callback_on_unload_completion_ =
-        base::BindOnce(&BrowserLoader::LoadNow, weak_factory_.GetWeakPtr(),
-                       std::move(callback));
-    return;
-  }
-
-  LoadNow(std::move(callback));
-}
-
-void BrowserLoader::LoadNow(LoadCompletionCallback callback) {
-  // Reset lacros selection loaders since it may be already initialized one if
-  // this is reloading.
-  // TODO(elkurin): We should call Unload before reloading if these loaders
-  // exist, then we can remove `reset` here.
-  rootfs_lacros_loader_.reset();
-  stateful_lacros_loader_.reset();
-
-  lacros_start_load_time_ = base::TimeTicks::Now();
-  // TODO(crbug.com/40689435): Remove non-error logging from this class.
-  LOG(WARNING) << "Starting lacros component load.";
-
-  // If the user has specified a path for the lacros-chrome binary, use that
-  // rather than component manager.
-  base::FilePath lacros_chrome_path =
-      base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
-          ash::switches::kLacrosChromePath);
-  if (!lacros_chrome_path.empty()) {
-    OnLoadComplete(std::move(callback), LacrosSelection::kDeployedLocally,
-                   base::Version(), lacros_chrome_path);
-    return;
-  }
-
-  // If the LacrosSelection policy or the user have specified to force using
-  // stateful or rootfs lacros-chrome binary, force the selection. Otherwise,
-  // load the newest available binary.
-  if (std::optional<ash::standalone_browser::LacrosSelection> lacros_selection =
-          ash::standalone_browser::DetermineLacrosSelection()) {
-    // TODO(crbug.com/40213424): We should check the version compatibility here,
-    // too.
-    switch (lacros_selection.value()) {
-      case ash::standalone_browser::LacrosSelection::kRootfs:
-        rootfs_lacros_loader_ = factory_->CreateRootfsLacrosLoader();
-        SelectRootfsLacros(std::move(callback), LacrosSelectionSource::kForced);
-        return;
-      case ash::standalone_browser::LacrosSelection::kStateful:
-        stateful_lacros_loader_ = factory_->CreateStatefulLacrosLoader();
-        SelectStatefulLacros(std::move(callback),
-                             LacrosSelectionSource::kForced);
-        return;
-      case ash::standalone_browser::LacrosSelection::kDeployedLocally:
-        NOTREACHED();
-    }
-  }
-
-  rootfs_lacros_loader_ = factory_->CreateRootfsLacrosLoader();
-  stateful_lacros_loader_ = factory_->CreateStatefulLacrosLoader();
-
-  // Proceed to load/mount the stateful lacros-chrome binary.
-  // In the case that the stateful lacros-chrome binary wasn't installed, this
-  // might take some time.
-  auto barrier_callback = base::BarrierCallback<LacrosSelectionVersion>(
-      kLacrosSelectionTypes,
-      base::BindOnce(&BrowserLoader::OnLoadVersions, weak_factory_.GetWeakPtr(),
-                     std::move(callback)));
-
-  rootfs_lacros_loader_->GetVersion(
-      base::BindOnce(&BrowserLoader::OnGetVersion, weak_factory_.GetWeakPtr(),
-                     LacrosSelection::kRootfs, barrier_callback));
-  stateful_lacros_loader_->GetVersion(
-      base::BindOnce(&BrowserLoader::OnGetVersion, weak_factory_.GetWeakPtr(),
-                     LacrosSelection::kStateful, barrier_callback));
-}
-
-void BrowserLoader::OnGetVersion(
-    LacrosSelection selection,
-    base::OnceCallback<void(LacrosSelectionVersion)> barrier_callback,
-    const base::Version& version) {
-  std::move(barrier_callback).Run(LacrosSelectionVersion(selection, version));
-}
-
-void BrowserLoader::OnLoadVersions(
-    LoadCompletionCallback callback,
-    std::vector<LacrosSelectionVersion> versions) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  CHECK_EQ(versions.size(), kLacrosSelectionTypes);
-
-  if (is_unload_requested_) {
-    LOG(WARNING) << "Unload is requested during collecting Lacros version.";
-    std::move(callback).Run(base::FilePath(), LacrosSelection::kStateful,
-                            base::Version());
-    return;
-  }
-
-  // Compare the rootfs vs stateful lacros-chrome binary versions.
-  // If the rootfs lacros-chrome is greater than lacros-chrome version,
-  // prioritize using the rootfs lacros-chrome. If the stateful lacros-chrome is
-  // not installed, let stateful lacros-chrome load in the background.
-  auto selected = base::ranges::max_element(
-      versions,
-      [](const LacrosSelectionVersion& lhs, const LacrosSelectionVersion& rhs) {
-        if (!lhs.version.IsValid()) {
-          return true;
-        }
-
-        if (!rhs.version.IsValid()) {
-          return false;
-        }
-
-        if (lhs.version != rhs.version) {
-          return lhs.version < rhs.version;
-        }
-
-        // If the versions are the same, stateful lacros-chrome should be
-        // prioritized, so considers LacrosSelectionVersion with kRootfs to be
-        // smaller. Note that this comparison only happens between kRootfs and
-        // kStateful.
-        return lhs.selection == LacrosSelection::kRootfs;
-      });
-
-  if (!selected->version.IsValid()) {
-    // Neither rootfs lacros nor stateful lacros are available.
-    // Returning an empty file path to notify error.
-    LOG(ERROR) << "No lacros is available";
-    std::move(callback).Run(base::FilePath(), LacrosSelection::kStateful,
-                            base::Version());
-    return;
-  }
-
-  // Selected lacros may be older than the one which was running in a previous
-  // sessions, accidentally. For experiment, now we intentionally ignore
-  // the case and forcibly load the selected one, which is the best we could do
-  // at this moment.
-  // TODO(crbug.com/40213424): Check the condition and report it via UMA stats.
-
-  switch (selected->selection) {
-    case LacrosSelection::kRootfs: {
-      SelectRootfsLacros(std::move(callback),
-                         LacrosSelectionSource::kCompatibilityCheck);
-      break;
-    }
-    case LacrosSelection::kStateful: {
-      SelectStatefulLacros(std::move(callback),
-                           LacrosSelectionSource::kCompatibilityCheck);
-      break;
-    }
-    case LacrosSelection::kDeployedLocally: {
-      NOTREACHED();
-    }
-  }
-}
-
 void BrowserLoader::Unload() {
-  is_unload_requested_ = true;
-
   // Can be called even if Lacros isn't enabled, to clean up the old install.
-  // Unmount the rootfs/stateful lacros-chrome if it was mounted.
-  if (rootfs_lacros_loader_) {
-    rootfs_lacros_loader_->Unload(
-        base::BindOnce(&BrowserLoader::OnUnloadCompleted,
-                       weak_factory_.GetWeakPtr(), LacrosSelection::kRootfs));
-  }
-
+  // Unmount the stateful lacros-chrome if it was mounted.
   if (stateful_lacros_loader_) {
-    stateful_lacros_loader_->Unload(
-        base::BindOnce(&BrowserLoader::OnUnloadCompleted,
-                       weak_factory_.GetWeakPtr(), LacrosSelection::kStateful));
+    stateful_lacros_loader_->Unload(base::BindOnce(
+        &BrowserLoader::OnUnloadCompleted, weak_factory_.GetWeakPtr()));
   }
 }
 
-void BrowserLoader::OnUnloadCompleted(LacrosSelection selection) {
+void BrowserLoader::OnUnloadCompleted() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  switch (selection) {
-    case LacrosSelection::kRootfs:
-      CHECK(rootfs_lacros_loader_->IsUnloaded());
-      rootfs_lacros_loader_.reset();
-      break;
-    case LacrosSelection::kStateful:
-      CHECK(stateful_lacros_loader_->IsUnloaded());
-      stateful_lacros_loader_.reset();
-      break;
-    case LacrosSelection::kDeployedLocally:
-      NOTREACHED();
-  }
-
-  // If either of rootfs or stateful lacros loader is still in the process of
-  // unload, wait running completion callback.
-  if (IsUnloading(rootfs_lacros_loader_.get()) ||
-      IsUnloading(stateful_lacros_loader_.get())) {
-    return;
-  }
-
-  // If both of the rootfs and stateful lacros load completed unloading, run the
-  // stored callback if exists.
+  CHECK(stateful_lacros_loader_->IsUnloaded());
+  stateful_lacros_loader_.reset();
   if (callback_on_unload_completion_) {
     std::move(callback_on_unload_completion_).Run();
   }
 }
 
-base::FilePath DetermineLacrosBinaryPath(const base::FilePath& path) {
-  // Interpret path as directory. If that fails, interpret it as the executable.
-  base::FilePath expanded =
-      path.Append(LacrosSelectionLoader::kLacrosChromeBinary);
-  if (base::PathExists(expanded)) {
-    return expanded;
-  }
-  if (base::PathExists(path)) {
-    return path;
-  }
-  return {};
-}
-
-void BrowserLoader::OnLoadComplete(LoadCompletionCallback callback,
-                                   LacrosSelection selection,
-                                   base::Version version,
-                                   const base::FilePath& path) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (is_unload_requested_) {
-    LOG(WARNING) << "Unload is requested during loading.";
-    std::move(callback).Run(base::FilePath(), LacrosSelection::kStateful,
-                            base::Version());
-    return;
-  }
-
-  // Bail out on empty `path` which implies there was an error on loading
-  // lacros.
-  if (path.empty()) {
-    std::move(callback).Run(base::FilePath(), selection, base::Version());
-    return;
-  }
-
-  // Fail early if the chrome binary still doesn't exist, such that
-  // (1) we end up with an error message in Ash's log, and
-  // (2) BrowserManager doesn't endlessly try to spawn Lacros.
-  // For example, in the past there have been issues with mounting rootfs Lacros
-  // that resulted in /run/lacros being empty at this point.
-  base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE, {base::MayBlock()},
-      base::BindOnce(&DetermineLacrosBinaryPath, path),
-      base::BindOnce(&BrowserLoader::FinishOnLoadComplete,
-                     weak_factory_.GetWeakPtr(), std::move(callback), path,
-                     selection, std::move(version)));
-}
-
-void BrowserLoader::FinishOnLoadComplete(LoadCompletionCallback callback,
-                                         const base::FilePath& path,
-                                         LacrosSelection selection,
-                                         base::Version version,
-                                         const base::FilePath& lacros_binary) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (is_unload_requested_) {
-    LOG(WARNING) << "Unload is requested during determining lacros path.";
-    std::move(callback).Run(base::FilePath(), LacrosSelection::kStateful,
-                            base::Version());
-    return;
-  }
-
-  if (lacros_binary.empty()) {
-    LOG(ERROR) << "Failed to find binary at " << path;
-    std::move(callback).Run(base::FilePath(), selection, base::Version());
-    return;
-  }
-
-  base::UmaHistogramMediumTimes(
-      "ChromeOS.Lacros.LoadTime",
-      base::TimeTicks::Now() - lacros_start_load_time_);
-
-  // Log the path on success.
-  LOG(WARNING) << "Loaded lacros image with binary " << lacros_binary;
-  std::move(callback).Run(lacros_binary, selection, std::move(version));
-}
-
-std::ostream& operator<<(std::ostream& ostream,
-                         BrowserLoader::LacrosSelectionSource source) {
-  switch (source) {
-    case BrowserLoader::LacrosSelectionSource::kUnknown:
-      return ostream << "Unknown";
-    case BrowserLoader::LacrosSelectionSource::kCompatibilityCheck:
-      return ostream << "CompatibilityCheck";
-    case BrowserLoader::LacrosSelectionSource::kForced:
-      return ostream << "Forced";
-    case BrowserLoader::LacrosSelectionSource::kDeployedPath:
-      return ostream << "DeployedPath";
-  }
-}
-
 }  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/browser_loader.h b/chrome/browser/ash/crosapi/browser_loader.h
index ee90a2e..ee762dd3 100644
--- a/chrome/browser/ash/crosapi/browser_loader.h
+++ b/chrome/browser/ash/crosapi/browser_loader.h
@@ -44,162 +44,24 @@
 
   virtual ~BrowserLoader();
 
-  // Returns true if the browser loader will try to load stateful lacros-chrome
-  // builds from the component manager. This may return false if the user
-  // specifies the lacros-chrome binary on the command line or the user has
-  // forced the lacros selection to rootfs.
-  // If this returns false subsequent loads of lacros-chrome will never load
-  // a newer lacros-chrome version and update checking can be skipped.
-  static bool WillLoadStatefulComponentBuilds();
-
-  struct LacrosSelectionVersion {
-    LacrosSelectionVersion(LacrosSelection selection, base::Version version);
-
-    // LacrosSelection::kRootfs or kStateful should be set here, not
-    // kDeployedLocally.
-    LacrosSelection selection;
-
-    base::Version version;
-  };
-
-  // Indicates how lacros is selected.
-  enum class LacrosSelectionSource {
-    kUnknown,
-
-    // Selected by comparing the version to choose newer one or either of the
-    // lacros selection is not available.
-    kCompatibilityCheck,
-
-    // Forced by the selection policy or about:flags. See
-    // browser_util::DetermineLacrosSelection for the detailed condition when
-    // the lacros selection is forced.
-    kForced,
-
-    // Forced by registered lacros-chrome path.
-    kDeployedPath,
-  };
-
-  // Starts to load lacros-chrome binary or the rootfs lacros-chrome binary.
-  // `callback` is called on completion with the path to the lacros-chrome on
-  // success, or an empty filepath on failure, and the loaded lacros selection
-  // which is either 'rootfs' or 'stateful'.
-  //
-  // If Load is called during Load, the previous load requests are discarded
-  // and immediately begin loading. LoadCompletionCallback for the previous
-  // request will NOT be called in this scenario.
-  // TODO(elkurin): We should run Unload for previous LacroSelectionLoader.
-  //
-  // Load should NOT be called once Unlaod is requested. Note that per-
-  // LacrosSelectionLoader unload that is requested inside BrowserManager class
-  // may run before or while calling Load.
-  // If Load is called during per-loader unload, Load request will be processed
-  // after all ongoing per-loader unload requests complete that are at most 2.
-  // Currently, this happens only when selecting stateful lacros-chrome and
-  // unloading rootfs.
-  using LoadCompletionCallback = base::OnceCallback<
-      void(const base::FilePath&, LacrosSelection, base::Version)>;
-  virtual void Load(LoadCompletionCallback callback);
-
-  // Starts to unload lacros-chrome binary.
-  // Once Unload is called, BrowserLoader should NOT accept Load requests.
-  //
-  // If Unload is called during Load, stops loading procedure on main thread and
-  // requests LacrosSelectionLoaders to unload. Each loader will start unloading
-  // after the current task completed.
-  //
-  // If Unload is called during Unload, no need to unload again so the
-  // coming unload request will be ignored.
   virtual void Unload();
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(BrowserLoaderTest,
-                           OnLoadSelectionQuicklyChooseRootfs);
-  FRIEND_TEST_ALL_PREFIXES(BrowserLoaderTest,
-                           OnLoadVersionSelectionNeitherIsAvailable);
-  FRIEND_TEST_ALL_PREFIXES(BrowserLoaderTest,
-                           OnLoadVersionSelectionStatefulIsUnavailable);
-  FRIEND_TEST_ALL_PREFIXES(BrowserLoaderTest,
-                           OnLoadVersionSelectionRootfsIsUnavailable);
-  FRIEND_TEST_ALL_PREFIXES(BrowserLoaderTest,
-                           OnLoadVersionSelectionRootfsIsNewer);
-  FRIEND_TEST_ALL_PREFIXES(BrowserLoaderTest,
-                           OnLoadVersionSelectionRootfsIsOlder);
-  FRIEND_TEST_ALL_PREFIXES(BrowserLoaderTest,
-                           OnLoadVersionSelectionSameVersions);
-  FRIEND_TEST_ALL_PREFIXES(BrowserLoaderTest, OnLoadSelectionPolicyIsRootfs);
-  FRIEND_TEST_ALL_PREFIXES(
-      BrowserLoaderTest,
-      OnLoadSelectionPolicyIsUserChoiceAndCommandLineIsRootfs);
-  FRIEND_TEST_ALL_PREFIXES(
-      BrowserLoaderTest,
-      OnLoadSelectionPolicyIsUserChoiceAndCommandLineIsStateful);
-  FRIEND_TEST_ALL_PREFIXES(BrowserLoaderTest,
-                           OnLoadLacrosBinarySpecifiedBySwitch);
-  FRIEND_TEST_ALL_PREFIXES(BrowserLoaderTest,
-                           OnLoadLacrosDirectorySpecifiedBySwitch);
-  FRIEND_TEST_ALL_PREFIXES(BrowserLoaderTest, LoadWhileUnloading);
+  void OnUnloadCompleted();
 
-  // Starts loading now/
-  void LoadNow(LoadCompletionCallback callback);
-
-  // `source` indicates why rootfs/stateful is selected. `source` is only used
-  // for logging.
-  void SelectRootfsLacros(LoadCompletionCallback callback,
-                          LacrosSelectionSource source);
-  void SelectStatefulLacros(LoadCompletionCallback callback,
-                            LacrosSelectionSource source);
-
-  // Called on GetVersion for each rootfs and stateful lacros loader.
-  void OnGetVersion(
-      LacrosSelection selection,
-      base::OnceCallback<void(LacrosSelectionVersion)> barrier_callback,
-      const base::Version& version);
-
-  // Called to determine which lacros to load based on version (rootfs vs
-  // stateful).
-  // `versions` consists of 2 elements, one for rootfs lacros, one for stateful
-  // lacros. The order is not specified.
-  void OnLoadVersions(LoadCompletionCallback callback,
-                      std::vector<LacrosSelectionVersion> versions);
-
-  // Called on the completion of loading.
-  void OnLoadComplete(LoadCompletionCallback callback,
-                      LacrosSelection selection,
-                      base::Version version,
-                      const base::FilePath& path);
-  void FinishOnLoadComplete(LoadCompletionCallback callback,
-                            const base::FilePath& path,
-                            LacrosSelection selection,
-                            base::Version version,
-                            const base::FilePath& lacros_binary);
-
-  // Called on unload completed.
-  void OnUnloadCompleted(LacrosSelection selection);
-
-  // Loader for rootfs lacros and stateful lacros. Loader objects are
-  // constructed on start loading and reset on unload completion or on reload.
-  std::unique_ptr<LacrosSelectionLoader> rootfs_lacros_loader_;
   std::unique_ptr<LacrosSelectionLoader> stateful_lacros_loader_;
 
   std::unique_ptr<LacrosSelectionLoaderFactory> factory_;
 
-  // Time when the lacros component was loaded.
-  base::TimeTicks lacros_start_load_time_;
-
-  // Called when Unload is completed for both rootfs and stateful lacros.
+  // Called when Unload is completed for stateful lacros.
   base::OnceClosure callback_on_unload_completion_;
 
-  // Set to true if BrowserLoader::Unload is requested.
-  bool is_unload_requested_ = false;
-
   // Used for DCHECKs to ensure method calls executed in the correct thread.
   SEQUENCE_CHECKER(sequence_checker_);
 
   base::WeakPtrFactory<BrowserLoader> weak_factory_{this};
 };
 
-std::ostream& operator<<(std::ostream&, BrowserLoader::LacrosSelectionSource);
-
 }  // namespace crosapi
 
 #endif  // CHROME_BROWSER_ASH_CROSAPI_BROWSER_LOADER_H_
diff --git a/chrome/browser/ash/crosapi/browser_loader_unittest.cc b/chrome/browser/ash/crosapi/browser_loader_unittest.cc
deleted file mode 100644
index e6bf022..0000000
--- a/chrome/browser/ash/crosapi/browser_loader_unittest.cc
+++ /dev/null
@@ -1,505 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/crosapi/browser_loader.h"
-
-#include "ash/constants/ash_switches.h"
-#include "base/auto_reset.h"
-#include "base/check_op.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/functional/callback.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/task/single_thread_task_runner.h"
-#include "base/test/bind.h"
-#include "base/test/scoped_command_line.h"
-#include "base/test/test_future.h"
-#include "base/version.h"
-#include "chrome/browser/ash/crosapi/lacros_selection_loader.h"
-#include "chrome/browser/ash/crosapi/lacros_selection_loader_factory.h"
-#include "chromeos/ash/components/standalone_browser/lacros_selection.h"
-#include "components/component_updater/ash/component_manager_ash.h"
-#include "components/policy/core/common/policy_map.h"
-#include "components/policy/policy_constants.h"
-#include "content/public/test/browser_task_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace crosapi {
-namespace {
-
-// Call the registered callback when Unload is started.
-class UnloadObserver {
- public:
-  UnloadObserver() = default;
-  UnloadObserver(const UnloadObserver&) = delete;
-  UnloadObserver& operator=(const UnloadObserver&) = delete;
-  ~UnloadObserver() = default;
-
-  void OnUnloadStarted() {
-    if (callback_) {
-      std::move(callback_).Run();
-    }
-  }
-
-  void SetCallback(base::OnceClosure cb) { callback_ = std::move(cb); }
-
- private:
-  base::OnceClosure callback_;
-};
-
-// This fake class is used to test BrowserLoader who is responsible for deciding
-// which lacros selection to use.
-// This class does not load nor get actual version. Such features are tested in
-// RootfsLacrosLoaderTest for rootfs and StatefulLacrosLoaderTest for stateful.
-class FakeLacrosSelectionLoader : public LacrosSelectionLoader {
- public:
-  FakeLacrosSelectionLoader(
-      const base::Version& version,
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-      : version_(version), task_runner_(task_runner) {
-    // Create dummy chrome binary path.
-    CHECK(temp_dir_.CreateUniqueTempDir());
-    chrome_path_ = temp_dir_.GetPath().Append(kLacrosChromeBinary);
-    base::WriteFile(chrome_path_, "I am chrome binary.");
-  }
-
-  FakeLacrosSelectionLoader(const FakeLacrosSelectionLoader&) = delete;
-  FakeLacrosSelectionLoader& operator=(const FakeLacrosSelectionLoader&) =
-      delete;
-
-  ~FakeLacrosSelectionLoader() override = default;
-
-  void Load(LoadCompletionCallback callback, bool forced) override {
-    // Load should NOT be called when it's unloaded or busy.
-    CHECK(!is_unloading_ && !is_unloaded_);
-
-    task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&FakeLacrosSelectionLoader::OnLoadCompleted,
-                                  base::Unretained(this), std::move(callback)));
-  }
-
-  void Unload(base::OnceClosure callback) override {
-    is_unloading_ = true;
-    unload_observer_.OnUnloadStarted();
-
-    task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&FakeLacrosSelectionLoader::OnUnloadCompleted,
-                                  base::Unretained(this), std::move(callback)));
-  }
-
-  bool IsUnloading() const override { return is_unloading_; }
-
-  bool IsUnloaded() const override { return is_unloaded_; }
-
-  void GetVersion(
-      base::OnceCallback<void(const base::Version&)> callback) override {
-    task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&FakeLacrosSelectionLoader::OnGetVersionCompleted,
-                       base::Unretained(this), std::move(callback)));
-  }
-
-  void SetCallbackOnUnload(base::OnceClosure cb) {
-    unload_observer_.SetCallback(std::move(cb));
-  }
-
- private:
-  void OnLoadCompleted(LoadCompletionCallback callback) {
-    if (!callback) {
-      return;
-    }
-
-    // If version is invalid, returns empty path. Otherwise fill in with some
-    // path. Whether path is empty or not is used as a condition to check
-    // whether error has occurred during loading.
-    const base::FilePath path =
-        version_.IsValid() ? temp_dir_.GetPath() : base::FilePath();
-    std::move(callback).Run(version_, path);
-  }
-
-  void OnUnloadCompleted(base::OnceClosure callback) {
-    is_unloading_ = false;
-    is_unloaded_ = true;
-    if (callback) {
-      std::move(callback).Run();
-    }
-  }
-
-  void OnGetVersionCompleted(
-      base::OnceCallback<void(const base::Version&)> callback) {
-    std::move(callback).Run(version_);
-  }
-
-  const base::Version version_;
-  base::ScopedTempDir temp_dir_;
-  base::FilePath chrome_path_;
-  // `task_runner_` to run Load/Unload/GetVersion task as asynchronous
-  // operations.
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-  UnloadObserver unload_observer_;
-
-  bool is_unloaded_ = false;
-  bool is_unloading_ = false;
-};
-
-class FakeLacrosSelectionLoaderFactory : public LacrosSelectionLoaderFactory {
- public:
-  FakeLacrosSelectionLoaderFactory(
-      const base::Version& rootfs_version,
-      const base::Version& stateful_version,
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-      : rootfs_version_(rootfs_version),
-        stateful_version_(stateful_version),
-        task_runner_(task_runner) {}
-
-  FakeLacrosSelectionLoaderFactory(const FakeLacrosSelectionLoaderFactory&) =
-      delete;
-  FakeLacrosSelectionLoaderFactory& operator=(
-      const FakeLacrosSelectionLoaderFactory&) = delete;
-
-  ~FakeLacrosSelectionLoaderFactory() override = default;
-
-  std::unique_ptr<LacrosSelectionLoader> CreateRootfsLacrosLoader() override {
-    return std::make_unique<FakeLacrosSelectionLoader>(rootfs_version_,
-                                                       task_runner_);
-  }
-
-  std::unique_ptr<LacrosSelectionLoader> CreateStatefulLacrosLoader() override {
-    return std::make_unique<FakeLacrosSelectionLoader>(stateful_version_,
-                                                       task_runner_);
-  }
-
- private:
-  // These versions will be set on initializing lacros selection loaders.
-  const base::Version rootfs_version_ = base::Version();
-  const base::Version stateful_version_ = base::Version();
-
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-};
-
-// This implementation of RAII for LacrosSelection is to make it easy reset
-// the state between runs.
-class ScopedLacrosSelectionCache {
- public:
-  explicit ScopedLacrosSelectionCache(
-      ash::standalone_browser::LacrosSelectionPolicy lacros_selection) {
-    SetLacrosSelection(lacros_selection);
-  }
-  ScopedLacrosSelectionCache(const ScopedLacrosSelectionCache&) = delete;
-  ScopedLacrosSelectionCache& operator=(const ScopedLacrosSelectionCache&) =
-      delete;
-  ~ScopedLacrosSelectionCache() {
-    ash::standalone_browser::ClearLacrosSelectionCacheForTest();
-  }
-
- private:
-  void SetLacrosSelection(
-      ash::standalone_browser::LacrosSelectionPolicy lacros_selection) {
-    policy::PolicyMap policy;
-    policy.Set(policy::key::kLacrosSelection, policy::POLICY_LEVEL_MANDATORY,
-               policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
-               base::Value(GetLacrosSelectionPolicyName(lacros_selection)),
-               /*external_data_fetcher=*/nullptr);
-    ash::standalone_browser::CacheLacrosSelection(policy);
-  }
-};
-
-}  // namespace
-
-class BrowserLoaderTest : public testing::Test {
- public:
-  BrowserLoaderTest() {
-    EXPECT_TRUE(BrowserLoader::WillLoadStatefulComponentBuilds());
-  }
-
- protected:
-  BrowserLoader CreateBrowserLoaderWithFakeSelectionLoaders(
-      const base::Version& rootfs_lacros_version,
-      const base::Version& stateful_lacros_version) {
-    return BrowserLoader(std::make_unique<FakeLacrosSelectionLoaderFactory>(
-        rootfs_lacros_version, stateful_lacros_version,
-        task_environment_.GetMainThreadTaskRunner()));
-  }
-
-  void WaitForTaskComplete() { task_environment_.RunUntilIdle(); }
-
- private:
-  content::BrowserTaskEnvironment task_environment_;
-};
-
-TEST_F(BrowserLoaderTest, OnLoadVersionSelectionNeitherIsAvailable) {
-  // If both stateful and rootfs lacros-chrome version is invalid, the chrome
-  // path should be empty.
-  const base::Version rootfs_lacros_version = base::Version();
-  const base::Version stateful_lacros_version = base::Version();
-  auto browser_loader = CreateBrowserLoaderWithFakeSelectionLoaders(
-      rootfs_lacros_version, stateful_lacros_version);
-
-  base::test::TestFuture<const base::FilePath&, LacrosSelection, base::Version>
-      future;
-  browser_loader.Load(future.GetCallback());
-  EXPECT_TRUE(future.Get<0>().empty());
-}
-
-TEST_F(BrowserLoaderTest, OnLoadVersionSelectionStatefulIsUnavailable) {
-  // Pass invalid `base::Version` to stateful lacros-chrome and set valid
-  // version to rootfs lacros-chrome.
-  const base::Version rootfs_lacros_version = base::Version("2.0.0");
-  const base::Version stateful_lacros_version = base::Version();
-  auto browser_loader = CreateBrowserLoaderWithFakeSelectionLoaders(
-      rootfs_lacros_version, stateful_lacros_version);
-
-  base::test::TestFuture<const base::FilePath&, LacrosSelection, base::Version>
-      future;
-  browser_loader.Load(future.GetCallback());
-  EXPECT_EQ(LacrosSelection::kRootfs, future.Get<1>());
-  EXPECT_EQ(rootfs_lacros_version, future.Get<2>());
-}
-
-TEST_F(BrowserLoaderTest, OnLoadVersionSelectionRootfsIsUnavailable) {
-  // Pass invalid `base::Version` as a rootfs lacros-chrome version.
-  const base::Version rootfs_lacros_version = base::Version();
-  const base::Version stateful_lacros_version = base::Version("1.0.0");
-  auto browser_loader = CreateBrowserLoaderWithFakeSelectionLoaders(
-      rootfs_lacros_version, stateful_lacros_version);
-
-  base::test::TestFuture<const base::FilePath&, LacrosSelection, base::Version>
-      future;
-  browser_loader.Load(future.GetCallback());
-  EXPECT_EQ(LacrosSelection::kStateful, future.Get<1>());
-  EXPECT_EQ(stateful_lacros_version, future.Get<2>());
-}
-
-TEST_F(BrowserLoaderTest, OnLoadVersionSelectionRootfsIsNewer) {
-  // Use rootfs when a stateful lacros-chrome version is older.
-  const base::Version rootfs_lacros_version = base::Version("2.0.0");
-  const base::Version stateful_lacros_version = base::Version("1.0.0");
-  auto browser_loader = CreateBrowserLoaderWithFakeSelectionLoaders(
-      rootfs_lacros_version, stateful_lacros_version);
-
-  base::test::TestFuture<const base::FilePath&, LacrosSelection, base::Version>
-      future;
-  browser_loader.Load(future.GetCallback());
-  EXPECT_EQ(LacrosSelection::kRootfs, future.Get<1>());
-  EXPECT_EQ(rootfs_lacros_version, future.Get<2>());
-}
-
-TEST_F(BrowserLoaderTest, OnLoadVersionSelectionRootfsIsOlder) {
-  // Use stateful when a rootfs lacros-chrome version is older.
-  const base::Version rootfs_lacros_version = base::Version("2.0.0");
-  const base::Version stateful_lacros_version = base::Version("3.0.0");
-  auto browser_loader = CreateBrowserLoaderWithFakeSelectionLoaders(
-      rootfs_lacros_version, stateful_lacros_version);
-
-  base::test::TestFuture<const base::FilePath&, LacrosSelection, base::Version>
-      future;
-  browser_loader.Load(future.GetCallback());
-  EXPECT_EQ(LacrosSelection::kStateful, future.Get<1>());
-  EXPECT_EQ(stateful_lacros_version, future.Get<2>());
-}
-
-TEST_F(BrowserLoaderTest, OnLoadVersionSelectionSameVersions) {
-  // Use stateful when rootfs and stateful lacros-chrome versions are the same.
-  const base::Version rootfs_lacros_version = base::Version("2.0.0");
-  const base::Version stateful_lacros_version = base::Version("2.0.0");
-  auto browser_loader = CreateBrowserLoaderWithFakeSelectionLoaders(
-      rootfs_lacros_version, stateful_lacros_version);
-
-  base::test::TestFuture<const base::FilePath&, LacrosSelection, base::Version>
-      future;
-  browser_loader.Load(future.GetCallback());
-  EXPECT_EQ(LacrosSelection::kStateful, future.Get<1>());
-  EXPECT_EQ(stateful_lacros_version, future.Get<2>());
-}
-
-TEST_F(BrowserLoaderTest, OnLoadSelectionPolicyIsRootfs) {
-  ScopedLacrosSelectionCache cache(
-      ash::standalone_browser::LacrosSelectionPolicy::kRootfs);
-  base::test::ScopedCommandLine command_line;
-  command_line.GetProcessCommandLine()->AppendSwitchASCII(
-      ash::standalone_browser::kLacrosSelectionSwitch,
-      ash::standalone_browser::kLacrosSelectionStateful);
-
-  // Set stateful lacros version newer than rootfs to test that the selection
-  // policy is prioritized higher.
-  const base::Version rootfs_lacros_version = base::Version("2.0.0");
-  const base::Version stateful_lacros_version = base::Version("3.0.0");
-  auto browser_loader = CreateBrowserLoaderWithFakeSelectionLoaders(
-      rootfs_lacros_version, stateful_lacros_version);
-
-  base::test::TestFuture<const base::FilePath&, LacrosSelection, base::Version>
-      future;
-  browser_loader.Load(future.GetCallback());
-
-  const LacrosSelection selection = future.Get<1>();
-  EXPECT_EQ(selection, LacrosSelection::kRootfs);
-  EXPECT_FALSE(BrowserLoader::WillLoadStatefulComponentBuilds());
-
-  // Check stateful lacros loader is not initialized since the selection is
-  // forced by policy.
-  EXPECT_FALSE(browser_loader.stateful_lacros_loader_);
-}
-
-TEST_F(BrowserLoaderTest,
-       OnLoadSelectionPolicyIsUserChoiceAndCommandLineIsRootfs) {
-  ScopedLacrosSelectionCache cache(
-      ash::standalone_browser::LacrosSelectionPolicy::kUserChoice);
-  base::test::ScopedCommandLine command_line;
-  command_line.GetProcessCommandLine()->AppendSwitchASCII(
-      ash::standalone_browser::kLacrosSelectionSwitch,
-      ash::standalone_browser::kLacrosSelectionRootfs);
-
-  // Set stateful lacros version newer than rootfs to test that the user choice
-  // is prioritized higher.
-  const base::Version rootfs_lacros_version = base::Version("2.0.0");
-  const base::Version stateful_lacros_version = base::Version("3.0.0");
-  auto browser_loader = CreateBrowserLoaderWithFakeSelectionLoaders(
-      rootfs_lacros_version, stateful_lacros_version);
-
-  base::test::TestFuture<const base::FilePath&, LacrosSelection, base::Version>
-      future;
-  browser_loader.Load(future.GetCallback());
-
-  const LacrosSelection selection = future.Get<1>();
-  EXPECT_EQ(selection, LacrosSelection::kRootfs);
-  EXPECT_FALSE(BrowserLoader::WillLoadStatefulComponentBuilds());
-
-  // Check stateful lacros loader is not initialized since the selection is
-  // forced by policy.
-  EXPECT_FALSE(browser_loader.stateful_lacros_loader_);
-}
-
-TEST_F(BrowserLoaderTest,
-       OnLoadSelectionPolicyIsUserChoiceAndCommandLineIsStateful) {
-  ScopedLacrosSelectionCache cache(
-      ash::standalone_browser::LacrosSelectionPolicy::kUserChoice);
-  base::test::ScopedCommandLine command_line;
-  command_line.GetProcessCommandLine()->AppendSwitchASCII(
-      ash::standalone_browser::kLacrosSelectionSwitch,
-      ash::standalone_browser::kLacrosSelectionStateful);
-
-  // Set rootfs lacros version newer than rootfs to test that the user choice
-  // is prioritized higher.
-  const base::Version rootfs_lacros_version = base::Version("2.0.0");
-  const base::Version stateful_lacros_version = base::Version("1.0.0");
-  auto browser_loader = CreateBrowserLoaderWithFakeSelectionLoaders(
-      rootfs_lacros_version, stateful_lacros_version);
-
-  base::test::TestFuture<const base::FilePath&, LacrosSelection, base::Version>
-      future;
-  browser_loader.Load(future.GetCallback());
-
-  const LacrosSelection selection = future.Get<1>();
-  EXPECT_EQ(selection, LacrosSelection::kStateful);
-  EXPECT_TRUE(BrowserLoader::WillLoadStatefulComponentBuilds());
-
-  // Check rootfs lacros loader is not initialized since the selection is forced
-  // by policy.
-  EXPECT_FALSE(browser_loader.rootfs_lacros_loader_);
-}
-
-TEST_F(BrowserLoaderTest, OnLoadLacrosBinarySpecifiedBySwitch) {
-  base::ScopedTempDir temp_dir;
-  CHECK(temp_dir.CreateUniqueTempDir());
-  const base::FilePath lacros_chrome_dir = temp_dir.GetPath();
-  base::WriteFile(lacros_chrome_dir.Append("chrome"),
-                  "I am lacros-chrome deployed locally.");
-  const base::FilePath lacros_chrome_path =
-      temp_dir.GetPath().Append("mychrome");
-  base::WriteFile(lacros_chrome_path,
-                  "I am a custom lacros-chrome deployed locally.");
-
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      ash::switches::kLacrosChromePath, lacros_chrome_path.MaybeAsASCII());
-
-  // Set stateful/rootfs lacros-chrome version to check that specified
-  // lacros-chrome is prioritized higher.
-  const base::Version rootfs_lacros_version = base::Version("2.0.0");
-  const base::Version stateful_lacros_version = base::Version("3.0.0");
-  auto browser_loader = CreateBrowserLoaderWithFakeSelectionLoaders(
-      rootfs_lacros_version, stateful_lacros_version);
-
-  base::test::TestFuture<base::FilePath, LacrosSelection, base::Version> future;
-  browser_loader.Load(future.GetCallback<const base::FilePath&, LacrosSelection,
-                                         base::Version>());
-
-  const base::FilePath path = future.Get<0>();
-  const LacrosSelection selection = future.Get<1>();
-  EXPECT_EQ(path, lacros_chrome_path);
-  EXPECT_EQ(selection, LacrosSelection::kDeployedLocally);
-
-  // Check both rootfs and stateful lacros loader are not initialized since the
-  // selection is forced by switch.
-  EXPECT_FALSE(browser_loader.rootfs_lacros_loader_);
-  EXPECT_FALSE(browser_loader.stateful_lacros_loader_);
-}
-
-TEST_F(BrowserLoaderTest, OnLoadLacrosDirectorySpecifiedBySwitch) {
-  base::ScopedTempDir temp_dir;
-  CHECK(temp_dir.CreateUniqueTempDir());
-  const base::FilePath lacros_chrome_dir = temp_dir.GetPath();
-  base::WriteFile(lacros_chrome_dir.Append("chrome"),
-                  "I am lacros-chrome deployed locally.");
-
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      ash::switches::kLacrosChromePath, lacros_chrome_dir.MaybeAsASCII());
-
-  // Set stateful/rootfs lacros-chrome version to check that specified
-  // lacros-chrome is prioritized higher.
-  const base::Version rootfs_lacros_version = base::Version("2.0.0");
-  const base::Version stateful_lacros_version = base::Version("3.0.0");
-  auto browser_loader = CreateBrowserLoaderWithFakeSelectionLoaders(
-      rootfs_lacros_version, stateful_lacros_version);
-
-  base::test::TestFuture<base::FilePath, LacrosSelection, base::Version> future;
-  browser_loader.Load(future.GetCallback<const base::FilePath&, LacrosSelection,
-                                         base::Version>());
-
-  const base::FilePath path = future.Get<0>();
-  const LacrosSelection selection = future.Get<1>();
-  EXPECT_EQ(path, lacros_chrome_dir.Append("chrome"));
-  EXPECT_EQ(selection, LacrosSelection::kDeployedLocally);
-
-  // Check both rootfs and stateful lacros loader are not initialized since the
-  // selection is forced by switch.
-  EXPECT_FALSE(browser_loader.rootfs_lacros_loader_);
-  EXPECT_FALSE(browser_loader.stateful_lacros_loader_);
-}
-
-TEST_F(BrowserLoaderTest, LoadWhileUnloading) {
-  // If stateful is newer, rootfs lacros will be unloaded.
-  const base::Version rootfs_lacros_version = base::Version("2.0.0");
-  const base::Version stateful_lacros_version = base::Version("3.0.0");
-  auto browser_loader = CreateBrowserLoaderWithFakeSelectionLoaders(
-      rootfs_lacros_version, stateful_lacros_version);
-
-  // Load once. This will start asynchronous unload for rootfs lacros loader.
-  base::test::TestFuture<base::FilePath, LacrosSelection, base::Version> future;
-  browser_loader.Load(future.GetCallback<const base::FilePath&, LacrosSelection,
-                                         base::Version>());
-
-  // Wait until rootfs lacros loader starts Unload. GetVersion runs
-  // asynchronously before it start unloading.
-  base::test::TestFuture<void> future1;
-  FakeLacrosSelectionLoader* rootfs_lacros_loader =
-      static_cast<FakeLacrosSelectionLoader*>(
-          browser_loader.rootfs_lacros_loader_.get());
-  rootfs_lacros_loader->SetCallbackOnUnload(future1.GetCallback());
-  ASSERT_TRUE(future1.Wait());
-
-  // On requesting Load while Unloading, the load request should be stored to
-  // `callback_on_unload_completion_` and wait for unload to complete to resume
-  // load request.
-  base::test::TestFuture<base::FilePath, LacrosSelection, base::Version>
-      future2;
-  browser_loader.Load(future2.GetCallback<const base::FilePath&,
-                                          LacrosSelection, base::Version>());
-
-  EXPECT_EQ(LacrosSelection::kStateful, future2.Get<1>());
-}
-
-}  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/browser_util.cc b/chrome/browser/ash/crosapi/browser_util.cc
index 9e4827c8..4d3c1d0 100644
--- a/chrome/browser/ash/crosapi/browser_util.cc
+++ b/chrome/browser/ash/crosapi/browser_util.cc
@@ -19,15 +19,11 @@
 #include "base/version.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
-#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
 #include "chromeos/crosapi/cpp/crosapi_constants.h"
 #include "components/exo/shell_surface_util.h"
 #include "components/version_info/channel.h"
 #include "components/version_info/version_info.h"
 
-using ash::standalone_browser::LacrosAvailability;
-using user_manager::User;
-
 namespace crosapi::browser_util {
 
 namespace {
diff --git a/chrome/browser/ash/crosapi/browser_util.h b/chrome/browser/ash/crosapi/browser_util.h
index 32ad8d5b..25bec24 100644
--- a/chrome/browser/ash/crosapi/browser_util.h
+++ b/chrome/browser/ash/crosapi/browser_util.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_CROSAPI_BROWSER_UTIL_H_
 #define CHROME_BROWSER_ASH_CROSAPI_BROWSER_UTIL_H_
 
-#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
 #include "chromeos/ash/components/standalone_browser/lacros_selection.h"
 
 namespace aura {
diff --git a/chrome/browser/ash/crosapi/browser_util_unittest.cc b/chrome/browser/ash/crosapi/browser_util_unittest.cc
index b74ec9b..009dfe6 100644
--- a/chrome/browser/ash/crosapi/browser_util_unittest.cc
+++ b/chrome/browser/ash/crosapi/browser_util_unittest.cc
@@ -137,14 +137,4 @@
   EXPECT_FALSE(browser_util::GetRootfsLacrosVersionMayBlock(path).IsValid());
 }
 
-// Lacros availability has an effect on googlers
-TEST_F(BrowserUtilTest, LacrosAvailabilityIgnoreGoogleEnableToUserChoice) {
-  AddRegularUser("user@google.com");
-
-  base::test::ScopedCommandLine cmd_line;
-  cmd_line.GetProcessCommandLine()->AppendSwitch(
-      ash::switches::kLacrosAvailabilityIgnore);
-  EXPECT_FALSE(browser_util::IsLacrosEnabled());
-}
-
 }  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/lacros_selection_loader_factory.h b/chrome/browser/ash/crosapi/lacros_selection_loader_factory.h
index 06010259..547f0cb 100644
--- a/chrome/browser/ash/crosapi/lacros_selection_loader_factory.h
+++ b/chrome/browser/ash/crosapi/lacros_selection_loader_factory.h
@@ -15,8 +15,7 @@
  public:
   virtual ~LacrosSelectionLoaderFactory() = default;
 
-  // Interface to create LacrosSelectionLoader for rootfs/stateful.
-  virtual std::unique_ptr<LacrosSelectionLoader> CreateRootfsLacrosLoader() = 0;
+  // Interface to create LacrosSelectionLoader for stateful.
   virtual std::unique_ptr<LacrosSelectionLoader>
   CreateStatefulLacrosLoader() = 0;
 };
diff --git a/chrome/browser/ash/crosapi/rootfs_lacros_loader.cc b/chrome/browser/ash/crosapi/rootfs_lacros_loader.cc
deleted file mode 100644
index f5d733c..0000000
--- a/chrome/browser/ash/crosapi/rootfs_lacros_loader.cc
+++ /dev/null
@@ -1,261 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/crosapi/rootfs_lacros_loader.h"
-
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/files/file_util.h"
-#include "base/functional/bind.h"
-#include "base/logging.h"
-#include "base/path_service.h"
-#include "base/task/task_traits.h"
-#include "base/task/thread_pool.h"
-#include "chrome/browser/ash/crosapi/browser_util.h"
-#include "chromeos/ash/components/dbus/upstart/upstart_client.h"
-#include "components/user_manager/user_manager.h"
-
-namespace crosapi {
-
-namespace {
-
-// The rootfs lacros-chrome binary related files.
-constexpr char kLacrosMetadata[] = "metadata.json";
-
-// The rootfs lacros-chrome binary related paths.
-// Must be kept in sync with lacros upstart conf files.
-constexpr char kRootfsLacrosMountPoint[] = "/run/lacros";
-constexpr char kRootfsLacrosPath[] = "/opt/google/lacros";
-
-// Lacros upstart jobs for mounting/unmounting the lacros-chrome image.
-// The conversion of upstart job names to dbus object paths is undocumented. See
-// function nih_dbus_path in libnih for the implementation.
-constexpr char kLacrosMounterUpstartJob[] = "lacros_2dmounter";
-constexpr char kLacrosUnmounterUpstartJob[] = "lacros_2dunmounter";
-
-}  // namespace
-
-RootfsLacrosLoader::RootfsLacrosLoader()
-    : RootfsLacrosLoader(
-          ash::UpstartClient::Get(),
-          base::FilePath(kRootfsLacrosPath).Append(kLacrosMetadata)) {}
-
-RootfsLacrosLoader::RootfsLacrosLoader(ash::UpstartClient* upstart_client,
-                                       base::FilePath metadata_path)
-    : upstart_client_(upstart_client),
-      metadata_path_(std::move(metadata_path)) {}
-
-RootfsLacrosLoader::~RootfsLacrosLoader() = default;
-
-void RootfsLacrosLoader::Load(LoadCompletionCallback callback, bool forced) {
-  CHECK(state_ == State::kNotLoaded ||
-        state_ == State::kVersionReadyButNotLoaded)
-      << state_;
-  LOG(WARNING) << "Loading rootfs lacros.";
-
-  if (state_ == State::kVersionReadyButNotLoaded) {
-    OnVersionReadyToLoad(std::move(callback), version_.value());
-    return;
-  }
-
-  // Calculate `version_` before start loading.
-  // It's not calculated yet in case when lacros selection is defined by
-  // selection policy or stateful lacros is not installed.
-  state_ = State::kReadingVersion;
-  GetVersionInternal(base::BindOnce(&RootfsLacrosLoader::OnVersionReadyToLoad,
-                                    weak_factory_.GetWeakPtr(),
-                                    std::move(callback)));
-}
-
-void RootfsLacrosLoader::Unload(base::OnceClosure callback) {
-  switch (state_) {
-    case State::kNotLoaded:
-    case State::kVersionReadyButNotLoaded:
-    case State::kUnloaded:
-      // Nothing to unload if it's not loaded or already unloaded.
-      state_ = State::kUnloaded;
-      std::move(callback).Run();
-      break;
-    case State::kReadingVersion:
-    case State::kLoading:
-    case State::kUnloading:
-      // If loader is busy, wait Unload until the current task has finished.
-      pending_unload_ =
-          base::BindOnce(&RootfsLacrosLoader::Unload,
-                         weak_factory_.GetWeakPtr(), std::move(callback));
-      break;
-    case State::kLoaded:
-      state_ = State::kUnloading;
-
-      upstart_client_->StartJob(
-          kLacrosUnmounterUpstartJob, {},
-          base::BindOnce(&RootfsLacrosLoader::OnUnloadCompleted,
-                         weak_factory_.GetWeakPtr(), std::move(callback)));
-  }
-}
-
-void RootfsLacrosLoader::GetVersion(
-    base::OnceCallback<void(const base::Version&)> callback) {
-  CHECK_EQ(state_, State::kNotLoaded) << state_;
-  state_ = State::kReadingVersion;
-  GetVersionInternal(std::move(callback));
-}
-
-bool RootfsLacrosLoader::IsUnloading() const {
-  return state_ == State::kUnloading;
-}
-
-bool RootfsLacrosLoader::IsUnloaded() const {
-  return state_ == State::kUnloaded;
-}
-
-void RootfsLacrosLoader::GetVersionInternal(
-    base::OnceCallback<void(const base::Version&)> callback) {
-  CHECK_EQ(state_, State::kReadingVersion) << state_;
-  CHECK(!version_);
-
-  base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE, {base::MayBlock()},
-      base::BindOnce(&browser_util::GetRootfsLacrosVersionMayBlock,
-                     metadata_path_),
-      base::BindOnce(&RootfsLacrosLoader::OnGetVersion,
-                     weak_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void RootfsLacrosLoader::OnGetVersion(
-    base::OnceCallback<void(const base::Version&)> callback,
-    base::Version version) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  CHECK_EQ(state_, State::kReadingVersion) << state_;
-
-  version_ = version;
-  state_ = State::kVersionReadyButNotLoaded;
-
-  if (pending_unload_) {
-    LOG(WARNING) << "Unload is requested during getting version of rootfs.";
-    std::move(callback).Run(base::Version());
-    std::move(pending_unload_).Run();
-    return;
-  }
-
-  std::move(callback).Run(version_.value());
-}
-
-void RootfsLacrosLoader::OnVersionReadyToLoad(LoadCompletionCallback callback,
-                                              const base::Version& version) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  CHECK_EQ(state_, State::kVersionReadyButNotLoaded) << state_;
-
-  if (pending_unload_) {
-    LOG(WARNING) << "Unload is requested during loading rootfs.";
-    std::move(callback).Run(base::Version(), base::FilePath());
-    std::move(pending_unload_).Run();
-    return;
-  }
-
-  // `version_` must be already filled by `version`.
-  CHECK(version_.has_value() &&
-        ((!version_.value().IsValid() && !version.IsValid()) ||
-         (version_.value() == version)));
-
-  state_ = State::kLoading;
-
-  base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE, {base::MayBlock()},
-      base::BindOnce(
-          &base::PathExists,
-          base::FilePath(kRootfsLacrosMountPoint).Append(kLacrosChromeBinary)),
-      base::BindOnce(&RootfsLacrosLoader::OnMountCheckToLoad,
-                     weak_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void RootfsLacrosLoader::OnMountCheckToLoad(LoadCompletionCallback callback,
-                                            bool already_mounted) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  CHECK_EQ(state_, State::kLoading) << state_;
-
-  if (pending_unload_) {
-    LOG(WARNING) << "Unload is requested during loading rootfs.";
-    state_ = State::kVersionReadyButNotLoaded;
-    std::move(callback).Run(base::Version(), base::FilePath());
-    std::move(pending_unload_).Run();
-    return;
-  }
-
-  if (already_mounted) {
-    OnUpstartLacrosMounter(std::move(callback), true);
-    return;
-  }
-
-  std::vector<std::string> job_env;
-  if (user_manager::UserManager::Get()->IsLoggedInAsGuest()) {
-    job_env.emplace_back("USE_SESSION_NAMESPACE=true");
-  }
-
-  upstart_client_->StartJob(
-      kLacrosMounterUpstartJob, job_env,
-      base::BindOnce(&RootfsLacrosLoader::OnUpstartLacrosMounter,
-                     weak_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void RootfsLacrosLoader::OnUpstartLacrosMounter(LoadCompletionCallback callback,
-                                                bool success) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  CHECK_EQ(state_, State::kLoading) << state_;
-  state_ = State::kLoaded;
-
-  LOG_IF(WARNING, !success) << "Upstart failed to mount rootfs lacros.";
-
-  if (pending_unload_) {
-    LOG(WARNING) << "Unload is requested during loading rootfs.";
-    std::move(callback).Run(base::Version(), base::FilePath());
-    std::move(pending_unload_).Run();
-    return;
-  }
-
-  // `version_` must be calculated before coming here.
-  CHECK(version_.has_value());
-  std::move(callback).Run(
-      version_.value(),
-      // If mounting wasn't successful, return a empty mount point to indicate
-      // failure. `OnLoadComplete` handles empty mount points and forwards the
-      // errors on the return callbacks.
-      success ? base::FilePath(kRootfsLacrosMountPoint) : base::FilePath());
-}
-
-void RootfsLacrosLoader::OnUnloadCompleted(base::OnceClosure callback,
-                                           bool success) {
-  // Proceed anyway regardless of unload success.
-  if (!success) {
-    LOG(ERROR) << "Failed to unload rootfs lacros";
-  }
-
-  CHECK_EQ(state_, State::kUnloading) << state_;
-  state_ = State::kUnloaded;
-  std::move(callback).Run();
-}
-
-std::ostream& operator<<(std::ostream& ostream,
-                         RootfsLacrosLoader::State state) {
-  switch (state) {
-    case RootfsLacrosLoader::State::kNotLoaded:
-      return ostream << "NotLoaded";
-    case RootfsLacrosLoader::State::kReadingVersion:
-      return ostream << "ReadingVersion";
-    case RootfsLacrosLoader::State::kVersionReadyButNotLoaded:
-      return ostream << "VersionReadyButNotLoaded";
-    case RootfsLacrosLoader::State::kLoading:
-      return ostream << "Loading";
-    case RootfsLacrosLoader::State::kLoaded:
-      return ostream << "Loaded";
-    case RootfsLacrosLoader::State::kUnloading:
-      return ostream << "Unloading";
-    case RootfsLacrosLoader::State::kUnloaded:
-      return ostream << "Unloaded";
-  }
-}
-
-}  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/rootfs_lacros_loader.h b/chrome/browser/ash/crosapi/rootfs_lacros_loader.h
deleted file mode 100644
index b492af5..0000000
--- a/chrome/browser/ash/crosapi/rootfs_lacros_loader.h
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ASH_CROSAPI_ROOTFS_LACROS_LOADER_H_
-#define CHROME_BROWSER_ASH_CROSAPI_ROOTFS_LACROS_LOADER_H_
-
-#include <optional>
-#include <ostream>
-
-#include "base/files/file_path.h"
-#include "base/functional/callback.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/version.h"
-#include "chrome/browser/ash/crosapi/lacros_selection_loader.h"
-
-namespace ash {
-class UpstartClient;
-}  // namespace ash
-
-namespace crosapi {
-
-class RootfsLacrosLoader : public LacrosSelectionLoader {
- public:
-  // Constructor for production.
-  RootfsLacrosLoader();
-  // Constructor for testing.
-  explicit RootfsLacrosLoader(ash::UpstartClient* upstart_client,
-                              base::FilePath metadata_path);
-  RootfsLacrosLoader(const RootfsLacrosLoader&) = delete;
-  RootfsLacrosLoader& operator=(const RootfsLacrosLoader&) = delete;
-  ~RootfsLacrosLoader() override;
-
-  // The state representing the loading state.
-  enum class State {
-    // Loader is not running any task.
-    kNotLoaded,
-
-    // Loader is in the process of reading the version from manifest file.
-    kReadingVersion,
-
-    // Loader gets version of lacros-chrome but not loaded it yet.
-    kVersionReadyButNotLoaded,
-
-    // Loader is in the process of loading lacros-chrome.
-    kLoading,
-
-    // Loader has loaded lacros-chrome and `version_` and `path_` is ready.
-    kLoaded,
-
-    // Loader is in the process of unloading lacros-chrome.
-    kUnloading,
-
-    // Loader has unloaded the lacros-chrome. State must NOT change once it
-    // becomes kUnloaded.
-    kUnloaded,
-  };
-
-  State GetState() const { return state_; }
-
-  // LacrosSelectionLoader:
-  void Load(LoadCompletionCallback callback, bool forced) override;
-  void Unload(base::OnceClosure callback) override;
-  void GetVersion(
-      base::OnceCallback<void(const base::Version&)> callback) override;
-  bool IsUnloading() const override;
-  bool IsUnloaded() const override;
-
- private:
-  void GetVersionInternal(
-      base::OnceCallback<void(const base::Version&)> callback);
-
-  // Called after GetVersion.
-  void OnGetVersion(base::OnceCallback<void(const base::Version&)> callback,
-                    base::Version version);
-
-  // Called when `version_` is calculated and set during Load() sequence.
-  void OnVersionReadyToLoad(LoadCompletionCallback callback,
-                            const base::Version& version);
-
-  // Called on checking rootfs lacros-chrome is already maounted or not during
-  // Load() sequence.
-  void OnMountCheckToLoad(LoadCompletionCallback callback,
-                          bool already_mounted);
-
-  // Callback from upstart mounting lacros-chrome.
-  void OnUpstartLacrosMounter(LoadCompletionCallback callback, bool success);
-
-  // Called on unload completed.
-  void OnUnloadCompleted(base::OnceClosure callback, bool success);
-
-  // The bundled rootfs lacros-chrome binary version. This is set after the
-  // first async call that checks the installed rootfs lacros version number.
-  // If `version_` is null, it implies the version is not yet calculated.
-  // For cases where it failed to read the version, invalid `base::Version()` is
-  // set.
-  std::optional<base::Version> version_;
-
-  // Pointer held to `UpstartClient` for testing purposes.
-  // Otherwise, the lifetime is the same as `ash::UpstartClient::Get()`.
-  const raw_ptr<ash::UpstartClient> upstart_client_;
-
-  // The path which stores the metadata including the version.
-  // This is always the same for production code, but may be overridden on
-  // testing.
-  base::FilePath metadata_path_;
-
-  base::OnceClosure pending_unload_;
-
-  State state_ = State::kNotLoaded;
-
-  // Used for DCHECKs to ensure method calls executed in the correct thread.
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  base::WeakPtrFactory<RootfsLacrosLoader> weak_factory_{this};
-};
-
-std::ostream& operator<<(std::ostream&, RootfsLacrosLoader::State);
-
-}  // namespace crosapi
-
-#endif  // CHROME_BROWSER_ASH_CROSAPI_ROOTFS_LACROS_LOADER_H_
diff --git a/chrome/browser/ash/crosapi/rootfs_lacros_loader_unittest.cc b/chrome/browser/ash/crosapi/rootfs_lacros_loader_unittest.cc
deleted file mode 100644
index c00045d3..0000000
--- a/chrome/browser/ash/crosapi/rootfs_lacros_loader_unittest.cc
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/crosapi/rootfs_lacros_loader.h"
-
-#include <memory>
-#include <string>
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/test/bind.h"
-#include "base/test/test_future.h"
-#include "base/version.h"
-#include "chromeos/ash/components/dbus/upstart/fake_upstart_client.h"
-#include "components/user_manager/fake_user_manager.h"
-#include "components/user_manager/scoped_user_manager.h"
-#include "content/public/test/browser_task_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace crosapi {
-namespace {
-
-// Copied from rootfs_lacros_loader.cc
-constexpr char kLacrosMounterUpstartJob[] = "lacros_2dmounter";
-
-class RootfsLacrosLoaderTest : public testing::Test {
- public:
-  RootfsLacrosLoaderTest() {
-    CHECK(temp_dir_.CreateUniqueTempDir());
-    metadata_path_ = temp_dir_.GetPath().Append("metadata");
-    base::WriteFile(metadata_path_,
-                    "{\"content\":{\"version\":\"" + version_str + "\"}}");
-    rootfs_lacros_loader_ = std::make_unique<RootfsLacrosLoader>(
-        &fake_upstart_client_, metadata_path_);
-  }
-
- protected:
-  content::BrowserTaskEnvironment task_environment_;
-
-  const std::string version_str = "1.0.0";
-  base::ScopedTempDir temp_dir_;
-  base::FilePath metadata_path_;
-
-  user_manager::TypedScopedUserManager<user_manager::FakeUserManager>
-      scoped_user_manager_{std::make_unique<user_manager::FakeUserManager>()};
-  ash::FakeUpstartClient fake_upstart_client_;
-  std::unique_ptr<RootfsLacrosLoader> rootfs_lacros_loader_;
-};
-
-TEST_F(RootfsLacrosLoaderTest, LoadRootfsLacrosSelectedByCompatibilityCheck) {
-  bool callback_called = false;
-  fake_upstart_client_.set_start_job_cb(base::BindRepeating(
-      [](bool* callback_called, const std::string& job,
-         const std::vector<std::string>& upstart_env) {
-        EXPECT_EQ(job, kLacrosMounterUpstartJob);
-        *callback_called = true;
-        return ash::FakeUpstartClient::StartJobResult(true /* success */);
-      },
-      &callback_called));
-
-  EXPECT_EQ(RootfsLacrosLoader::State::kNotLoaded,
-            rootfs_lacros_loader_->GetState());
-
-  // If rootfs is selected by compatibility check, it first calls GetVersion to
-  // read the version, and then Load is requested. Inside GetVersion, Load won't
-  // complete.
-  base::test::TestFuture<const base::Version&> future1;
-  rootfs_lacros_loader_->GetVersion(
-      future1.GetCallback<const base::Version&>());
-  EXPECT_EQ(base::Version(version_str), future1.Get<0>());
-  EXPECT_EQ(RootfsLacrosLoader::State::kVersionReadyButNotLoaded,
-            rootfs_lacros_loader_->GetState());
-  EXPECT_FALSE(callback_called);
-
-  // Load is called after version is calculated.
-  base::test::TestFuture<base::Version, const base::FilePath&> future2;
-  rootfs_lacros_loader_->Load(
-      future2.GetCallback<base::Version, const base::FilePath&>(),
-      /*forced=*/false);
-  EXPECT_EQ(base::Version(version_str), future2.Get<0>());
-  EXPECT_TRUE(callback_called);
-
-  EXPECT_EQ(RootfsLacrosLoader::State::kLoaded,
-            rootfs_lacros_loader_->GetState());
-}
-
-TEST_F(RootfsLacrosLoaderTest, LoadRootfsLacrosSelectedByPolicy) {
-  bool callback_called = false;
-  fake_upstart_client_.set_start_job_cb(base::BindRepeating(
-      [](bool* callback_called, const std::string& job,
-         const std::vector<std::string>& upstart_env) {
-        EXPECT_EQ(job, kLacrosMounterUpstartJob);
-        *callback_called = true;
-        return ash::FakeUpstartClient::StartJobResult(true /* success */);
-      },
-      &callback_called));
-
-  EXPECT_EQ(RootfsLacrosLoader::State::kNotLoaded,
-            rootfs_lacros_loader_->GetState());
-
-  // If rootfs is selected by policy, it does not call GetVersion. Instead, it
-  // calls Load directly and compute read the version inside Load together.
-  base::test::TestFuture<base::Version, const base::FilePath&> future;
-  rootfs_lacros_loader_->Load(
-      future.GetCallback<base::Version, const base::FilePath&>(),
-      /*forced=*/false);
-  EXPECT_EQ(base::Version(version_str), future.Get<0>());
-  EXPECT_TRUE(callback_called);
-
-  EXPECT_EQ(RootfsLacrosLoader::State::kLoaded,
-            rootfs_lacros_loader_->GetState());
-}
-
-TEST_F(RootfsLacrosLoaderTest, UnloadRequestedOnVersionReady) {
-  EXPECT_EQ(RootfsLacrosLoader::State::kNotLoaded,
-            rootfs_lacros_loader_->GetState());
-
-  // First, request loader to get version and stops at
-  // `kVersionReadyButNotLoaded`.
-  base::test::TestFuture<const base::Version&> future1;
-  rootfs_lacros_loader_->GetVersion(
-      future1.GetCallback<const base::Version&>());
-  EXPECT_EQ(base::Version(version_str), future1.Get<0>());
-  EXPECT_EQ(RootfsLacrosLoader::State::kVersionReadyButNotLoaded,
-            rootfs_lacros_loader_->GetState());
-
-  // Simulate the case that stateful is selected by compatibility check so that
-  // it requests rootfs lacros loader to unload.
-  base::test::TestFuture<void> future2;
-  rootfs_lacros_loader_->Unload(future2.GetCallback());
-  EXPECT_EQ(RootfsLacrosLoader::State::kUnloaded,
-            rootfs_lacros_loader_->GetState());
-}
-
-}  // namespace
-}  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/stateful_lacros_loader_unittest.cc b/chrome/browser/ash/crosapi/stateful_lacros_loader_unittest.cc
index 1b6800b..f27b143c 100644
--- a/chrome/browser/ash/crosapi/stateful_lacros_loader_unittest.cc
+++ b/chrome/browser/ash/crosapi/stateful_lacros_loader_unittest.cc
@@ -65,7 +65,6 @@
     stateful_lacros_loader_ = std::make_unique<StatefulLacrosLoader>(
         component_manager_, &mock_component_update_service_,
         kLacrosComponentName);
-    EXPECT_TRUE(BrowserLoader::WillLoadStatefulComponentBuilds());
   }
 
   ~StatefulLacrosLoaderTest() override {
diff --git a/chrome/browser/ash/extensions/users_private/users_private_delegate_factory.h b/chrome/browser/ash/extensions/users_private/users_private_delegate_factory.h
index caa3d6c..34bf74450c 100644
--- a/chrome/browser/ash/extensions/users_private/users_private_delegate_factory.h
+++ b/chrome/browser/ash/extensions/users_private/users_private_delegate_factory.h
@@ -8,7 +8,7 @@
 #include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
 
-namespace context {
+namespace content {
 class BrowserContext;
 }
 
diff --git a/chrome/browser/ash/input_method/BUILD.gn b/chrome/browser/ash/input_method/BUILD.gn
index dd2fb34..5fe38e8d 100644
--- a/chrome/browser/ash/input_method/BUILD.gn
+++ b/chrome/browser/ash/input_method/BUILD.gn
@@ -89,8 +89,6 @@
     "editor_transition_enums.h",
     "emoji_suggester.cc",
     "emoji_suggester.h",
-    "field_trial.cc",
-    "field_trial.h",
     "get_current_window_properties.cc",
     "get_current_window_properties.h",
     "grammar_manager.cc",
diff --git a/chrome/browser/ash/input_method/assistive_input_denylist.cc b/chrome/browser/ash/input_method/assistive_input_denylist.cc
index 144193f..cdc78f2 100644
--- a/chrome/browser/ash/input_method/assistive_input_denylist.cc
+++ b/chrome/browser/ash/input_method/assistive_input_denylist.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/ash/input_method/assistive_input_denylist.h"
 
-#include "base/json/json_reader.h"
 #include "chrome/browser/ash/input_method/url_utils.h"
 
 namespace ash {
@@ -38,19 +37,6 @@
 // Exceptions where the features are enabled.
 const char* kAllowedDomainsWithPaths[][2] = {{"mail.google", "/chat"}};
 
-std::vector<std::string> ToDenylist(const base::Value& value) {
-  if (!value.is_list()) {
-    return {};
-  }
-  std::vector<std::string> domains;
-  for (const auto& item : value.GetList()) {
-    if (item.is_string()) {
-      domains.push_back(item.GetString());
-    }
-  }
-  return domains;
-}
-
 bool MatchesSubDomainFromDefaultList(const GURL& url) {
   for (const char* domain : kDefaultDomainDenylist) {
     if (IsSubDomain(url, domain)) {
@@ -60,16 +46,6 @@
   return false;
 }
 
-bool MatchesSubDomainFrom(const std::vector<std::string>& denylist,
-                          const GURL& url) {
-  for (const auto& domain : denylist) {
-    if (IsSubDomain(url, domain)) {
-      return true;
-    }
-  }
-  return false;
-}
-
 bool AllowedSubDomainWithPathPrefix(const GURL& url) {
   for (const auto& [domain, path_prefix] : kAllowedDomainsWithPaths) {
     if (IsSubDomainWithPathPrefix(url, domain, path_prefix)) {
@@ -81,25 +57,12 @@
 
 }  // namespace
 
-AssistiveInputDenylist::AssistiveInputDenylist(
-    const DenylistAdditions& additions) {
-  if (auto parsed = base::JSONReader::Read(additions.autocorrect_denylist_json);
-      parsed.has_value() && parsed->is_list()) {
-    autocorrect_denylist_ = ToDenylist(*parsed);
-  }
-
-  if (auto parsed = base::JSONReader::Read(additions.multi_word_denylist_json);
-      parsed.has_value() && parsed->is_list()) {
-    multi_word_denylist_ = ToDenylist(*parsed);
-  }
-}
+AssistiveInputDenylist::AssistiveInputDenylist() = default;
 
 AssistiveInputDenylist::~AssistiveInputDenylist() = default;
 
 bool AssistiveInputDenylist::Contains(const GURL& url) {
-  return ((MatchesSubDomainFromDefaultList(url) ||
-           MatchesSubDomainFrom(autocorrect_denylist_, url) ||
-           MatchesSubDomainFrom(multi_word_denylist_, url)) &&
+  return (MatchesSubDomainFromDefaultList(url) &&
           // Used to allow specific paths on a top level domain that has been
           // denied (for example, "mail.google.com/chat").
           !AllowedSubDomainWithPathPrefix(url));
diff --git a/chrome/browser/ash/input_method/assistive_input_denylist.h b/chrome/browser/ash/input_method/assistive_input_denylist.h
index b774541..1651fa48 100644
--- a/chrome/browser/ash/input_method/assistive_input_denylist.h
+++ b/chrome/browser/ash/input_method/assistive_input_denylist.h
@@ -5,36 +5,22 @@
 #ifndef CHROME_BROWSER_ASH_INPUT_METHOD_ASSISTIVE_INPUT_DENYLIST_H_
 #define CHROME_BROWSER_ASH_INPUT_METHOD_ASSISTIVE_INPUT_DENYLIST_H_
 
-#include <optional>
-#include <string>
-#include <vector>
-
 #include "base/values.h"
 #include "url/gurl.h"
 
 namespace ash {
 namespace input_method {
 
-struct DenylistAdditions {
-  const std::string autocorrect_denylist_json;
-  const std::string multi_word_denylist_json;
-};
-
 // Determines if assistive inputs should be enabled or disabled for a particular
 // input field. A denylist is made up of a list of urls where assistive
 // features should NOT show.
 class AssistiveInputDenylist {
  public:
-  AssistiveInputDenylist(const DenylistAdditions& additions);
+  AssistiveInputDenylist();
   ~AssistiveInputDenylist();
 
   // Is the url given found in the denylist?
   bool Contains(const GURL& url);
-
- private:
-  // Holds the specific denylists for each experiment.
-  std::vector<std::string> autocorrect_denylist_;
-  std::vector<std::string> multi_word_denylist_;
 };
 
 }  // namespace input_method
diff --git a/chrome/browser/ash/input_method/assistive_input_denylist_unittest.cc b/chrome/browser/ash/input_method/assistive_input_denylist_unittest.cc
index d6d9805..7f75fc6 100644
--- a/chrome/browser/ash/input_method/assistive_input_denylist_unittest.cc
+++ b/chrome/browser/ash/input_method/assistive_input_denylist_unittest.cc
@@ -4,24 +4,11 @@
 
 #include "chrome/browser/ash/input_method/assistive_input_denylist.h"
 
-#include "chrome/browser/ash/input_method/field_trial.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace ash {
 namespace input_method {
 
-std::string Empty() {
-  return "";
-}
-
-std::string InvalidJson() {
-  return "[:]";
-}
-
-std::string ExampleDenylist() {
-  return "[\"xyz\", \"uk\", \"subdomain.blah\"]";
-}
-
 using Contains = testing::TestWithParam<std::string>;
 
 INSTANTIATE_TEST_SUITE_P(
@@ -53,40 +40,7 @@
         "http://www.abc.smile.amazon.com.au/abc+com+au/some/other/text"));
 
 TEST_P(Contains, Url) {
-  EXPECT_TRUE(AssistiveInputDenylist(
-                  DenylistAdditions{.autocorrect_denylist_json = Empty(),
-                                    .multi_word_denylist_json = Empty()})
-                  .Contains(GURL(GetParam())));
-}
-
-TEST_P(Contains, UrlWhenInvalidJsonPassedAsAutocorrectDenylist) {
-  EXPECT_TRUE(AssistiveInputDenylist(
-                  DenylistAdditions{.autocorrect_denylist_json = InvalidJson(),
-                                    .multi_word_denylist_json = Empty()})
-                  .Contains(GURL(GetParam())));
-}
-
-TEST_P(Contains, UrlWhenInvalidJsonPassedAsMultiWordDenylist) {
-  EXPECT_TRUE(AssistiveInputDenylist(
-                  DenylistAdditions{.autocorrect_denylist_json = Empty(),
-                                    .multi_word_denylist_json = InvalidJson()})
-                  .Contains(GURL(GetParam())));
-}
-
-TEST_P(Contains, UrlWhenAutocorrectDynamicDenylistGiven) {
-  EXPECT_TRUE(
-      AssistiveInputDenylist(
-          DenylistAdditions{.autocorrect_denylist_json = ExampleDenylist(),
-                            .multi_word_denylist_json = Empty()})
-          .Contains(GURL(GetParam())));
-}
-
-TEST_P(Contains, UrlWhenMultiWordDynamicDenylistGiven) {
-  EXPECT_TRUE(
-      AssistiveInputDenylist(
-          DenylistAdditions{.autocorrect_denylist_json = Empty(),
-                            .multi_word_denylist_json = ExampleDenylist()})
-          .Contains(GURL(GetParam())));
+  EXPECT_TRUE(AssistiveInputDenylist().Contains(GURL(GetParam())));
 }
 
 using DoesNotContain = testing::TestWithParam<std::string>;
@@ -109,93 +63,7 @@
                     "http://.com/test"));
 
 TEST_P(DoesNotContain, Url) {
-  EXPECT_FALSE(AssistiveInputDenylist(
-                   DenylistAdditions{.autocorrect_denylist_json = Empty(),
-                                     .multi_word_denylist_json = Empty()})
-                   .Contains(GURL(GetParam())));
-}
-
-TEST_P(DoesNotContain, UrlWhenInvalidJsonPassedAsAutocorrectDenylist) {
-  EXPECT_FALSE(AssistiveInputDenylist(
-                   DenylistAdditions{.autocorrect_denylist_json = InvalidJson(),
-                                     .multi_word_denylist_json = Empty()})
-                   .Contains(GURL(GetParam())));
-}
-
-TEST_P(DoesNotContain, UrlWhenInvalidJsonPassedAsMultiWordDenylist) {
-  EXPECT_FALSE(AssistiveInputDenylist(
-                   DenylistAdditions{.autocorrect_denylist_json = Empty(),
-                                     .multi_word_denylist_json = InvalidJson()})
-                   .Contains(GURL(GetParam())));
-}
-
-TEST_P(DoesNotContain, UrlWhenAutocorrectDynamicDenylistGiven) {
-  EXPECT_FALSE(
-      AssistiveInputDenylist(
-          DenylistAdditions{.autocorrect_denylist_json = ExampleDenylist(),
-                            .multi_word_denylist_json = Empty()})
-          .Contains(GURL(GetParam())));
-}
-
-TEST_P(DoesNotContain, UrlWhenMultiWordDynamicDenylistGiven) {
-  EXPECT_FALSE(
-      AssistiveInputDenylist(
-          DenylistAdditions{.autocorrect_denylist_json = Empty(),
-                            .multi_word_denylist_json = ExampleDenylist()})
-          .Contains(GURL(GetParam())));
-}
-
-struct UrlExample {
-  std::string url;
-  bool found_in_list;
-};
-
-using UsesDynamicDenylist = testing::TestWithParam<UrlExample>;
-
-INSTANTIATE_TEST_SUITE_P(
-    AssistiveInputDenylistTest,
-    UsesDynamicDenylist,
-    testing::Values(
-        // Disabled examples
-        UrlExample{"http://xyz.com", /*found_in_list=*/true},
-        UrlExample{"https://xyz.com", /*found_in_list=*/true},
-        UrlExample{"https://www.xyz.com", /*found_in_list=*/true},
-        UrlExample{"https://xyz.com/with-path", /*found_in_list=*/true},
-        UrlExample{"https://xyz.com/with-path?and=params",
-                   /*found_in_list=*/true},
-        UrlExample{"https://uk.com", /*found_in_list=*/true},
-        UrlExample{"https://subdomain.blah.com", /*found_in_list=*/true},
-        UrlExample{"https://subdomain.blah.com/with-path",
-                   /*found_in_list=*/true},
-        // Enabled examples
-        UrlExample{"https://www.something.co.uk", /*found_in_list=*/false},
-        UrlExample{"https://something.co.uk/with-path",
-                   /*found_in_list=*/false},
-        UrlExample{"https://blah.com", /*found_in_list=*/false},
-        UrlExample{"https://something.blah.com", /*found_in_list=*/false},
-        UrlExample{"https://something.blah.com/with-path",
-                   /*found_in_list=*/false}));
-
-TEST_P(UsesDynamicDenylist, ForAutocorrect) {
-  const UrlExample& example = GetParam();
-
-  EXPECT_EQ(
-      AssistiveInputDenylist(
-          DenylistAdditions{.autocorrect_denylist_json = ExampleDenylist(),
-                            .multi_word_denylist_json = Empty()})
-          .Contains(GURL(example.url)),
-      example.found_in_list);
-}
-
-TEST_P(UsesDynamicDenylist, ForMultiWord) {
-  const UrlExample& example = GetParam();
-
-  EXPECT_EQ(
-      AssistiveInputDenylist(
-          DenylistAdditions{.autocorrect_denylist_json = Empty(),
-                            .multi_word_denylist_json = ExampleDenylist()})
-          .Contains(GURL(example.url)),
-      example.found_in_list);
+  EXPECT_FALSE(AssistiveInputDenylist().Contains(GURL(GetParam())));
 }
 
 }  // namespace input_method
diff --git a/chrome/browser/ash/input_method/assistive_suggester_client_filter.cc b/chrome/browser/ash/input_method/assistive_suggester_client_filter.cc
index 45b150b8..2ba3f94 100644
--- a/chrome/browser/ash/input_method/assistive_suggester_client_filter.cc
+++ b/chrome/browser/ash/input_method/assistive_suggester_client_filter.cc
@@ -17,7 +17,6 @@
 #include "ash/public/cpp/window_properties.h"
 #include "base/functional/callback.h"
 #include "base/hash/hash.h"
-#include "chrome/browser/ash/input_method/field_trial.h"
 #include "chrome/browser/ash/input_method/url_utils.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -262,14 +261,7 @@
     GetUrlCallback get_url,
     GetFocusedWindowPropertiesCallback get_window_properties)
     : get_url_(std::move(get_url)),
-      get_window_properties_(std::move(get_window_properties)),
-      denylist_(DenylistAdditions{
-          .autocorrect_denylist_json =
-              GetFieldTrialParam(features::kAutocorrectByDefault,
-                                 ParamName::kDenylist),
-          .multi_word_denylist_json =
-              GetFieldTrialParam(features::kAssistMultiWord,
-                                 ParamName::kDenylist)}) {}
+      get_window_properties_(std::move(get_window_properties)) {}
 
 AssistiveSuggesterClientFilter::~AssistiveSuggesterClientFilter() = default;
 
diff --git a/chrome/browser/ash/input_method/autocorrect_manager.cc b/chrome/browser/ash/input_method/autocorrect_manager.cc
index 7fd00ee..405e3a8 100644
--- a/chrome/browser/ash/input_method/autocorrect_manager.cc
+++ b/chrome/browser/ash/input_method/autocorrect_manager.cc
@@ -16,12 +16,10 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "chrome/browser/ash/crosapi/browser_util.h"
-#include "chrome/browser/ash/input_method/assistive_input_denylist.h"
 #include "chrome/browser/ash/input_method/assistive_prefs.h"
 #include "chrome/browser/ash/input_method/assistive_window_properties.h"
 #include "chrome/browser/ash/input_method/autocorrect_enums.h"
 #include "chrome/browser/ash/input_method/autocorrect_prefs.h"
-#include "chrome/browser/ash/input_method/field_trial.h"
 #include "chrome/browser/ash/input_method/suggestion_enums.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
@@ -344,15 +342,7 @@
 AutocorrectManager::AutocorrectManager(
     SuggestionHandlerInterface* suggestion_handler,
     Profile* profile)
-    : denylist_(DenylistAdditions{
-          .autocorrect_denylist_json =
-              GetFieldTrialParam(features::kAutocorrectByDefault,
-                                 ParamName::kDenylist),
-          .multi_word_denylist_json =
-              GetFieldTrialParam(features::kAssistMultiWord,
-                                 ParamName::kDenylist)}),
-      suggestion_handler_(suggestion_handler),
-      profile_(profile) {
+    : suggestion_handler_(suggestion_handler), profile_(profile) {
   undo_button_.id = ui::ime::ButtonId::kUndo;
   undo_button_.window_type = ash::ime::AssistiveWindowType::kUndoWindow;
   learn_more_button_.id = ui::ime::ButtonId::kLearnMore;
diff --git a/chrome/browser/ash/input_method/field_trial.cc b/chrome/browser/ash/input_method/field_trial.cc
deleted file mode 100644
index 1c79031..0000000
--- a/chrome/browser/ash/input_method/field_trial.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/input_method/field_trial.h"
-
-#include "base/metrics/field_trial_params.h"
-
-namespace ash {
-namespace input_method {
-
-std::string ToString(const ParamName& param_name) {
-  switch (param_name) {
-    case ParamName::kDenylist:
-      return "block";
-  }
-}
-
-std::string GetFieldTrialParam(const base::Feature& feature,
-                               const ParamName& param_name) {
-  return base::GetFieldTrialParamValueByFeature(feature, ToString(param_name));
-}
-
-}  // namespace input_method
-}  // namespace ash
diff --git a/chrome/browser/ash/input_method/field_trial.h b/chrome/browser/ash/input_method/field_trial.h
deleted file mode 100644
index 79315a19..0000000
--- a/chrome/browser/ash/input_method/field_trial.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ASH_INPUT_METHOD_FIELD_TRIAL_H_
-#define CHROME_BROWSER_ASH_INPUT_METHOD_FIELD_TRIAL_H_
-
-#include <string>
-
-#include "base/feature_list.h"
-
-namespace ash {
-namespace input_method {
-
-enum class ParamName { kDenylist };
-
-std::string GetFieldTrialParam(const base::Feature& feature,
-                               const ParamName& param_name);
-
-}  // namespace input_method
-}  // namespace ash
-
-#endif  // CHROME_BROWSER_ASH_INPUT_METHOD_FIELD_TRIAL_H_
diff --git a/chrome/browser/ash/net/alwayson_vpn_pre_connect_url_allowlist_service.cc b/chrome/browser/ash/net/alwayson_vpn_pre_connect_url_allowlist_service.cc
index a6c1772..d0aca73 100644
--- a/chrome/browser/ash/net/alwayson_vpn_pre_connect_url_allowlist_service.cc
+++ b/chrome/browser/ash/net/alwayson_vpn_pre_connect_url_allowlist_service.cc
@@ -28,9 +28,6 @@
   PrefService* pref_service =
       user_prefs::UserPrefs::Get(browser_context_.get());
 
-  // TODO(b/188864779, acostinas): After the ARC legacy migration is completed,
-  // monitor the Always-on VPN state from the network profile property instead
-  // of the user pref.
   profile_pref_change_registrar_.Init(pref_service);
   profile_pref_change_registrar_.Add(
       arc::prefs::kAlwaysOnVpnLockdown,
diff --git a/chrome/browser/ash/net/alwayson_vpn_pre_connect_url_allowlist_service_browsertest.cc b/chrome/browser/ash/net/alwayson_vpn_pre_connect_url_allowlist_service_browsertest.cc
index 4a5ea3c..1ad5de6 100644
--- a/chrome/browser/ash/net/alwayson_vpn_pre_connect_url_allowlist_service_browsertest.cc
+++ b/chrome/browser/ash/net/alwayson_vpn_pre_connect_url_allowlist_service_browsertest.cc
@@ -10,22 +10,19 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
-#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/ash/net/alwayson_vpn_pre_connect_url_allowlist_service_factory.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h"
 #include "chromeos/ash/components/dbus/shill/shill_service_client.h"
 #include "chromeos/ash/components/network/network_handler_test_helper.h"
 #include "components/account_id/account_id.h"
 #include "components/policy/core/common/policy_pref_names.h"
 #include "components/prefs/pref_service.h"
-#include "components/user_manager/fake_user_manager.h"
-#include "components/user_manager/scoped_user_manager.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -37,8 +34,6 @@
 constexpr char kDefaultEthernetPath[] = "/service/eth1";
 constexpr char kDefaultVpnPath[] = "/service/vpn1";
 
-constexpr char kFakePrimaryUsername[] = "test-primary@example.com";
-
 constexpr char kTestUrl[] = "test.url.com";
 }  // namespace
 
@@ -59,6 +54,28 @@
     ash::AlwaysOnVpnPreConnectUrlAllowlistServiceFactory::GetInstance()
         ->SetServiceIsNULLWhileTestingForTesting(
             /*service_is_null_while_testing=*/false);
+
+    network_handler_test_helper_ =
+        std::make_unique<::ash::NetworkHandlerTestHelper>();
+    ShillServiceClient::Get()->GetTestInterface()->SetServiceProperty(
+        "/service/wifi1", shill::kStateProperty,
+        base::Value(shill::kStateIdle));
+
+    browser()
+        ->profile()
+        ->GetProfilePolicyConnector()
+        ->OverrideIsManagedForTesting(true);
+
+    // The AlwaysOnVpnPreConnectUrlAllowlistService keyed service for this
+    // profile needs to be disassociated with the null object so that a new
+    // instance of the service is created.
+    ash::AlwaysOnVpnPreConnectUrlAllowlistServiceFactory::GetInstance()
+        ->RecreateServiceInstanceForTesting(browser()->profile());
+
+    // The service should be created for a managed profile.
+    ASSERT_TRUE(
+        ash::AlwaysOnVpnPreConnectUrlAllowlistServiceFactory::GetForProfile(
+            browser()->profile()));
   }
 
   void TearDownOnMainThread() override {
@@ -67,90 +84,6 @@
         ->SetServiceIsNULLWhileTestingForTesting(
             /*service_is_null_while_testing=*/true);
   }
-};
-
-IN_PROC_BROWSER_TEST_F(AlwaysOnVpnPreConnectUrlAllowlistServiceTest,
-                       NoServiceForUnmanagedProfiles) {
-  // The service should be null because the profile is not managed.
-  EXPECT_FALSE(
-      ash::AlwaysOnVpnPreConnectUrlAllowlistServiceFactory::GetForProfile(
-          browser()->profile()));
-}
-
-IN_PROC_BROWSER_TEST_F(AlwaysOnVpnPreConnectUrlAllowlistServiceTest,
-                       NoServiceForSecondaryProfiles) {
-  // Create a secondary managed profile.
-  TestingProfile::Builder profile_builder;
-  profile_builder.OverridePolicyConnectorIsManagedForTesting(
-      /*is_managed*/ true);
-  std::unique_ptr<TestingProfile> managed_profile = profile_builder.Build();
-
-  EXPECT_FALSE(
-      ash::AlwaysOnVpnPreConnectUrlAllowlistServiceFactory::GetForProfile(
-          browser()->profile()));
-}
-
-class AlwaysOnVpnPreConnectUrlAllowlistServiceManagedProfileTest
-    : public AlwaysOnVpnPreConnectUrlAllowlistServiceTest {
- public:
-  AlwaysOnVpnPreConnectUrlAllowlistServiceManagedProfileTest() = default;
-  AlwaysOnVpnPreConnectUrlAllowlistServiceManagedProfileTest(
-      const AlwaysOnVpnPreConnectUrlAllowlistServiceManagedProfileTest&) =
-      delete;
-  AlwaysOnVpnPreConnectUrlAllowlistServiceManagedProfileTest& operator=(
-      const AlwaysOnVpnPreConnectUrlAllowlistServiceManagedProfileTest&) =
-      delete;
-  ~AlwaysOnVpnPreConnectUrlAllowlistServiceManagedProfileTest() override =
-      default;
-
-  void SetUpOnMainThread() override {
-    AlwaysOnVpnPreConnectUrlAllowlistServiceTest::SetUpOnMainThread();
-    network_handler_test_helper_ =
-        std::make_unique<::ash::NetworkHandlerTestHelper>();
-    ShillServiceClient::Get()->GetTestInterface()->SetServiceProperty(
-        "/service/wifi1", shill::kStateProperty,
-        base::Value(shill::kStateIdle));
-
-    // Create a primary managed profile.
-    fake_user_manager_.Reset(std::make_unique<ash::FakeChromeUserManager>());
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    TestingProfile::Builder profile_builder;
-    profile_builder.SetPath(temp_dir_.GetPath().AppendASCII(
-        BrowserContextHelper::GetUserBrowserContextDirName(
-            user_manager::FakeUserManager::GetFakeUsernameHash(
-                AccountId::FromUserEmail(kFakePrimaryUsername)))));
-    profile_builder.SetProfileName(kFakePrimaryUsername);
-    profile_builder.OverridePolicyConnectorIsManagedForTesting(
-        /*is_managed*/ true);
-
-    managed_profile_ = profile_builder.Build();
-    primary_account_id_ =
-        AccountId::FromUserEmail(managed_profile_->GetProfileUserName());
-    const user_manager::User* user =
-        fake_user_manager_->AddPublicAccountUser(primary_account_id_);
-    fake_user_manager_->UserLoggedIn(primary_account_id_, user->username_hash(),
-                                     false /* browser_restart */,
-                                     false /* is_child */);
-    fake_user_manager_->SetIsCurrentUserNew(/*is_new=*/true);
-
-    // The AlwaysOnVpnPreConnectUrlAllowlistService keyed service for this
-    // profile needs to be disassociated with the null object so that a new
-    // instance of the service is created.
-    ash::AlwaysOnVpnPreConnectUrlAllowlistServiceFactory::GetInstance()
-        ->RecreateServiceInstanceForTesting(managed_profile_.get());
-
-    // The service should be created for a managed profile.
-    ASSERT_TRUE(
-        ash::AlwaysOnVpnPreConnectUrlAllowlistServiceFactory::GetForProfile(
-            managed_profile()));
-  }
-
-  void TearDownOnMainThread() override {
-    fake_user_manager_->RemoveUserFromList(primary_account_id_);
-    managed_profile_.reset();
-    fake_user_manager_.Reset();
-    AlwaysOnVpnPreConnectUrlAllowlistServiceTest::TearDownOnMainThread();
-  }
 
  protected:
   void SetVpnConnectionState(bool vpn_enabled) {
@@ -179,49 +112,59 @@
               ash::NetworkState::NetworkTechnologyType::kVPN);
     base::Value::List list;
     list.Append(kTestUrl);
-    managed_profile()->GetPrefs()->SetList(
+    browser()->profile()->GetPrefs()->SetList(
         policy::policy_prefs::kAlwaysOnVpnPreConnectUrlAllowlist,
         std::move(list));
-    managed_profile()->GetPrefs()->SetBoolean(arc::prefs::kAlwaysOnVpnLockdown,
-                                              true);
+    browser()->profile()->GetPrefs()->SetBoolean(
+        arc::prefs::kAlwaysOnVpnLockdown, true);
   }
 
   bool IsPreConnectListEnforced() {
     return ash::AlwaysOnVpnPreConnectUrlAllowlistServiceFactory::GetForProfile(
-               managed_profile())
+               browser()->profile())
         ->enforce_alwayson_pre_connect_url_allowlist();
   }
 
-  Profile* managed_profile() { return managed_profile_.get(); }
-
  private:
   std::unique_ptr<::ash::NetworkHandlerTestHelper> network_handler_test_helper_;
   std::unique_ptr<AlwaysOnVpnPreConnectUrlAllowlistService>
       alwayson_vpn_pre_connect_url_allowlist_service_;
-  std::unique_ptr<TestingProfile> managed_profile_;
 
-  base::ScopedTempDir temp_dir_;
-  user_manager::TypedScopedUserManager<ash::FakeChromeUserManager>
-      fake_user_manager_;
-  AccountId primary_account_id_;
 };
 
 // Ensure that the local state pref kEnforceAlwaysOnVpnPreConnectUrlAllowlist is
 // true when the kAlwaysOnVpnPreConnectUrlAllowlist is set but the AlwaysOn VPN
 // is not yet connected.
-IN_PROC_BROWSER_TEST_F(
-    AlwaysOnVpnPreConnectUrlAllowlistServiceManagedProfileTest,
-    PreConnectListEnabled) {
+IN_PROC_BROWSER_TEST_F(AlwaysOnVpnPreConnectUrlAllowlistServiceTest,
+                       PreConnectListEnabled) {
   EXPECT_FALSE(IsPreConnectListEnforced());
   CreatePreConnectListEnv();
   EXPECT_TRUE(IsPreConnectListEnforced());
 }
 
 // Ensure that the local state pref kEnforceAlwaysOnVpnPreConnectUrlAllowlist is
+// also enforced for incognito profiles.
+IN_PROC_BROWSER_TEST_F(AlwaysOnVpnPreConnectUrlAllowlistServiceTest,
+                       IncognitoModePreConnectListEnabled) {
+  EXPECT_FALSE(IsPreConnectListEnforced());
+  CreatePreConnectListEnv();
+
+  // Create an incognito profile.
+  Profile* incognito_profile =
+      browser()->profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true);
+
+  AlwaysOnVpnPreConnectUrlAllowlistService* service =
+      ash::AlwaysOnVpnPreConnectUrlAllowlistServiceFactory::GetForProfile(
+          incognito_profile);
+  ASSERT_THAT(service, testing::NotNull());
+
+  EXPECT_TRUE(service->enforce_alwayson_pre_connect_url_allowlist());
+}
+
+// Ensure that the local state pref kEnforceAlwaysOnVpnPreConnectUrlAllowlist is
 // false when the VPN is connected.
-IN_PROC_BROWSER_TEST_F(
-    AlwaysOnVpnPreConnectUrlAllowlistServiceManagedProfileTest,
-    VpnConnected) {
+IN_PROC_BROWSER_TEST_F(AlwaysOnVpnPreConnectUrlAllowlistServiceTest,
+                       VpnConnected) {
   CreatePreConnectListEnv();
   EXPECT_TRUE(IsPreConnectListEnforced());
 
@@ -237,22 +180,21 @@
 
 // Ensure that the local state pref kEnforceAlwaysOnVpnPreConnectUrlAllowlist is
 // false when the kAlwaysOnVpnPreConnectUrlAllowlist pref is not set.
-IN_PROC_BROWSER_TEST_F(
-    AlwaysOnVpnPreConnectUrlAllowlistServiceManagedProfileTest,
-    AlwaysOnVpnPreConnectUrlAllowlistEmpty) {
+IN_PROC_BROWSER_TEST_F(AlwaysOnVpnPreConnectUrlAllowlistServiceTest,
+                       AlwaysOnVpnPreConnectUrlAllowlistEmpty) {
   CreatePreConnectListEnv();
   EXPECT_TRUE(IsPreConnectListEnforced());
 
   // Create and set an empty list.
   base::Value::List list;
-  managed_profile()->GetPrefs()->SetList(
+  browser()->profile()->GetPrefs()->SetList(
       policy::policy_prefs::kAlwaysOnVpnPreConnectUrlAllowlist, list.Clone());
   EXPECT_FALSE(IsPreConnectListEnforced());
 
   // Set a value for the kAlwaysOnVpnPreConnectUrlAllowlist pref again and
   // verify that the pre-connect list is again enforced.
   list.Append(kTestUrl);
-  managed_profile()->GetPrefs()->SetList(
+  browser()->profile()->GetPrefs()->SetList(
       policy::policy_prefs::kAlwaysOnVpnPreConnectUrlAllowlist,
       std::move(list));
   EXPECT_TRUE(IsPreConnectListEnforced());
@@ -260,22 +202,35 @@
 
 // Ensure that the local state pref kEnforceAlwaysOnVpnPreConnectUrlAllowlist is
 // false when the VPN is not in lockdown mode.
-IN_PROC_BROWSER_TEST_F(
-    AlwaysOnVpnPreConnectUrlAllowlistServiceManagedProfileTest,
-    AlwaysOnVpnFalse) {
+IN_PROC_BROWSER_TEST_F(AlwaysOnVpnPreConnectUrlAllowlistServiceTest,
+                       AlwaysOnVpnFalse) {
   CreatePreConnectListEnv();
   EXPECT_TRUE(IsPreConnectListEnforced());
 
   // Remove lockdown mode.
-  managed_profile()->GetPrefs()->SetBoolean(arc::prefs::kAlwaysOnVpnLockdown,
-                                            false);
+  browser()->profile()->GetPrefs()->SetBoolean(arc::prefs::kAlwaysOnVpnLockdown,
+                                               false);
   EXPECT_FALSE(IsPreConnectListEnforced());
 
   // Set lockdown mode and verify that the pre-connect list is again
   // enforced.
-  managed_profile()->GetPrefs()->SetBoolean(arc::prefs::kAlwaysOnVpnLockdown,
-                                            true);
+  browser()->profile()->GetPrefs()->SetBoolean(arc::prefs::kAlwaysOnVpnLockdown,
+                                               true);
   EXPECT_TRUE(IsPreConnectListEnforced());
 }
 
+IN_PROC_BROWSER_TEST_F(AlwaysOnVpnPreConnectUrlAllowlistServiceTest,
+                       NoEnforcementForSecondaryProfiles) {
+  // Create a secondary managed profile.
+  TestingProfile::Builder profile_builder;
+  profile_builder.OverridePolicyConnectorIsManagedForTesting(
+      /*is_managed*/ true);
+  std::unique_ptr<TestingProfile> managed_profile = profile_builder.Build();
+
+  EXPECT_FALSE(
+      ash::AlwaysOnVpnPreConnectUrlAllowlistServiceFactory::GetForProfile(
+          managed_profile.get())
+          ->enforce_alwayson_pre_connect_url_allowlist());
+}
+
 }  // namespace ash
diff --git a/chrome/browser/ash/net/alwayson_vpn_pre_connect_url_allowlist_service_factory.cc b/chrome/browser/ash/net/alwayson_vpn_pre_connect_url_allowlist_service_factory.cc
index 9dbb4d0..db9bc0b 100644
--- a/chrome/browser/ash/net/alwayson_vpn_pre_connect_url_allowlist_service_factory.cc
+++ b/chrome/browser/ash/net/alwayson_vpn_pre_connect_url_allowlist_service_factory.cc
@@ -43,11 +43,7 @@
     : ProfileKeyedServiceFactory(
           "AlwaysOnVpnPreConnectUrlAllowlistService",
           ProfileSelections::Builder()
-              .WithRegular(ProfileSelection::kOriginalOnly)
-              .WithGuest(ProfileSelection::kOriginalOnly)
-              // TODO(crbug.com/41488885): Check if this service is needed for
-              // Ash Internals.
-              .WithAshInternals(ProfileSelection::kOriginalOnly)
+              .WithRegular(ProfileSelection::kOwnInstance)
               .Build()) {}
 
 AlwaysOnVpnPreConnectUrlAllowlistServiceFactory::
@@ -56,13 +52,8 @@
 std::unique_ptr<KeyedService> AlwaysOnVpnPreConnectUrlAllowlistServiceFactory::
     BuildServiceInstanceForBrowserContext(
         content::BrowserContext* context) const {
-  Profile* profile = Profile::FromBrowserContext(context);
-  if (!user_manager::UserManager::Get()->IsPrimaryUser(
-          ash::BrowserContextHelper::Get()->GetUserByBrowserContext(context)) ||
-      !profile->GetProfilePolicyConnector()->IsManaged()) {
-    return nullptr;
-  }
-  return std::make_unique<AlwaysOnVpnPreConnectUrlAllowlistService>(profile);
+  return std::make_unique<AlwaysOnVpnPreConnectUrlAllowlistService>(
+      Profile::FromBrowserContext(context));
 }
 
 bool AlwaysOnVpnPreConnectUrlAllowlistServiceFactory::
diff --git a/chrome/browser/ash/policy/handlers/BUILD.gn b/chrome/browser/ash/policy/handlers/BUILD.gn
index c14fdc5..e07256f 100644
--- a/chrome/browser/ash/policy/handlers/BUILD.gn
+++ b/chrome/browser/ash/policy/handlers/BUILD.gn
@@ -32,8 +32,6 @@
     "device_wifi_allowed_handler.h",
     "help_me_read_policy_handler.cc",
     "help_me_read_policy_handler.h",
-    "lacros_availability_policy_handler.cc",
-    "lacros_availability_policy_handler.h",
     "lacros_selection_policy_handler.cc",
     "lacros_selection_policy_handler.h",
     "lock_to_single_user_manager.cc",
diff --git a/chrome/browser/ash/policy/handlers/lacros_availability_policy_handler.cc b/chrome/browser/ash/policy/handlers/lacros_availability_policy_handler.cc
deleted file mode 100644
index 8194d96a..0000000
--- a/chrome/browser/ash/policy/handlers/lacros_availability_policy_handler.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/policy/handlers/lacros_availability_policy_handler.h"
-
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
-#error This file shall only be used in ash.
-#endif
-
-#include "chrome/common/pref_names.h"
-#include "components/policy/core/browser/policy_error_map.h"
-#include "components/policy/policy_constants.h"
-#include "components/prefs/pref_value_map.h"
-#include "components/strings/grit/components_strings.h"
-
-namespace policy {
-
-LacrosAvailabilityPolicyHandler::LacrosAvailabilityPolicyHandler()
-    : TypeCheckingPolicyHandler(key::kLacrosAvailability,
-                                base::Value::Type::STRING) {}
-
-LacrosAvailabilityPolicyHandler::~LacrosAvailabilityPolicyHandler() = default;
-
-bool LacrosAvailabilityPolicyHandler::CheckPolicySettings(
-    const PolicyMap& policies,
-    PolicyErrorMap* errors) {
-  return GetValue(policies, errors).has_value();
-}
-
-void LacrosAvailabilityPolicyHandler::ApplyPolicySettings(
-    const PolicyMap& policies,
-    PrefValueMap* prefs) {
-  auto enum_value = GetValue(policies, nullptr);
-  if (enum_value.has_value()) {
-    prefs->SetInteger(prefs::kLacrosLaunchSwitch,
-                      static_cast<int>(*enum_value));
-  }
-}
-
-std::optional<ash::standalone_browser::LacrosAvailability>
-LacrosAvailabilityPolicyHandler::GetValue(const PolicyMap& policies,
-                                          PolicyErrorMap* errors) {
-  const base::Value* value;
-  const bool value_found = CheckAndGetValue(policies, errors, &value) && value;
-  if (!value_found)
-    return std::nullopt;
-
-  auto parsed =
-      ash::standalone_browser::ParseLacrosAvailability(value->GetString());
-  if (!parsed.has_value() && errors)
-    errors->AddError(policy_name(), IDS_POLICY_INVALID_SELECTION_ERROR,
-                     "LacrosAvailabilty value");
-  return parsed;
-}
-
-}  // namespace policy
diff --git a/chrome/browser/ash/policy/handlers/lacros_availability_policy_handler.h b/chrome/browser/ash/policy/handlers/lacros_availability_policy_handler.h
deleted file mode 100644
index e876e89..0000000
--- a/chrome/browser/ash/policy/handlers/lacros_availability_policy_handler.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ASH_POLICY_HANDLERS_LACROS_AVAILABILITY_POLICY_HANDLER_H_
-#define CHROME_BROWSER_ASH_POLICY_HANDLERS_LACROS_AVAILABILITY_POLICY_HANDLER_H_
-
-#include <optional>
-
-#include "build/buildflag.h"
-#include "build/chromeos_buildflags.h"
-#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
-#include "components/policy/core/browser/configuration_policy_handler.h"
-
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
-#error This file shall only be used in ash.
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
-class PrefValueMap;
-
-namespace policy {
-
-class PolicyMap;
-
-class LacrosAvailabilityPolicyHandler : public TypeCheckingPolicyHandler {
- public:
-  LacrosAvailabilityPolicyHandler();
-
-  ~LacrosAvailabilityPolicyHandler() override;
-
-  // ConfigurationPolicyHandler:
-  bool CheckPolicySettings(const PolicyMap& policies,
-                           PolicyErrorMap* errors) override;
-
-  void ApplyPolicySettings(const PolicyMap& policies,
-                           PrefValueMap* prefs) override;
-
- private:
-  std::optional<ash::standalone_browser::LacrosAvailability> GetValue(
-      const PolicyMap& policies,
-      PolicyErrorMap* errors);
-};
-
-}  // namespace policy
-
-#endif  // CHROME_BROWSER_ASH_POLICY_HANDLERS_LACROS_AVAILABILITY_POLICY_HANDLER_H_
diff --git a/chrome/browser/ash/preferences/preferences.cc b/chrome/browser/ash/preferences/preferences.cc
index cd1bdce..4bbeff12 100644
--- a/chrome/browser/ash/preferences/preferences.cc
+++ b/chrome/browser/ash/preferences/preferences.cc
@@ -59,7 +59,6 @@
 #include "chromeos/ash/components/peripheral_notification/peripheral_notification_manager.h"
 #include "chromeos/ash/components/settings/cros_settings.h"
 #include "chromeos/ash/components/settings/cros_settings_names.h"
-#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
 #include "chromeos/ash/components/standalone_browser/lacros_selection.h"
 #include "chromeos/ash/components/system/statistics_provider.h"
 #include "chromeos/ash/components/timezone/timezone_resolver.h"
@@ -155,10 +154,6 @@
       enterprise_management::SystemTimezoneProto::USERS_DECIDE);
   registry->RegisterStringPref(::prefs::kMinimumAllowedChromeVersion, "");
   registry->RegisterIntegerPref(
-      ::prefs::kLacrosLaunchSwitch,
-      static_cast<int>(
-          ash::standalone_browser::LacrosAvailability::kUserChoice));
-  registry->RegisterIntegerPref(
       ::prefs::kLacrosSelection,
       static_cast<int>(
           ash::standalone_browser::LacrosSelectionPolicy::kUserChoice));
diff --git a/chrome/browser/ash/scanner/chrome_scanner_delegate.cc b/chrome/browser/ash/scanner/chrome_scanner_delegate.cc
index 0a22481..8613ad8 100644
--- a/chrome/browser/ash/scanner/chrome_scanner_delegate.cc
+++ b/chrome/browser/ash/scanner/chrome_scanner_delegate.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/public/cpp/scanner/scanner_feedback_info.h"
 #include "ash/public/cpp/scanner/scanner_profile_scoped_delegate.h"
 #include "ash/scanner/scanner_controller.h"
 #include "chrome/browser/ash/scanner/scanner_keyed_service_factory.h"
@@ -21,7 +22,8 @@
       ProfileManager::GetActiveUserProfile());
 }
 
-void ChromeScannerDelegate::OpenFeedbackDialog() {
-  auto* dialog = new ash::ScannerFeedbackDialog();
+void ChromeScannerDelegate::OpenFeedbackDialog(
+    ash::ScannerFeedbackInfo feedback_info) {
+  auto* dialog = new ash::ScannerFeedbackDialog(std::move(feedback_info));
   dialog->ShowSystemDialog();
 }
diff --git a/chrome/browser/ash/scanner/chrome_scanner_delegate.h b/chrome/browser/ash/scanner/chrome_scanner_delegate.h
index 5ac6280..3b0faefe 100644
--- a/chrome/browser/ash/scanner/chrome_scanner_delegate.h
+++ b/chrome/browser/ash/scanner/chrome_scanner_delegate.h
@@ -22,7 +22,7 @@
 
   // ash::ScannerDelegate:
   ash::ScannerProfileScopedDelegate* GetProfileScopedDelegate() override;
-  void OpenFeedbackDialog() override;
+  void OpenFeedbackDialog(ash::ScannerFeedbackInfo feedback_info) override;
 };
 
 #endif  // CHROME_BROWSER_ASH_SCANNER_CHROME_SCANNER_DELEGATE_H_
diff --git a/chrome/browser/ash/settings/about_flags.cc b/chrome/browser/ash/settings/about_flags.cc
index af874bd..25ced7d 100644
--- a/chrome/browser/ash/settings/about_flags.cc
+++ b/chrome/browser/ash/settings/about_flags.cc
@@ -20,7 +20,6 @@
 #include "chromeos/ash/components/cryptohome/cryptohome_parameters.h"
 #include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
 #include "chromeos/ash/components/settings/cros_settings_names.h"
-#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
 #include "components/account_id/account_id.h"
 #include "components/flags_ui/flags_storage.h"
 #include "components/flags_ui/flags_ui_pref_names.h"
@@ -205,43 +204,10 @@
   if (!primary_user || primary_user != user_manager->GetActiveUser())
     return;
 
-  std::set<std::string> flags = flags_;
-
-  // If LacrosAvailability policy is set, inject it into the feature flag,
-  // so that the value is preserved on restarting the Chrome.
-  // This is a kind of pseudo feature flag, so do not apply it in
-  // ApplyUserPolicyToFlags to store in |flags_|, otherwise the value will
-  // be used to decide whether or not to reboot to apply feature flags.
-  const PrefService::Preference* lacros_launch_switch_pref =
-      g_browser_process->local_state()->FindPreference(
-          ::prefs::kLacrosLaunchSwitch);
-  if (lacros_launch_switch_pref->IsManaged()) {
-    // If there's the value, convert it into the feature name.
-    std::string_view value =
-        ash::standalone_browser::GetLacrosAvailabilityPolicyName(
-            static_cast<ash::standalone_browser::LacrosAvailability>(
-                lacros_launch_switch_pref->GetValue()->GetInt()));
-    DCHECK(!value.empty())
-        << "The unexpect value is set to LacrosAvailability: "
-        << lacros_launch_switch_pref->GetValue()->GetInt();
-    auto* entry = ::about_flags::GetCurrentFlagsState()->FindFeatureEntryByName(
-        ash::standalone_browser::kLacrosAvailabilityPolicyInternalName);
-    DCHECK(entry);
-    int index;
-    for (index = 0; index < entry->NumOptions(); ++index) {
-      if (value == entry->ChoiceForOption(index).command_line_value)
-        break;
-    }
-    if (static_cast<size_t>(index) != entry->choices.size()) {
-      LOG(ERROR) << "Updating the lacros_availability: " << index;
-      flags.insert(entry->NameForOption(index));
-    }
-  }
-
   auto account_id = cryptohome::CreateAccountIdentifierFromAccountId(
       primary_user->GetAccountId());
   SessionManagerClient::Get()->SetFeatureFlagsForUser(
-      account_id, {flags.begin(), flags.end()}, origin_list_flags_);
+      account_id, {flags_.begin(), flags_.end()}, origin_list_flags_);
 }
 
 // static
diff --git a/chrome/browser/ash/system_web_apps/apps/projector_app/untrusted_projector_ui_config.cc b/chrome/browser/ash/system_web_apps/apps/projector_app/untrusted_projector_ui_config.cc
index 220fe05..5f18f89 100644
--- a/chrome/browser/ash/system_web_apps/apps/projector_app/untrusted_projector_ui_config.cc
+++ b/chrome/browser/ash/system_web_apps/apps/projector_app/untrusted_projector_ui_config.cc
@@ -37,6 +37,8 @@
   source->AddBoolean("isDynamicColorsEnabled",
                      ash::features::IsProjectorDynamicColorsEnabled());
   source->AddBoolean("isGm3Enabled", ash::features::IsProjectorGm3Enabled());
+  source->AddBoolean("useDvsPlaybackEndpoint",
+                     ash::features::IsProjectorUseDVSPlaybackEndpointEnabled());
 
   source->AddBoolean(
       "isInternalServerSideSpeechRecognitionEnabled",
diff --git a/chrome/browser/autofill/autofill_offer_manager_factory.cc b/chrome/browser/autofill/autofill_offer_manager_factory.cc
index 0e0ad39..00f4190 100644
--- a/chrome/browser/autofill/autofill_offer_manager_factory.cc
+++ b/chrome/browser/autofill/autofill_offer_manager_factory.cc
@@ -7,6 +7,7 @@
 #include "base/no_destructor.h"
 #include "build/build_config.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
+#include "components/autofill/core/browser/data_manager/personal_data_manager.h"
 #include "components/autofill/core/browser/payments/autofill_offer_manager.h"
 
 namespace autofill {
@@ -45,7 +46,8 @@
 AutofillOfferManagerFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   return std::make_unique<AutofillOfferManager>(
-      PersonalDataManagerFactory::GetForBrowserContext(context));
+      &PersonalDataManagerFactory::GetForBrowserContext(context)
+           ->payments_data_manager());
 }
 
 }  // namespace autofill
diff --git a/chrome/browser/browsing_data/browsing_data_model_browsertest.cc b/chrome/browser/browsing_data/browsing_data_model_browsertest.cc
index 647f85c..5eb104de 100644
--- a/chrome/browser/browsing_data/browsing_data_model_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_model_browsertest.cc
@@ -480,14 +480,7 @@
       public ::testing::WithParamInterface<bool> {
  public:
   BrowsingDataModelBrowserTest() {
-    auto& field_trial_param =
-        network::features::kTrustTokenOperationsRequiringOriginTrial;
     std::vector<FeatureRefAndParams> enabled_features = {
-        {network::features::kPrivateStateTokens,
-         {{field_trial_param.name,
-           field_trial_param.GetName(
-               network::features::TrustTokenOriginTrialSpec::
-                   kOriginTrialNotRequired)}}},
         {features::kPrivacySandboxAdsAPIsOverride, {}},
         {features::kIsolatedWebApps, {}},
         {features::kIsolatedWebAppDevMode, {}},
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index 5fa8ce6..548ba93 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -306,6 +306,7 @@
 #include "ash/webui/recorder_app_ui/recorder_app_ui.h"
 #include "ash/webui/sanitize_ui/mojom/sanitize_ui.mojom.h"
 #include "ash/webui/sanitize_ui/sanitize_ui.h"
+#include "ash/webui/scanner_feedback_ui/mojom/scanner_feedback_ui.mojom.h"
 #include "ash/webui/scanner_feedback_ui/scanner_feedback_untrusted_ui.h"
 #include "ash/webui/scanning/mojom/scanning.mojom.h"
 #include "ash/webui/scanning/scanning_ui.h"
@@ -1795,7 +1796,8 @@
       .Add<color_change_listener::mojom::PageHandler>();
 
   registry.ForWebUI<ash::ScannerFeedbackUntrustedUI>()
-      .Add<color_change_listener::mojom::PageHandler>();
+      .Add<color_change_listener::mojom::PageHandler>()
+      .Add<ash::mojom::scanner_feedback_ui::PageHandler>();
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OFFICIAL_BUILD)
diff --git a/chrome/browser/client_hints/client_hints_browsertest.cc b/chrome/browser/client_hints/client_hints_browsertest.cc
index d7d1bfd..058f17d 100644
--- a/chrome/browser/client_hints/client_hints_browsertest.cc
+++ b/chrome/browser/client_hints/client_hints_browsertest.cc
@@ -4801,11 +4801,7 @@
       ui_test_utils::NavigateToURL(otr_browser, without_accept_ch_url()));
 }
 
-// Validate that the updated GREASE algorithm is used by default. The continued
-// support of the old algorithm (which used only semicolon and space) is tested
-// separately below. That functionality will be maintained for a period of time
-// until we are confident in more permutations generated by the updated
-// algorithm.
+// Validate that the updated GREASE algorithm is used by default.
 IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, UpdatedGREASEByDefault) {
   const GURL gurl = accept_ch_url();
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
@@ -4814,29 +4810,6 @@
   ASSERT_TRUE(SawUpdatedGrease(ua_ch_result) && !SawOldGrease(ua_ch_result));
 }
 
-class GreaseFeatureParamOptOutTest : public ClientHintsBrowserTest {
-  // Test that feature param opt outs are able to trigger the old algorithm,
-  // which we will maintain until additional confidence in the permutations of
-  // the new algorithm is attained.
-  void SetUpScopedFeatureList(
-      base::test::ScopedFeatureList& scoped_feature_list) override {
-    std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
-    feature_list->InitFromCommandLine("GreaseUACH:updated_algorithm/false", "");
-    scoped_feature_list.InitWithFeatureList(std::move(feature_list));
-  }
-};
-
-// Checks that the updated GREASE algorithm is not used when explicitly
-// disabled.
-IN_PROC_BROWSER_TEST_F(GreaseFeatureParamOptOutTest,
-                       UpdatedGreaseFeatureParamOptOutTest) {
-  const GURL gurl = accept_ch_url();
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
-  std::string ua_ch_result = main_frame_ua_observed();
-
-  ASSERT_TRUE(SawOldGrease(ua_ch_result));
-}
-
 class XRClientHintsTest : public ClientHintsBrowserTest {
   // Enables ClientHintsXRFormFactor feature in addition to the default ones.
   void SetUpScopedFeatureList(
diff --git a/chrome/browser/collaboration/messaging/messaging_backend_service_factory.cc b/chrome/browser/collaboration/messaging/messaging_backend_service_factory.cc
index 7580412a6..918131c 100644
--- a/chrome/browser/collaboration/messaging/messaging_backend_service_factory.cc
+++ b/chrome/browser/collaboration/messaging/messaging_backend_service_factory.cc
@@ -19,6 +19,7 @@
 #include "components/collaboration/internal/messaging/messaging_backend_service_impl.h"
 #include "components/collaboration/internal/messaging/storage/messaging_backend_store_impl.h"
 #include "components/collaboration/internal/messaging/tab_group_change_notifier_impl.h"
+#include "components/collaboration/public/features.h"
 #include "components/data_sharing/public/features.h"
 #include "components/saved_tab_groups/public/features.h"
 #include "components/saved_tab_groups/public/tab_group_sync_service.h"
@@ -62,7 +63,8 @@
   // to be enabled.
   if (!base::FeatureList::IsEnabled(
           data_sharing::features::kDataSharingFeature) ||
-      !tab_groups::IsTabGroupSyncEnabled(profile->GetPrefs())) {
+      !tab_groups::IsTabGroupSyncEnabled(profile->GetPrefs()) ||
+      !base::FeatureList::IsEnabled(kCollaborationMessaging)) {
     return std::make_unique<EmptyMessagingBackendService>();
   }
 
diff --git a/chrome/browser/component_updater/trust_token_key_commitments_component_installer.cc b/chrome/browser/component_updater/trust_token_key_commitments_component_installer.cc
index 8d55739..55a39e2 100644
--- a/chrome/browser/component_updater/trust_token_key_commitments_component_installer.cc
+++ b/chrome/browser/component_updater/trust_token_key_commitments_component_installer.cc
@@ -7,13 +7,11 @@
 #include <memory>
 #include <string>
 
-#include "base/feature_list.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/logging.h"
 #include "components/component_updater/installer_policies/trust_token_key_commitments_component_installer_policy.h"
 #include "content/public/browser/network_service_instance.h"
-#include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/network_service.mojom.h"
 
 using component_updater::ComponentUpdateService;
@@ -22,11 +20,6 @@
 
 void RegisterTrustTokenKeyCommitmentsComponentIfTrustTokensEnabled(
     ComponentUpdateService* cus) {
-  if (!base::FeatureList::IsEnabled(network::features::kPrivateStateTokens) &&
-      !base::FeatureList::IsEnabled(network::features::kFledgePst)) {
-    return;
-  }
-
   VLOG(1) << "Registering Trust Token Key Commitments component.";
   auto installer = base::MakeRefCounted<ComponentInstaller>(
       std::make_unique<TrustTokenKeyCommitmentsComponentInstallerPolicy>(
diff --git a/chrome/browser/component_updater/trust_token_key_commitments_component_installer_unittest.cc b/chrome/browser/component_updater/trust_token_key_commitments_component_installer_unittest.cc
deleted file mode 100644
index 8a77e94..0000000
--- a/chrome/browser/component_updater/trust_token_key_commitments_component_installer_unittest.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/component_updater/trust_token_key_commitments_component_installer.h"
-
-#include "base/files/scoped_temp_dir.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/test/task_environment.h"
-#include "components/component_updater/mock_component_updater_service.h"
-#include "services/network/public/cpp/features.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace component_updater {
-
-namespace {
-using ::testing::_;
-}  // namespace
-
-class TrustTokenKeyCommitmentsComponentInstallerTest : public ::testing::Test {
- public:
-  TrustTokenKeyCommitmentsComponentInstallerTest() = default;
-
- protected:
-  base::test::TaskEnvironment env_;
-};
-
-TEST_F(TrustTokenKeyCommitmentsComponentInstallerTest, FeatureDisabled) {
-  base::test::ScopedFeatureList scoped_list;
-  scoped_list.InitWithFeatures({}, {network::features::kPrivateStateTokens,
-                                    network::features::kFledgePst});
-  auto service =
-      std::make_unique<component_updater::MockComponentUpdateService>();
-  EXPECT_CALL(*service, RegisterComponent(_)).Times(0);
-  RegisterTrustTokenKeyCommitmentsComponentIfTrustTokensEnabled(service.get());
-
-  env_.RunUntilIdle();
-}
-
-}  // namespace component_updater
diff --git a/chrome/browser/extensions/account_extension_tracker.cc b/chrome/browser/extensions/account_extension_tracker.cc
index 7650b1ec..dc838b0 100644
--- a/chrome/browser/extensions/account_extension_tracker.cc
+++ b/chrome/browser/extensions/account_extension_tracker.cc
@@ -110,13 +110,8 @@
 
 void AccountExtensionTracker::SetAccountExtensionTypeOnExtensionInstalled(
     const Extension& extension) {
-  syncer::SyncService* sync_service =
-      SyncServiceFactory::GetForProfile(profile_);
-  bool extension_sync_enabled =
-      sync_service && sync_service->GetUserSettings()->GetSelectedTypes().Has(
-                          syncer::UserSelectableType::kExtensions);
-  bool is_syncable_extension =
-      ExtensionSyncService::IsSyncableExtension(profile_, extension);
+  bool extension_sync_enabled = sync_util::IsSyncingExtensionsEnabled(profile_);
+  bool is_syncable_extension = sync_util::ShouldSync(profile_, &extension);
 
   // Set to `kAccountInstalledSignedIn` if this is a syncable extension (by
   // ExtensionSyncService) that was installed when a user is signed in and has
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 46531b0..8dd02bd2 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -392,8 +392,6 @@
   (*s_allowlist)
       [::unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled] =
           settings_api::PrefType::kBoolean;
-  (*s_allowlist)[unified_consent::prefs::kPageContentCollectionEnabled] =
-      settings_api::PrefType::kBoolean;
   (*s_allowlist)[::commerce::kPriceEmailNotificationsEnabled] =
       settings_api::PrefType::kBoolean;
 
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
index a7b1526..d959142 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -852,9 +852,7 @@
 
   safe_browsing::RemoteHostInfo::ProtocolType protocol =
       safe_browsing::RemoteHostInfo::UNSPECIFIED;
-  if (base::FeatureList::IsEnabled(
-          safe_browsing::kExtensionTelemetryReportContactedHosts) &&
-      url.SchemeIsHTTPOrHTTPS()) {
+  if (url.SchemeIsHTTPOrHTTPS()) {
     protocol = safe_browsing::RemoteHostInfo::HTTP_HTTPS;
   } else if (url.SchemeIsWSOrWSS()) {
     protocol = safe_browsing::RemoteHostInfo::WEBSOCKET;
diff --git a/chrome/browser/extensions/extension_sync_service.cc b/chrome/browser/extensions/extension_sync_service.cc
index 6798b77..da7bacc 100644
--- a/chrome/browser/extensions/extension_sync_service.cc
+++ b/chrome/browser/extensions/extension_sync_service.cc
@@ -137,17 +137,6 @@
   return ExtensionSyncServiceFactory::GetForBrowserContext(context);
 }
 
-// static
-bool ExtensionSyncService::IsSyncableExtension(
-    content::BrowserContext* browser_context,
-    const Extension& extension) {
-  // Themes are handled by the ThemeSyncableService.
-  return extensions::sync_util::ShouldSync(browser_context, &extension) &&
-         !extension.is_theme() &&
-         !extensions::blocklist_prefs::IsExtensionBlocklisted(
-             extension.id(), ExtensionPrefs::Get(browser_context));
-}
-
 void ExtensionSyncService::SyncExtensionChangeIfNeeded(
     const Extension& extension) {
   if (ignore_updates_ || !ShouldSync(extension)) {
@@ -694,5 +683,11 @@
     return false;
   }
 
-  return IsSyncableExtension(profile_, extension);
+  if (extension.is_theme()) {
+    // Themes are handled by the ThemeSyncableService.
+    return false;
+  }
+
+  // Otherwise, defer to the general extension sync calculation.
+  return extensions::sync_util::ShouldSync(profile_, &extension);
 }
diff --git a/chrome/browser/extensions/extension_sync_service.h b/chrome/browser/extensions/extension_sync_service.h
index d7dbd12..4cb14de 100644
--- a/chrome/browser/extensions/extension_sync_service.h
+++ b/chrome/browser/extensions/extension_sync_service.h
@@ -51,12 +51,6 @@
   // Convenience function to get the ExtensionSyncService for a BrowserContext.
   static ExtensionSyncService* Get(content::BrowserContext* context);
 
-  // Returns whether the given extension is eligible to be synced by this class.
-  // Filters out unsyncable extensions as well as themes (which are handled by
-  // ThemeSyncableService instead).
-  static bool IsSyncableExtension(content::BrowserContext* context,
-                                  const extensions::Extension& extension);
-
   // Notifies Sync (if needed) of a newly-installed extension or a change to
   // an existing extension. Call this when you change an extension setting that
   // is synced as part of ExtensionSyncData (e.g. incognito_enabled).
@@ -130,9 +124,7 @@
       syncer::DataType type,
       std::vector<extensions::ExtensionSyncData>* sync_data_list) const;
 
-  // Returns if the given `extension` should be synced. This differs from
-  // `IsSyncableExtension` which checks if an extension is eligible to be synced
-  // by this class.
+  // Returns if the given `extension` should be synced by this class.
   bool ShouldSync(const extensions::Extension& extension) const;
 
   // The normal profile associated with this ExtensionSyncService.
diff --git a/chrome/browser/extensions/extension_sync_service_unittest.cc b/chrome/browser/extensions/extension_sync_service_unittest.cc
index dadcd20a..9697bfb 100644
--- a/chrome/browser/extensions/extension_sync_service_unittest.cc
+++ b/chrome/browser/extensions/extension_sync_service_unittest.cc
@@ -1913,9 +1913,11 @@
 
 // Test that sync cannot enable blocklisted extensions.
 TEST_F(BlocklistedExtensionSyncServiceTest, SyncBlocklistedExtension) {
-  std::string& extension_id = this->extension_id();
+  // The extension should be syncable before being blocklisted.
+  EXPECT_TRUE(extensions::sync_util::ShouldSync(profile(), extension()));
 
   // Blocklist the extension.
+  std::string& extension_id = this->extension_id();
   test_blocklist().SetBlocklistState(extension_id,
                                      extensions::BLOCKLISTED_MALWARE, true);
   ForceBlocklistUpdate();
@@ -1926,6 +1928,9 @@
   // The extension should not be enabled.
   EXPECT_FALSE(registry()->enabled_extensions().GetByID(extension_id));
   EXPECT_TRUE(processor()->changes().empty());
+
+  // Double check that the extension is not syncable.
+  EXPECT_FALSE(extensions::sync_util::ShouldSync(profile(), extension()));
 }
 
 // Test that some greylisted extensions can be enabled through sync.
diff --git a/chrome/browser/extensions/extension_sync_util.cc b/chrome/browser/extensions/extension_sync_util.cc
index 995ed0d2..7544667 100644
--- a/chrome/browser/extensions/extension_sync_util.cc
+++ b/chrome/browser/extensions/extension_sync_util.cc
@@ -14,6 +14,7 @@
 #include "components/sync/base/features.h"
 #include "components/sync/service/sync_service.h"
 #include "components/sync/service/sync_user_settings.h"
+#include "extensions/browser/blocklist_extension_prefs.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/pref_names.h"
 #include "extensions/common/extension.h"
@@ -35,7 +36,9 @@
     return false;
   }
   return sync_helper::IsSyncable(extension) &&
-         !ExtensionPrefs::Get(context)->DoNotSync(extension->id());
+         !ExtensionPrefs::Get(context)->DoNotSync(extension->id()) &&
+         !extensions::blocklist_prefs::IsExtensionBlocklisted(
+             extension->id(), ExtensionPrefs::Get(context));
 }
 
 bool IsSyncingExtensionsEnabled(Profile* profile) {
diff --git a/chrome/browser/extensions/orb_and_cors_extension_browsertest.cc b/chrome/browser/extensions/orb_and_cors_extension_browsertest.cc
index 9edbcfe..4efbee77 100644
--- a/chrome/browser/extensions/orb_and_cors_extension_browsertest.cc
+++ b/chrome/browser/extensions/orb_and_cors_extension_browsertest.cc
@@ -1268,21 +1268,10 @@
 //
 // (Specifically, this makes sure RFHI is passing the correct factory
 // parameter to URLLoaderFactoryParamsHelper::CreateForIsolatedWorld.)
-class TrustTokenExtensionBrowserTest : public OrbAndCorsExtensionBrowserTest {
- public:
-  TrustTokenExtensionBrowserTest() {
-    scoped_feature_list_.InitAndEnableFeature(
-        network::features::kPrivateStateTokens);
-  }
-
- protected:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
 // TODO(crbug.com/40221677): Have trust tokens handle the existence, or not, of
 // PrivacySandboxSettings3.
 IN_PROC_BROWSER_TEST_F(
-    TrustTokenExtensionBrowserTest,
+    OrbAndCorsExtensionBrowserTest,
     DISABLED_FromProgrammaticContentScript_TrustTokenRedemptionAllowed) {
   // Trust Tokens operations only work on secure origins - set up a https test
   // server to help with this. One alternative would be using a localhost URL
diff --git a/chrome/browser/extensions/user_script_world_configuration_manager_unittest.cc b/chrome/browser/extensions/user_script_world_configuration_manager_unittest.cc
index 5bb189f..7b03fe5 100644
--- a/chrome/browser/extensions/user_script_world_configuration_manager_unittest.cc
+++ b/chrome/browser/extensions/user_script_world_configuration_manager_unittest.cc
@@ -88,9 +88,13 @@
   // Register two different configurations for user script worlds, one for the
   // default world and another for "world 1".
   configuration_manager()->SetUserScriptWorldInfo(
-      *extension, std::nullopt, "script-src: self", /*enable_messaging=*/false);
+      *extension, mojom::UserScriptWorldInfo::New(extension->id(), std::nullopt,
+                                                  "script-src: self",
+                                                  /*enable_messaging=*/false));
   configuration_manager()->SetUserScriptWorldInfo(
-      *extension, "world 1", "script-src: none", /*enable_messaging=*/false);
+      *extension, mojom::UserScriptWorldInfo::New(extension->id(), "world 1",
+                                                  "script-src: none",
+                                                  /*enable_messaging=*/false));
   EXPECT_EQ(
       2u,
       configuration_manager()->GetAllUserScriptWorlds(extension->id()).size());
@@ -119,15 +123,21 @@
 
   // Set configurations for a specified world and the default world for each
   // extension.
-  configuration_manager()->SetUserScriptWorldInfo(*extension1, default_world,
-                                                  csp1, kEnableMessaging);
-  configuration_manager()->SetUserScriptWorldInfo(*extension1, other_world,
-                                                  csp2, kEnableMessaging);
+  configuration_manager()->SetUserScriptWorldInfo(
+      *extension1,
+      mojom::UserScriptWorldInfo::New(extension1->id(), default_world, csp1,
+                                      kEnableMessaging));
+  configuration_manager()->SetUserScriptWorldInfo(
+      *extension1, mojom::UserScriptWorldInfo::New(
+                       extension1->id(), other_world, csp2, kEnableMessaging));
 
-  configuration_manager()->SetUserScriptWorldInfo(*extension2, default_world,
-                                                  csp1, kEnableMessaging);
-  configuration_manager()->SetUserScriptWorldInfo(*extension2, other_world,
-                                                  csp2, kEnableMessaging);
+  configuration_manager()->SetUserScriptWorldInfo(
+      *extension2,
+      mojom::UserScriptWorldInfo::New(extension2->id(), default_world, csp1,
+                                      kEnableMessaging));
+  configuration_manager()->SetUserScriptWorldInfo(
+      *extension2, mojom::UserScriptWorldInfo::New(
+                       extension2->id(), other_world, csp2, kEnableMessaging));
 
   // Verify initial state. Each extension should have those two worlds
   // configured.
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index dc204a3..b4bd4d6 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -4478,6 +4478,11 @@
     "expiry_milestone": 135
   },
   {
+    "name": "fedcm-delegation",
+    "owners": [ "goto@chromium.org", "web-identity-eng@google.com"],
+    "expiry_milestone": 135
+  },
+  {
     "name": "fedcm-idp-registration",
     "owners": [ "goto@chromium.org", "web-identity-eng@google.com"],
     "expiry_milestone": 135
@@ -7041,14 +7046,6 @@
     "expiry_milestone": 130
   },
   {
-    "name": "price-tracking-icon-colors",
-    "owners": [
-      "mdjones@chromium.org",
-      "chrome-shopping-eng@google.com"
-    ],
-    "expiry_milestone": 128
-  },
-  {
     "name": "price-tracking-subscription-service-locale-key",
     "owners": [ "qib@google.com", "chrommerce-eng@google.com" ],
     "expiry_milestone": 135
@@ -7241,6 +7238,11 @@
     "expiry_milestone": 136
   },
   {
+    "name": "projector-use-dvs-playback-endpoint",
+    "owners": ["bzielinski@google.com", "cros-projector@google.com"],
+    "expiry_milestone": 140
+  },
+  {
     "name": "promise-icons",
     "owners": ["vpao@chromium.org", "chromeos-apps-foundation-team@google.com"],
     "expiry_milestone": 130
@@ -8015,11 +8017,6 @@
     "expiry_milestone": 140
   },
   {
-  "name": "shopping-icon-color-variant",
-    "owners": [ "chrome-desktop-ui-sea@google.com" ],
-    "expiry_milestone": 126
-  },
-  {
     "name": "shopping-list",
     "owners": [ "mdjones@chromium.org", "chrome-shopping-eng@google.com" ],
     "expiry_milestone": 122
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 81ee7e7b..af3d197 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1941,6 +1941,10 @@
     "Enables RPs specify whether they want to trigger the FedCM widget flow or "
     "the button flow.";
 
+const char kFedCmDelegationName[] = "FedCM with delegation support";
+const char kFedCmDelegationDescription[] =
+    "Enables IdPs to delegate presentation to the browser.";
+
 const char kFedCmIdPRegistrationName[] = "FedCM with IdP Registration support";
 const char kFedCmIdPRegistrationDescription[] =
     "Enables RPs to get identity credentials from registered IdPs.";
@@ -6936,13 +6940,6 @@
 const char kCrosComponentsDescription[] =
     "Enable cros-component UI elements, replacing other elements.";
 
-const char kLacrosAvailabilityIgnoreName[] =
-    "Ignore lacros-availability policy";
-const char kLacrosAvailabilityIgnoreDescription[] =
-    "Makes the lacros-availability policy have no effect on Google-internal "
-    "accounts. Instead, Lacros availability will be controlled by experiment "
-    "and/or user flags for such accounts.";
-
 const char kLacrosStabilityName[] = "Lacros stability";
 const char kLacrosStabilityDescription[] = "Lacros update channel.";
 
@@ -7178,6 +7175,12 @@
     "Allows Screencast to use the latest model for server side speech "
     "recognition.";
 
+const char kProjectorUseDVSPlaybackEndpointName[] =
+    "Use DVS endpoint in the Screencast app";
+const char kProjectorUseDVSPlaybackEndpointDescription[] =
+    "Use the latest endpoint for retrieving playback urls in the Screencast "
+    "app.";
+
 const char kReleaseNotesNotificationAllChannelsName[] =
     "Release Notes Notification All Channels";
 const char kReleaseNotesNotificationAllChannelsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 6a9aa31..7d5d9b3 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1097,6 +1097,9 @@
 extern const char kFedCmButtonModeName[];
 extern const char kFedCmButtonModeDescription[];
 
+extern const char kFedCmDelegationName[];
+extern const char kFedCmDelegationDescription[];
+
 extern const char kFedCmIdPRegistrationName[];
 extern const char kFedCmIdPRegistrationDescription[];
 
@@ -4037,9 +4040,6 @@
 extern const char kCrosComponentsName[];
 extern const char kCrosComponentsDescription[];
 
-extern const char kLacrosAvailabilityIgnoreName[];
-extern const char kLacrosAvailabilityIgnoreDescription[];
-
 extern const char kLacrosStabilityName[];
 extern const char kLacrosStabilityDescription[];
 
@@ -4172,6 +4172,9 @@
 extern const char kProjectorServerSideUsmName[];
 extern const char kProjectorServerSideUsmDescription[];
 
+extern const char kProjectorUseDVSPlaybackEndpointName[];
+extern const char kProjectorUseDVSPlaybackEndpointDescription[];
+
 extern const char kReleaseNotesNotificationAllChannelsName[];
 extern const char kReleaseNotesNotificationAllChannelsDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 02bd697..ed0ee3f 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -410,7 +410,6 @@
     &tab_groups::kUseAlternateHistorySyncIllustration,
     &visited_url_ranking::features::kVisitedURLRankingService,
     &webapps::features::kWebApkInstallFailureNotification,
-    &network::features::kPrivateStateTokens,
     &base::features::kPostGetMyMemoryStateToBackground,
 };
 
@@ -838,7 +837,7 @@
 
 BASE_FEATURE(kNewTabPageAndroidTriggerForPrerender2,
              "NewTabPageAndroidTriggerForPrerender2",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE(kNotificationPermissionVariant,
              "NotificationPermissionVariant",
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index e818aa6..9db11f2 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -441,7 +441,6 @@
     public static final String PRIVACY_SANDBOX_PRIVACY_GUIDE_AD_TOPICS =
             "PrivacySandboxPrivacyGuideAdTopics";
     public static final String PRIVACY_SANDBOX_PRIVACY_POLICY = "PrivacySandboxPrivacyPolicy";
-    public static final String PRIVATE_STATE_TOKENS = "PrivateStateTokens";
     public static final String PUSH_MESSAGING_DISALLOW_SENDER_IDS =
             "PushMessagingDisallowSenderIDs";
     public static final String PWA_UPDATE_DIALOG_FOR_ICON = "PwaUpdateDialogForIcon";
@@ -696,7 +695,7 @@
     public static final CachedFlag sNavBarColorMatchesTabBackground =
             newCachedFlag(NAV_BAR_COLOR_MATCHES_TAB_BACKGROUND, true);
     public static final CachedFlag sNewTabPageAndroidTriggerForPrerender2 =
-            newCachedFlag(NEW_TAB_PAGE_ANDROID_TRIGGER_FOR_PRERENDER2, false);
+            newCachedFlag(NEW_TAB_PAGE_ANDROID_TRIGGER_FOR_PRERENDER2, true);
     public static final CachedFlag sNotificationTrampoline =
             newCachedFlag(NOTIFICATION_TRAMPOLINE, false);
     public static final CachedFlag sPowerSavingModeBroadcastReceiverInBackground =
diff --git a/chrome/browser/glic/glic_keyed_service.cc b/chrome/browser/glic/glic_keyed_service.cc
index ea81166..b6e22ecc 100644
--- a/chrome/browser/glic/glic_keyed_service.cc
+++ b/chrome/browser/glic/glic_keyed_service.cc
@@ -76,6 +76,14 @@
   return window_controller_->GetSize();
 }
 
+void GlicKeyedService::SetPanelDraggableAreas(
+    const std::vector<gfx::Rect>& draggable_areas) {
+  if (!window_controller_) {
+    return;
+  }
+  window_controller_->SetDraggableAreas(draggable_areas);
+}
+
 void GlicKeyedService::GetContextFromFocusedTab(
     bool include_inner_text,
     bool include_viewport_screenshot,
diff --git a/chrome/browser/glic/glic_keyed_service.h b/chrome/browser/glic/glic_keyed_service.h
index 2ee3ac5..fdb8603 100644
--- a/chrome/browser/glic/glic_keyed_service.h
+++ b/chrome/browser/glic/glic_keyed_service.h
@@ -43,6 +43,7 @@
                  glic::mojom::WebClientHandler::CreateTabCallback callback);
   virtual void ClosePanel();
   std::optional<gfx::Size> ResizePanel(const gfx::Size& size);
+  void SetPanelDraggableAreas(const std::vector<gfx::Rect>& draggable_areas);
 
   void GetContextFromFocusedTab(
       bool include_inner_text,
diff --git a/chrome/browser/glic/glic_window_controller.cc b/chrome/browser/glic/glic_window_controller.cc
index 91c1aaf..9aed5961 100644
--- a/chrome/browser/glic/glic_window_controller.cc
+++ b/chrome/browser/glic/glic_window_controller.cc
@@ -23,6 +23,7 @@
 constexpr static int kSnapDistanceThreshold = 50;
 constexpr static int kWidgetWidth = 400;
 constexpr static int kWidgetHeight = 800;
+constexpr static int kWidgetTopBarHeight = 80;
 
 // Helper class for observing mouse and key events from native window.
 class WindowEventObserver : public ui::EventObserver {
@@ -33,7 +34,8 @@
       : glic_window_controller_(glic_window_controller), glic_view_(glic_view) {
     event_monitor_ = views::EventMonitor::CreateWindowMonitor(
         this, glic_view->GetWidget()->GetNativeWindow(),
-        {ui::EventType::kMouseDragged});
+        {ui::EventType::kMousePressed, ui::EventType::kMouseReleased,
+         ui::EventType::kMouseDragged});
   }
 
   WindowEventObserver(const WindowEventObserver&) = delete;
@@ -41,19 +43,37 @@
   ~WindowEventObserver() override = default;
 
   void OnEvent(const ui::Event& event) override {
-    if (event.IsMouseEvent()) {
-      if (event.type() == ui::EventType::kMouseDragged) {
-        gfx::Point mouse_location = event_monitor_->GetLastMouseLocation();
-        views::View::ConvertPointFromScreen(glic_view_, &mouse_location);
-        glic_window_controller_->DragFromPoint(
-            mouse_location.OffsetFromOrigin());
-      }
+    if (!event.IsMouseEvent()) {
+      return;
+    }
+
+    gfx::Point mouse_location = event_monitor_->GetLastMouseLocation();
+    views::View::ConvertPointFromScreen(glic_view_, &mouse_location);
+    if (event.type() == ui::EventType::kMousePressed &&
+        glic_view_->IsPointWithinDraggableArea(mouse_location)) {
+      mouse_down_in_draggable_area_ = true;
+    }
+
+    if (event.type() == ui::EventType::kMouseReleased ||
+        event.type() == ui::EventType::kMouseExited) {
+      mouse_down_in_draggable_area_ = false;
+    }
+
+    // Window should only be dragged if a corresponding mouse drag event was
+    // initiated in the draggable area.
+    if (mouse_down_in_draggable_area_ &&
+        event.type() == ui::EventType::kMouseDragged) {
+      glic_window_controller_->DragFromPoint(mouse_location.OffsetFromOrigin());
     }
   }
 
   raw_ptr<glic::GlicWindowController> glic_window_controller_;
   raw_ptr<glic::GlicView> glic_view_;
   std::unique_ptr<views::EventMonitor> event_monitor_;
+
+  // Tracks whether the mouse is pressed and was initially within a draggable
+  // area of the window.
+  bool mouse_down_in_draggable_area_;
 };
 
 }  // namespace
@@ -64,7 +84,8 @@
     : profile_(profile) {}
 
 void GlicWindowController::Show(views::View* glic_button_view) {
-  // TODO(crbug.com/379943498): possibly bring to front or activate in this case
+  // TODO(crbug.com/379943498): If a glic window already exists, handle showing
+  // by bringing to front or activating.
   if (widget_) {
     return;
   }
@@ -93,6 +114,8 @@
   widget_->Show();
   window_event_observer_ =
       std::make_unique<WindowEventObserver>(this, glic_view_);
+  // Set the draggable area to the top bar of the window, by default.
+  glic_view_->SetDraggableAreas({{0, 0, kWidgetWidth, kWidgetTopBarHeight}});
 }
 
 gfx::Point GlicWindowController::GetTopRightPositionForAttachedWindow(
@@ -145,6 +168,15 @@
   return widget_->GetSize();
 }
 
+void GlicWindowController::SetDraggableAreas(
+    const std::vector<gfx::Rect>& draggable_areas) {
+  if (!glic_view_) {
+    return;
+  }
+
+  glic_view_->SetDraggableAreas(draggable_areas);
+}
+
 void GlicWindowController::Close() {
   if (!widget_) {
     return;
@@ -177,11 +209,11 @@
   for (Browser* browser : BrowserList::GetInstance()->OrderedByActivation()) {
     views::Widget* window_widget =
         browser->window()->AsBrowserView()->GetWidget();
-    // Skips if:
-    // - incognito
-    // - not visible
-    // - is the same widget as glic
-    // - is a different profile (uses browser context to check)
+    // Skips if the browser:
+    // - is incognito
+    // - is not visible
+    // - uses the same widget as glic
+    // - uses a different profile from glic
     if (browser->profile()->IsOffTheRecord() ||
         !browser->window()->IsVisible() || window_widget == widget_.get() ||
         browser->GetWebView()->GetBrowserContext() !=
@@ -222,7 +254,7 @@
     return;
   }
   gfx::Rect glic_rect = widget_->GetWindowBoundsInScreen();
-  // TODO fix exact snap location
+  // TODO(andreaxg): Fix exact snap location.
   gfx::Rect glic_button_rect = browser->window()
                                    ->AsBrowserView()
                                    ->tab_strip_region_view()
@@ -244,7 +276,7 @@
         views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
     params.activatable = views::Widget::InitParams::Activatable::kNo;
     params.accept_events = false;
-    // Name specified for debug purposes
+    // Widget name is specified for debug purposes.
     params.name = "HolderWindow";
     params.bounds = gfx::Rect(0, 0, 0, 0);
     params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
diff --git a/chrome/browser/glic/glic_window_controller.h b/chrome/browser/glic/glic_window_controller.h
index 64885a4..2c4fa1e 100644
--- a/chrome/browser/glic/glic_window_controller.h
+++ b/chrome/browser/glic/glic_window_controller.h
@@ -43,10 +43,13 @@
   // Returns the current size of the glic window.
   gfx::Size GetSize();
 
+  // Sets the areas of the view from which it should be draggable.
+  void SetDraggableAreas(const std::vector<gfx::Rect>& draggable_areas);
+
   // Called to notify the controller that the window was requested to be closed.
   void Close();
 
-  // User drags glic window
+  // Drags the glic window following the current mouse location.
   void DragFromPoint(gfx::Vector2d mouse_location);
 
   // Returns a WeakPtr to this instance. It can be destroyed at any time if the
@@ -77,7 +80,6 @@
         delete;
     ~PinnedTargetWidgetObserver() override;
     void SetPinnedTargetWidget(views::Widget* widget);
-
     void OnWidgetBoundsChanged(views::Widget* widget,
                                const gfx::Rect& new_bounds) override;
     void OnWidgetDestroying(views::Widget* widget) override;
@@ -94,8 +96,8 @@
   // glic to the top right of the browser's glic button.
   void HandleBrowserPinning(gfx::Vector2d mouse_location);
 
-  // When glic is unpinned, reparent to empty holder widget. Initializes the
-  // empty holder widget if it hasn't been created yet.g
+  // When glic is unpinned, reparent it to an empty holder Widget. Initializes
+  // the empty holder widget if it hasn't been created yet.
   void MaybeCreateHolderWindowAndReparent();
 
   // Moves glic view to the pin target of the specified browser.
diff --git a/chrome/browser/glic/launcher/glic_status_icon.cc b/chrome/browser/glic/launcher/glic_status_icon.cc
index cde9cbe..bb0f792 100644
--- a/chrome/browser/glic/launcher/glic_status_icon.cc
+++ b/chrome/browser/glic/launcher/glic_status_icon.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/status_icons/status_icon_menu_model.h"
 #include "chrome/browser/status_icons/status_tray.h"
 #include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/user_education/common/help_bubble/help_bubble_params.h"
 #include "glic_status_icon.h"
@@ -30,6 +31,11 @@
   status_icon_ = status_tray_->CreateStatusIcon(
       StatusTray::GLIC_ICON, status_tray_icon,
       l10n_util::GetStringUTF16(IDS_GLIC_STATUS_ICON_TOOLTIP));
+#if BUILDFLAG(IS_MAC)
+  if (features::kGlicStatusIconOpenMenuWithSecondaryClick.Get()) {
+    status_icon_->SetOpenMenuWithSecondaryClick(true);
+  }
+#endif
   status_icon_->AddObserver(this);
 
   std::unique_ptr<StatusIconMenuModel> menu = CreateStatusIconMenu();
diff --git a/chrome/browser/k_anonymity_service/k_anonymity_service_client_browsertest.cc b/chrome/browser/k_anonymity_service/k_anonymity_service_client_browsertest.cc
index d24de94..31ce81c 100644
--- a/chrome/browser/k_anonymity_service/k_anonymity_service_client_browsertest.cc
+++ b/chrome/browser/k_anonymity_service/k_anonymity_service_client_browsertest.cc
@@ -81,8 +81,7 @@
     GURL ohttp_relay = https_server_->GetURL("/ohttpRelay");
 
     feature_list_.InitWithFeaturesAndParameters(
-        /*enabled_features=*/{{network::features::kPrivateStateTokens, {}},
-                              {features::kKAnonymityService,
+        /*enabled_features=*/{{features::kKAnonymityService,
                                {{"KAnonymityServiceAuthServer",
                                  https_server_->base_url().spec()},
                                 {"KAnonymityServiceJoinServer",
diff --git a/chrome/browser/k_anonymity_service/k_anonymity_service_client_unittest.cc b/chrome/browser/k_anonymity_service/k_anonymity_service_client_unittest.cc
index 28c43d3a..ee95229 100644
--- a/chrome/browser/k_anonymity_service/k_anonymity_service_client_unittest.cc
+++ b/chrome/browser/k_anonymity_service/k_anonymity_service_client_unittest.cc
@@ -49,7 +49,7 @@
  protected:
   void SetUp() override {
     feature_list_.InitWithFeatures(
-        /*enabled_features=*/{network::features::kPrivateStateTokens},
+        {},
         /*disabled_features=*/{features::kKAnonymityServiceOHTTPRequests});
     TestingProfile::Builder builder;
     builder.SetSharedURLLoaderFactory(
@@ -521,8 +521,7 @@
  protected:
   void SetUp() override {
     feature_list_.InitWithFeaturesAndParameters(
-        {{network::features::kPrivateStateTokens, {}},
-         {features::kKAnonymityService,
+        {{features::kKAnonymityService,
           {
               {"KAnonymityServiceJoinRelayServer", kJoinRelayURL},
               {"KAnonymityServiceQueryRelayServer", kQueryRelayURL},
diff --git a/chrome/browser/k_anonymity_service/k_anonymity_trust_token_getter.cc b/chrome/browser/k_anonymity_service/k_anonymity_trust_token_getter.cc
index 17d808e..6938b75 100644
--- a/chrome/browser/k_anonymity_service/k_anonymity_trust_token_getter.cc
+++ b/chrome/browser/k_anonymity_service/k_anonymity_trust_token_getter.cc
@@ -20,7 +20,6 @@
 #include "mojo/public/cpp/bindings/callback_helpers.h"
 #include "net/base/load_flags.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/simple_url_loader.h"
 
@@ -120,14 +119,11 @@
 
 void KAnonymityTrustTokenGetter::TryGetTrustTokenAndKey(
     TryGetTrustTokenAndKeyCallback callback) {
-  if ((!base::FeatureList::IsEnabled(network::features::kPrivateStateTokens) &&
-       !base::FeatureList::IsEnabled(network::features::kFledgePst)) ||
-      !identity_manager_ ||
+  if (!identity_manager_ ||
       !identity_manager_->HasPrimaryAccount(signin::ConsentLevel::kSignin)) {
     std::move(callback).Run(std::nullopt);
     return;
   }
-
   RecordTrustTokenGetterAction(
       KAnonymityTrustTokenGetterAction::kTryGetTrustTokenAndKey);
   bool currently_fetching = pending_callbacks_.size() > 0;
diff --git a/chrome/browser/k_anonymity_service/k_anonymity_trust_token_getter_unittest.cc b/chrome/browser/k_anonymity_service/k_anonymity_trust_token_getter_unittest.cc
index efec5fd..1e904958 100644
--- a/chrome/browser/k_anonymity_service/k_anonymity_trust_token_getter_unittest.cc
+++ b/chrome/browser/k_anonymity_service/k_anonymity_trust_token_getter_unittest.cc
@@ -66,8 +66,7 @@
  protected:
   void SetUp() override {
     feature_list_.InitWithFeaturesAndParameters(
-        /*enabled_features=*/{{network::features::kPrivateStateTokens, {}},
-                              {features::kKAnonymityService,
+        /*enabled_features=*/{{features::kKAnonymityService,
                                {{"KAnonymityServiceAuthServer", kAuthServer}}}},
         /*disabled_features=*/{});
     TestingProfile::Builder builder;
diff --git a/chrome/browser/media/audio_ducker.cc b/chrome/browser/media/audio_ducker.cc
new file mode 100644
index 0000000..0f2570b
--- /dev/null
+++ b/chrome/browser/media/audio_ducker.cc
@@ -0,0 +1,80 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/audio_ducker.h"
+
+#include "content/public/browser/media_session.h"
+#include "content/public/browser/media_session_service.h"
+
+AudioDucker::AudioDucker(content::Page& page)
+    : content::PageUserData<AudioDucker>(page),
+      content::WebContentsObserver(GetWebContents()) {}
+
+AudioDucker::~AudioDucker() {
+  StopDuckingOtherAudio();
+}
+
+bool AudioDucker::StartDuckingOtherAudio() {
+  if (ducking_state_ == AudioDuckingState::kDucking) {
+    return true;
+  }
+  if (!BindToAudioFocusManagerIfNecessary()) {
+    return false;
+  }
+  StartDuckingImpl();
+  ducking_state_ = AudioDuckingState::kDucking;
+  return true;
+}
+
+bool AudioDucker::StopDuckingOtherAudio() {
+  if (ducking_state_ == AudioDuckingState::kNoDucking) {
+    return true;
+  }
+  if (!BindToAudioFocusManagerIfNecessary()) {
+    return false;
+  }
+  audio_focus_remote_->StopDuckingAllAudio();
+  ducking_state_ = AudioDuckingState::kNoDucking;
+  return true;
+}
+
+void AudioDucker::MediaSessionCreated(content::MediaSession*) {
+  // When a MediaSession is created and we're already ducking, we need to tell
+  // the AudioFocusManager to start ducking again while exempting the new
+  // request ID. This will supercede the previous request and replace it with a
+  // request that has an exempted MediaSession.
+  if (ducking_state_ == AudioDuckingState::kDucking &&
+      BindToAudioFocusManagerIfNecessary()) {
+    StartDuckingImpl();
+  }
+}
+
+void AudioDucker::StartDuckingImpl() {
+  // Null base::UnguessableTokens cannot be passed via mojo, so convert to an
+  // empty optional if the request ID is null.
+  const base::UnguessableToken& request_id =
+      content::MediaSession::GetRequestIdFromWebContents(GetWebContents());
+  std::optional<base::UnguessableToken> optional_request_id;
+  if (!request_id.is_empty()) {
+    optional_request_id = request_id;
+  }
+
+  audio_focus_remote_->StartDuckingAllAudio(optional_request_id);
+}
+
+content::WebContents* AudioDucker::GetWebContents() const {
+  return content::WebContents::FromRenderFrameHost(&page().GetMainDocument());
+}
+
+bool AudioDucker::BindToAudioFocusManagerIfNecessary() {
+  if (audio_focus_remote_.is_bound()) {
+    return true;
+  }
+  content::GetMediaSessionService().BindAudioFocusManager(
+      audio_focus_remote_.BindNewPipeAndPassReceiver());
+  audio_focus_remote_.reset_on_disconnect();
+  return audio_focus_remote_.is_bound();
+}
+
+PAGE_USER_DATA_KEY_IMPL(AudioDucker);
diff --git a/chrome/browser/media/audio_ducker.h b/chrome/browser/media/audio_ducker.h
new file mode 100644
index 0000000..c1dad0a
--- /dev/null
+++ b/chrome/browser/media/audio_ducker.h
@@ -0,0 +1,66 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_AUDIO_DUCKER_H_
+#define CHROME_BROWSER_MEDIA_AUDIO_DUCKER_H_
+
+#include "content/public/browser/page_user_data.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "services/media_session/public/mojom/audio_focus.mojom.h"
+
+// The AudioDucker ducks other audio in Chrome besides what is playing through
+// its associated Page's WebContents.
+//
+// TODO(https://crbug.com/382316461): This should also duck audio from
+// applications other than Chrome.
+class AudioDucker : public content::PageUserData<AudioDucker>,
+                    public content::WebContentsObserver {
+ public:
+  enum class AudioDuckingState {
+    // The AudioDucker is not currently ducking other audio.
+    kNoDucking,
+
+    // The AudioDucker is currently ducking other audio.
+    kDucking,
+  };
+
+  AudioDucker(const AudioDucker&) = delete;
+  AudioDucker& operator=(const AudioDucker&) = delete;
+  ~AudioDucker() override;
+
+  // Ducks all audio in Chrome except audio playback in our associated Page's
+  // WebContents. Returns true if ducking was started successfully or if we're
+  // already ducking.
+  bool StartDuckingOtherAudio();
+
+  // Stops ducking started by `StartDuckingOtherAudio()`. Does nothing if we're
+  // not currently ducking. Returns true if ducking was stopped successfully or
+  // if we're not currently ducking.
+  bool StopDuckingOtherAudio();
+
+  AudioDuckingState GetAudioDuckingState() const { return ducking_state_; }
+
+ private:
+  explicit AudioDucker(content::Page& page);
+
+  friend PageUserData;
+  PAGE_USER_DATA_KEY_DECL();
+
+  // content::WebContentsObserver:
+  void MediaSessionCreated(content::MediaSession*) override;
+
+  void StartDuckingImpl();
+
+  content::WebContents* GetWebContents() const;
+
+  // Binds |audio_focus_remote_| if it's not already bound. Returns true if
+  // |audio_focus_remote_| is already bound or has become bound.
+  bool BindToAudioFocusManagerIfNecessary();
+
+  AudioDuckingState ducking_state_ = AudioDuckingState::kNoDucking;
+  mojo::Remote<media_session::mojom::AudioFocusManager> audio_focus_remote_;
+};
+
+#endif  // CHROME_BROWSER_MEDIA_AUDIO_DUCKER_H_
diff --git a/chrome/browser/media/audio_ducker_browsertest.cc b/chrome/browser/media/audio_ducker_browsertest.cc
new file mode 100644
index 0000000..d71d7bcb
--- /dev/null
+++ b/chrome/browser/media/audio_ducker_browsertest.cc
@@ -0,0 +1,244 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/audio_ducker.h"
+
+#include "base/functional/bind.h"
+#include "base/run_loop.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/media_session.h"
+#include "content/public/browser/media_session_service.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/media_session/public/cpp/test/audio_focus_test_util.h"
+
+namespace {
+
+constexpr base::FilePath::CharType kTestPage[] =
+    FILE_PATH_LITERAL("media/bigbuck-player.html");
+
+constexpr base::FilePath::CharType kTestPageStartWithNoPlayer[] =
+    FILE_PATH_LITERAL("media/start-with-no-player.html");
+
+}  // namespace
+
+using media_session::mojom::MediaSessionInfo;
+
+class AudioDuckerBrowserTest : public InProcessBrowserTest {
+ public:
+  AudioDuckerBrowserTest() = default;
+  AudioDuckerBrowserTest(const AudioDuckerBrowserTest&) = delete;
+  AudioDuckerBrowserTest& operator=(const AudioDuckerBrowserTest&) = delete;
+  ~AudioDuckerBrowserTest() override = default;
+
+  void SetUpOnMainThread() override {
+    ResetAudioFocusObserver();
+
+    host_resolver()->AddRule("*", "127.0.0.1");
+    embedded_test_server()->ServeFilesFromSourceDirectory("chrome/test/data");
+    ASSERT_TRUE(embedded_test_server()->Start());
+  }
+
+  void AddVideo(content::WebContents& web_contents) {
+    web_contents.GetPrimaryMainFrame()
+        ->ExecuteJavaScriptWithUserGestureForTests(
+            u"addVideo();", base::NullCallback(),
+            content::ISOLATED_WORLD_ID_GLOBAL);
+  }
+
+  void PlayVideoAndWaitForAudioFocus(content::WebContents& web_contents) {
+    ResetAudioFocusObserver();
+    web_contents.GetPrimaryMainFrame()
+        ->ExecuteJavaScriptWithUserGestureForTests(
+            u"document.getElementsByTagName('video')[0].play()",
+            base::NullCallback(), content::ISOLATED_WORLD_ID_GLOBAL);
+    WaitForAudioFocusGained();
+  }
+
+  void ResetAudioFocusObserver() {
+    mojo::Remote<media_session::mojom::AudioFocusManager> audio_focus_remote;
+    content::GetMediaSessionService().BindAudioFocusManager(
+        audio_focus_remote.BindNewPipeAndPassReceiver());
+    audio_focus_observer_ =
+        std::make_unique<media_session::test::TestAudioFocusObserver>();
+    audio_focus_remote->AddObserver(
+        audio_focus_observer_->BindNewPipeAndPassRemote());
+  }
+
+  void WaitForAudioFocusGained() {
+    audio_focus_observer_->WaitForGainedEvent();
+  }
+
+  void FlushAudioFocusManager() {
+    mojo::Remote<media_session::mojom::AudioFocusManager> audio_focus_remote;
+    content::GetMediaSessionService().BindAudioFocusManager(
+        audio_focus_remote.BindNewPipeAndPassReceiver());
+
+    base::RunLoop flush_waiter;
+    audio_focus_remote->FlushForTesting(flush_waiter.QuitClosure());
+    flush_waiter.Run();
+  }
+
+  void ExpectMediaSessionState(content::MediaSession& media_session,
+                               MediaSessionInfo::SessionState expected_state) {
+    base::RunLoop waiter;
+    media_session.GetMediaSessionInfo(base::BindOnce(
+        [](MediaSessionInfo::SessionState expected_state,
+           base::OnceClosure wait_closure,
+           media_session::mojom::MediaSessionInfoPtr info) {
+          EXPECT_EQ(info->state, expected_state);
+          std::move(wait_closure).Run();
+        },
+        expected_state, waiter.QuitClosure()));
+    waiter.Run();
+  }
+
+ private:
+  std::unique_ptr<media_session::test::TestAudioFocusObserver>
+      audio_focus_observer_;
+};
+
+IN_PROC_BROWSER_TEST_F(AudioDuckerBrowserTest,
+                       DucksAudioInOtherTabs_MediaPlaying) {
+  GURL test_page_url = ui_test_utils::GetTestUrl(
+      base::FilePath(base::FilePath::kCurrentDirectory),
+      base::FilePath(kTestPage));
+
+  // Open a test page and start playing a video.
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_page_url));
+  content::WebContents* web_contents1 =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  PlayVideoAndWaitForAudioFocus(*web_contents1);
+
+  // Open a second test page and also play a video.
+  ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition(
+      browser(), test_page_url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP));
+  content::WebContents* web_contents2 =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  PlayVideoAndWaitForAudioFocus(*web_contents2);
+
+  content::MediaSession* media_session1 =
+      content::MediaSession::GetIfExists(web_contents1);
+  content::MediaSession* media_session2 =
+      content::MediaSession::GetIfExists(web_contents2);
+  ASSERT_TRUE(media_session1);
+  ASSERT_TRUE(media_session2);
+
+  AudioDucker* audio_ducker =
+      AudioDucker::GetOrCreateForPage(web_contents2->GetPrimaryPage());
+
+  // Neither page should be ducked.
+  ExpectMediaSessionState(*media_session1,
+                          MediaSessionInfo::SessionState::kActive);
+  ExpectMediaSessionState(*media_session2,
+                          MediaSessionInfo::SessionState::kActive);
+  EXPECT_EQ(AudioDucker::AudioDuckingState::kNoDucking,
+            audio_ducker->GetAudioDuckingState());
+
+  // Tell the AudioDucker associated with the second page to duck other audio.
+  EXPECT_TRUE(audio_ducker->StartDuckingOtherAudio());
+  FlushAudioFocusManager();
+
+  // The first page should be ducked while the second remains unducked.
+  ExpectMediaSessionState(*media_session1,
+                          MediaSessionInfo::SessionState::kDucking);
+  ExpectMediaSessionState(*media_session2,
+                          MediaSessionInfo::SessionState::kActive);
+  EXPECT_EQ(AudioDucker::AudioDuckingState::kDucking,
+            audio_ducker->GetAudioDuckingState());
+
+  // Tell the AudioDucker to stop ducking.
+  EXPECT_TRUE(audio_ducker->StopDuckingOtherAudio());
+  FlushAudioFocusManager();
+
+  // Neither page should be ducked.
+  ExpectMediaSessionState(*media_session1,
+                          MediaSessionInfo::SessionState::kActive);
+  ExpectMediaSessionState(*media_session2,
+                          MediaSessionInfo::SessionState::kActive);
+  EXPECT_EQ(AudioDucker::AudioDuckingState::kNoDucking,
+            audio_ducker->GetAudioDuckingState());
+}
+
+IN_PROC_BROWSER_TEST_F(AudioDuckerBrowserTest,
+                       DucksAudioInOtherTabs_NoMediaPlaying) {
+  GURL test_page_url = ui_test_utils::GetTestUrl(
+      base::FilePath(base::FilePath::kCurrentDirectory),
+      base::FilePath(kTestPage));
+
+  // Open a test page and start playing a video.
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_page_url));
+  content::WebContents* web_contents1 =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  PlayVideoAndWaitForAudioFocus(*web_contents1);
+
+  // Open a second test page that has no video.
+  GURL test_page_no_player_url = ui_test_utils::GetTestUrl(
+      base::FilePath(base::FilePath::kCurrentDirectory),
+      base::FilePath(kTestPageStartWithNoPlayer));
+
+  ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition(
+      browser(), test_page_no_player_url,
+      WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP));
+  content::WebContents* web_contents2 =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  content::MediaSession* media_session1 =
+      content::MediaSession::GetIfExists(web_contents1);
+  ASSERT_TRUE(media_session1);
+  ASSERT_EQ(nullptr, content::MediaSession::GetIfExists(web_contents2));
+
+  AudioDucker* audio_ducker =
+      AudioDucker::GetOrCreateForPage(web_contents2->GetPrimaryPage());
+
+  // The first page should not be ducked.
+  ExpectMediaSessionState(*media_session1,
+                          MediaSessionInfo::SessionState::kActive);
+  EXPECT_EQ(AudioDucker::AudioDuckingState::kNoDucking,
+            audio_ducker->GetAudioDuckingState());
+
+  // Tell the AudioDucker associated with the second page to duck other audio.
+  EXPECT_TRUE(audio_ducker->StartDuckingOtherAudio());
+  FlushAudioFocusManager();
+
+  // The first page should be ducked.
+  ExpectMediaSessionState(*media_session1,
+                          MediaSessionInfo::SessionState::kDucking);
+  EXPECT_EQ(AudioDucker::AudioDuckingState::kDucking,
+            audio_ducker->GetAudioDuckingState());
+
+  // Add a video into the second page and play it.
+  AddVideo(*web_contents2);
+  PlayVideoAndWaitForAudioFocus(*web_contents2);
+  content::MediaSession* media_session2 =
+      content::MediaSession::GetIfExists(web_contents2);
+  ASSERT_TRUE(media_session2);
+
+  // The first page should still be ducked but the second page should not be
+  // ducked.
+  ExpectMediaSessionState(*media_session1,
+                          MediaSessionInfo::SessionState::kDucking);
+  ExpectMediaSessionState(*media_session2,
+                          MediaSessionInfo::SessionState::kActive);
+  EXPECT_EQ(AudioDucker::AudioDuckingState::kDucking,
+            audio_ducker->GetAudioDuckingState());
+
+  // Tell the AudioDucker to stop ducking.
+  EXPECT_TRUE(audio_ducker->StopDuckingOtherAudio());
+  FlushAudioFocusManager();
+
+  // The first page should no longer be ducked.
+  ExpectMediaSessionState(*media_session1,
+                          MediaSessionInfo::SessionState::kActive);
+  ExpectMediaSessionState(*media_session2,
+                          MediaSessionInfo::SessionState::kActive);
+  EXPECT_EQ(AudioDucker::AudioDuckingState::kNoDucking,
+            audio_ducker->GetAudioDuckingState());
+}
diff --git a/chrome/browser/net/profile_network_context_service_browsertest.cc b/chrome/browser/net/profile_network_context_service_browsertest.cc
index 1d3c941..f3ce54e 100644
--- a/chrome/browser/net/profile_network_context_service_browsertest.cc
+++ b/chrome/browser/net/profile_network_context_service_browsertest.cc
@@ -845,19 +845,7 @@
 class ProfileNetworkContextTrustTokensBrowsertest
     : public ProfileNetworkContextServiceBrowsertest {
  public:
-  ProfileNetworkContextTrustTokensBrowsertest() {
-    auto& field_trial_param =
-        network::features::kTrustTokenOperationsRequiringOriginTrial;
-    feature_list_.InitWithFeaturesAndParameters(
-        // Enabled Features:
-        {{network::features::kPrivateStateTokens,
-          {{field_trial_param.name,
-            field_trial_param.GetName(
-                network::features::TrustTokenOriginTrialSpec::
-                    kOriginTrialNotRequired)}}}},
-        // Disabled Features:
-        {});
-  }
+  ProfileNetworkContextTrustTokensBrowsertest() = default;
   ~ProfileNetworkContextTrustTokensBrowsertest() override = default;
 
   void SetUpOnMainThread() override {
@@ -909,12 +897,10 @@
  private:
   std::unique_ptr<net::EmbeddedTestServer> https_server_;
   network::test::TrustTokenRequestHandler request_handler_;
-  base::test::ScopedFeatureList feature_list_;
 };
 
 IN_PROC_BROWSER_TEST_F(ProfileNetworkContextTrustTokensBrowsertest,
                        TrustTokenBlocked) {
-  base::test::ScopedFeatureList feature_list_;
   ProvideRequestHandlerKeyCommitmentsToNetworkService("a.test");
   auto* privacy_sandbox_settings =
       PrivacySandboxSettingsFactory::GetForProfile(browser()->profile());
diff --git a/chrome/browser/net/trust_token_usecounter_browsertest.cc b/chrome/browser/net/trust_token_usecounter_browsertest.cc
index f4faeac..0f1bf8b 100644
--- a/chrome/browser/net/trust_token_usecounter_browsertest.cc
+++ b/chrome/browser/net/trust_token_usecounter_browsertest.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -11,7 +10,6 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
-#include "services/network/public/cpp/features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom.h"
 
@@ -28,9 +26,7 @@
 
 class TrustTokenUseCountersBrowsertest : public InProcessBrowserTest {
  public:
-  TrustTokenUseCountersBrowsertest() {
-    features_.InitAndEnableFeature(network::features::kPrivateStateTokens);
-  }
+  TrustTokenUseCountersBrowsertest() = default;
 
   void SetUpOnMainThread() override {
     server_.AddDefaultHandlers(
@@ -39,8 +35,6 @@
   }
 
  protected:
-  base::test::ScopedFeatureList features_;
-
   net::EmbeddedTestServer server_{net::EmbeddedTestServer::TYPE_HTTPS};
 };
 
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index daa5ef7f..22cfee7 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -202,7 +202,6 @@
 #include "chrome/browser/ash/policy/handlers/configuration_policy_handler_ash.h"
 #include "chrome/browser/ash/policy/handlers/contextual_google_integrations_policies_handler.h"
 #include "chrome/browser/ash/policy/handlers/help_me_read_policy_handler.h"
-#include "chrome/browser/ash/policy/handlers/lacros_availability_policy_handler.h"
 #include "chrome/browser/ash/policy/handlers/lacros_selection_policy_handler.h"
 #include "chrome/browser/ash/policy/handlers/multi_screen_capture_policy_handler.h"
 #include "chrome/browser/ash/policy/handlers/screen_capture_location_policy_handler.h"
@@ -3052,7 +3051,6 @@
       SimpleSchemaValidatingPolicyHandler::MANDATORY_ALLOWED));
   handlers->AddHandler(std::make_unique<BooleanDisablingPolicyHandler>(
       key::kNearbyShareAllowed, prefs::kNearbySharingEnabledPrefName));
-  handlers->AddHandler(std::make_unique<LacrosAvailabilityPolicyHandler>());
   handlers->AddHandler(std::make_unique<LacrosSelectionPolicyHandler>());
   handlers->AddHandler(std::make_unique<BooleanDisablingPolicyHandler>(
       key::kFastPairEnabled, ash::prefs::kFastPairEnabled));
diff --git a/chrome/browser/policy/test/default_search_provider_policy_browsertest.cc b/chrome/browser/policy/test/default_search_provider_policy_browsertest.cc
index 3f8d9b6..47c09b01 100644
--- a/chrome/browser/policy/test/default_search_provider_policy_browsertest.cc
+++ b/chrome/browser/policy/test/default_search_provider_policy_browsertest.cc
@@ -56,8 +56,7 @@
   search_test_utils::WaitForTemplateURLServiceToLoad(service);
   const TemplateURL* default_search = service->GetDefaultSearchProvider();
   ASSERT_TRUE(default_search);
-  EXPECT_EQ(default_search->created_by_policy(),
-            TemplateURLData::CreatedByPolicy::kNoPolicy);
+  EXPECT_FALSE(default_search->CreatedByPolicy());
   EXPECT_NE(kKeyword, default_search->keyword());
   EXPECT_NE(kSearchURL, default_search->url());
   EXPECT_FALSE(default_search->alternate_urls().size() == 2 &&
@@ -96,8 +95,7 @@
   UpdateProviderPolicy(policies);
   default_search = service->GetDefaultSearchProvider();
   ASSERT_TRUE(default_search);
-  EXPECT_EQ(default_search->created_by_policy(),
-            TemplateURLData::CreatedByPolicy::kDefaultSearchProvider);
+  EXPECT_TRUE(default_search->CreatedByDefaultSearchProviderPolicy());
   EXPECT_EQ(kKeyword, default_search->keyword());
   EXPECT_EQ(kSearchURL, default_search->url());
   EXPECT_EQ(2U, default_search->alternate_urls().size());
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 8424b56..f45d3c59 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -1169,8 +1169,13 @@
 const char kCryptAuthEnrollmentUserPrivateKey[] =
     "cryptauth.enrollment.user_private_key";
 const char kLacrosLaunchOnLogin[] = "lacros.launch_on_login";
+const char kLacrosLaunchSwitch[] = "lacros_launch_switch";
 #endif
 
+// Deprecated 12/2024.
+inline constexpr char kPageContentCollectionEnabled[] =
+    "page_content_collection.enabled";
+
 // Register local state used only for migration (clearing or moving to a new
 // key).
 void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) {
@@ -1280,6 +1285,11 @@
 
   // Deprecated 11/2024.
   registry->RegisterIntegerPref(kOnDeviceModelTimeoutCount, 0);
+
+#if BUILDFLAG(IS_CHROMEOS)
+  // Deprecated 12/2024.
+  registry->RegisterIntegerPref(kLacrosLaunchSwitch, 0);
+#endif
 }
 
 // Register prefs used only for migration (clearing or moving to a new key).
@@ -1663,6 +1673,9 @@
                                std::string());
   registry->RegisterBooleanPref(kLacrosLaunchOnLogin, false);
 #endif
+
+  // Deprecated 12/2024.
+  registry->RegisterBooleanPref(kPageContentCollectionEnabled, false);
 }
 
 }  // namespace
@@ -2161,6 +2174,7 @@
   bookmarks_webui::RegisterProfilePrefs(registry);
   browser_sync::ForeignSessionHandler::RegisterProfilePrefs(registry);
   BrowserUserEducationStorageService::RegisterProfilePrefs(registry);
+  captions::LiveCaptionController::RegisterProfilePrefs(registry);
   captions::LiveTranslateController::RegisterProfilePrefs(registry);
   ChromeAuthenticatorRequestDelegate::RegisterProfilePrefs(registry);
   commerce::CommerceUiTabHelper::RegisterProfilePrefs(registry);
@@ -2199,10 +2213,6 @@
   toolbar::RegisterProfilePrefs(registry);
   UnifiedAutoplayConfig::RegisterProfilePrefs(registry);
   user_notes::RegisterProfilePrefs(registry);
-
-#if !BUILDFLAG(IS_CHROMEOS_LACROS)
-  captions::LiveCaptionController::RegisterProfilePrefs(registry);
-#endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)
 #endif  // BUILDFLAG(IS_ANDROID)
 
 #if BUILDFLAG(IS_CHROMEOS)
@@ -2582,6 +2592,11 @@
   optimization_guide::model_execution::prefs::MigrateLegacyUsagePrefs(
       local_state);
 
+  // Added 12/2024
+#if BUILDFLAG(IS_CHROMEOS)
+  local_state->ClearPref(kLacrosLaunchSwitch);
+#endif
+
   // Please don't delete the following line. It is used by PRESUBMIT.py.
   // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS
 
@@ -3000,6 +3015,9 @@
   profile_prefs->ClearPref(kLacrosLaunchOnLogin);
 #endif
 
+  // Added 12/2024.
+  profile_prefs->ClearPref(kPageContentCollectionEnabled);
+
   // Please don't delete the following line. It is used by PRESUBMIT.py.
   // END_MIGRATE_OBSOLETE_PROFILE_PREFS
 
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
index 86b4d333f..5082c75f 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
@@ -572,11 +572,9 @@
         ReadAloudReadabilityHooksFactory factory =
                 ServiceLoaderUtil.maybeCreate(ReadAloudReadabilityHooksFactory.class);
         if (factory != null) {
-            mReadabilityHooks = factory.create(mActivity.getApplicationContext(), profile);
+            mReadabilityHooks = factory.create(mActivity, profile);
         } else {
-            mReadabilityHooks =
-                    new ReadAloudReadabilityHooksUpstreamImpl(
-                            mActivity.getApplicationContext(), profile);
+            mReadabilityHooks = new ReadAloudReadabilityHooksUpstreamImpl(mActivity, profile);
         }
         if (mReadabilityHooks.isEnabled()) {
             boolean isAllowed = ReadAloudFeatures.isAllowed(profile);
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index c54052fd..2ac8293 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -4649,10 +4649,7 @@
 // added benefit of also doing the right thing when Lacros is enabled).
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
-      GetProfile(),
-      ash::features::IsOsSettingsRevampWayfindingEnabled()
-          ? chromeos::settings::mojom::kLanguagesSubpagePath
-          : chromeos::settings::mojom::kLanguagesAndInputSectionPath);
+      GetProfile(), chromeos::settings::mojom::kLanguagesSubpagePath);
 #else
   WindowOpenDisposition disposition = ui::DispositionFromEventFlags(
       event_flags, WindowOpenDisposition::NEW_FOREGROUND_TAB);
diff --git a/chrome/browser/resources/ash/settings/BUILD.gn b/chrome/browser/resources/ash/settings/BUILD.gn
index c9016fb..748fc22 100644
--- a/chrome/browser/resources/ash/settings/BUILD.gn
+++ b/chrome/browser/resources/ash/settings/BUILD.gn
@@ -284,7 +284,6 @@
     "os_languages_page/os_japanese_dictionary_expand.ts",
     "os_languages_page/os_japanese_dictionary_entry_row.ts",
     "os_languages_page/os_languages_page_v2.ts",
-    "os_languages_page/os_languages_section.ts",
     "os_people_page/account_manager_settings_card.ts",
     "os_people_page/add_user_dialog.ts",
     "os_people_page/additional_accounts_settings_card.ts",
diff --git a/chrome/browser/resources/ash/settings/common/route_origin_mixin.ts b/chrome/browser/resources/ash/settings/common/route_origin_mixin.ts
index de33fb9..7431d5fa 100644
--- a/chrome/browser/resources/ash/settings/common/route_origin_mixin.ts
+++ b/chrome/browser/resources/ash/settings/common/route_origin_mixin.ts
@@ -75,9 +75,6 @@
           }
 
           // Route change does not apply to the route for this page.
-          // When infinite scroll exists (OsSettingsRevampWayfinding disabled)
-          // subpage triggers should be refocused if the previous route was the
-          // root page.
           if (newRoute !== this.route && newRoute !== routes.BASIC) {
             return;
           }
diff --git a/chrome/browser/resources/ash/settings/os_languages_page/os_languages_section.html b/chrome/browser/resources/ash/settings/os_languages_page/os_languages_section.html
deleted file mode 100644
index b6058b3..0000000
--- a/chrome/browser/resources/ash/settings/os_languages_page/os_languages_section.html
+++ /dev/null
@@ -1,66 +0,0 @@
-<style include="settings-shared"></style>
-
-<!-- Top-level settings section. -->
-<os-settings-animated-pages id="pages" section="[[section_]]">
-  <div route-path="default">
-    <language-settings-card
-        prefs="{{prefs}}"
-        languages="[[languages]]"
-        language-helper="[[languageHelper]]">
-    </language-settings-card>
-  </div>
-
-  <!-- "Languages" page. -->
-  <template is="dom-if" route-path="/osLanguages/languages">
-    <os-settings-subpage page-title="$i18n{languagesPageTitle}">
-      <os-settings-languages-page-v2
-          language-helper="[[languageHelper]]"
-          languages="[[languages]]"
-          prefs="{{prefs}}">
-      </os-settings-languages-page-v2>
-    </os-settings-subpage>
-  </template>
-
-  <!-- "App Languages" sub-page. -->
-  <template is="dom-if" route-path="/osLanguages/languages/appLanguages">
-    <os-settings-subpage page-title="$i18n{appLanguagesTitle}">
-      <os-settings-app-languages-page prefs="{{prefs}}">
-      </os-settings-app-languages-page>
-    </os-settings-subpage>
-  </template>
-
-  <!-- "Input" page. -->
-  <template is="dom-if" route-path="/osLanguages/input">
-    <os-settings-subpage page-title="$i18n{inputPageTitle}">
-      <os-settings-input-page language-helper="[[languageHelper]]"
-          languages="[[languages]]" prefs="{{prefs}}">
-      </os-settings-input-page>
-    </os-settings-subpage>
-  </template>
-
-  <!-- "Input method settings" sub-sub-page. -->
-  <template is="dom-if" route-path="/osLanguages/inputMethodOptions">
-    <os-settings-subpage>
-      <settings-input-method-options-page
-          language-helper="[[languageHelper]]"
-          prefs="{{prefs}}">
-      </settings-input-method-options-page>
-    </os-settings-subpage>
-  </template>
-
-  <!-- "Customize spell check" sub-sub-page. -->
-  <template is="dom-if" route-path="/osLanguages/editDictionary">
-    <os-settings-subpage page-title="$i18n{editDictionaryLabel}">
-      <os-settings-edit-dictionary-page></os-settings-edit-dictionary-page>
-    </os-settings-subpage>
-  </template>
-
-  <!-- "Japanese Manage User dictionary" sub-sub-page. -->
-  <template is="dom-if" route-path="/osLanguages/japaneseManageUserDictionary">
-    <os-settings-subpage page-title="$i18n{japaneseManageUserDictionaryLabel}">
-      <os-settings-japanese-manage-user-dictionary-page>
-      </os-settings-japanese-manage-user-dictionary-page>
-    </os-settings-subpage>
-  </template>
-
-</os-settings-animated-pages>
diff --git a/chrome/browser/resources/ash/settings/os_languages_page/os_languages_section.ts b/chrome/browser/resources/ash/settings/os_languages_page/os_languages_section.ts
deleted file mode 100644
index ea5f51e..0000000
--- a/chrome/browser/resources/ash/settings/os_languages_page/os_languages_section.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview
- * 'os-settings-languages-section' is the top-level settings section for
- * languages.
- */
-
-import 'chrome://resources/ash/common/cr_elements/cr_icon_button/cr_icon_button.js';
-import 'chrome://resources/ash/common/cr_elements/cr_shared_vars.css.js';
-import './language_settings_card.js';
-import '../os_settings_page/os_settings_animated_pages.js';
-import '../os_settings_page/os_settings_subpage.js';
-import '../settings_shared.css.js';
-import '../settings_vars.css.js';
-
-import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js';
-import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import type {PrefsState} from '../common/types.js';
-import {Section} from '../mojom-webui/routes.mojom-webui.js';
-
-import type {LanguageHelper, LanguagesModel} from './languages_types.js';
-import {getTemplate} from './os_languages_section.html.js';
-
-const OsSettingsLanguagesSectionElementBase = I18nMixin(PolymerElement);
-
-export class OsSettingsLanguagesSectionElement extends
-    OsSettingsLanguagesSectionElementBase {
-  static get is() {
-    return 'os-settings-languages-section' as const;
-  }
-
-  static get template() {
-    return getTemplate();
-  }
-
-  static get properties() {
-    return {
-      prefs: {
-        type: Object,
-        notify: true,
-      },
-
-      section_: {
-        type: Number,
-        value: Section.kLanguagesAndInput,
-        readOnly: true,
-      },
-
-      /**
-       * Set of languages from <settings-languages>
-       */
-      languages: Object,
-
-      /**
-       * Language helper API from <settings-languages>
-       */
-      languageHelper: Object,
-    };
-  }
-
-  // Public API: Bidirectional data flow.
-  /** Passed down to children. Do not access without using PrefsMixin. */
-  prefs: PrefsState;
-
-  languages: LanguagesModel|undefined;
-  languageHelper: LanguageHelper|undefined;
-
-  // Internal state.
-  private section_: Section;
-}
-
-customElements.define(
-    OsSettingsLanguagesSectionElement.is, OsSettingsLanguagesSectionElement);
-
-declare global {
-  interface HTMLElementTagNameMap {
-    [OsSettingsLanguagesSectionElement.is]: OsSettingsLanguagesSectionElement;
-  }
-}
diff --git a/chrome/browser/resources/ash/settings/os_page_availability.ts b/chrome/browser/resources/ash/settings/os_page_availability.ts
index 5eaf4150..2b7bd4e 100644
--- a/chrome/browser/resources/ash/settings/os_page_availability.ts
+++ b/chrome/browser/resources/ash/settings/os_page_availability.ts
@@ -45,11 +45,6 @@
     [Section.kPeople]: !!routes.OS_PEOPLE,
     [Section.kPersonalization]: !!routes.PERSONALIZATION,
     [Section.kPrivacyAndSecurity]: !!routes.OS_PRIVACY,
-
-    // Only available when OsSettingsRevampWayfinding feature is enabled.
     [Section.kSystemPreferences]: !!routes.SYSTEM_PREFERENCES,
-
-    // Only available when OsSettingsRevampWayfinding feature is disabled.
-    [Section.kLanguagesAndInput]: !!routes.OS_LANGUAGES,
   };
 }
diff --git a/chrome/browser/resources/ash/settings/os_settings_routes.ts b/chrome/browser/resources/ash/settings/os_settings_routes.ts
index 316b9dd3..824e3ca 100644
--- a/chrome/browser/resources/ash/settings/os_settings_routes.ts
+++ b/chrome/browser/resources/ash/settings/os_settings_routes.ts
@@ -13,7 +13,7 @@
 import {assert} from 'chrome://resources/js/assert.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 
-import {androidAppsVisible, isAppParentalControlsFeatureAvailable, isArcVmEnabled, isCrostiniSupported, isGuest, isInputDeviceSettingsSplitEnabled, isKerberosEnabled, isPluginVmAvailable, isRevampWayfindingEnabled} from './common/load_time_booleans.js';
+import {androidAppsVisible, isAppParentalControlsFeatureAvailable, isArcVmEnabled, isCrostiniSupported, isGuest, isInputDeviceSettingsSplitEnabled, isKerberosEnabled, isPluginVmAvailable} from './common/load_time_booleans.js';
 import * as routesMojom from './mojom-webui/routes.mojom-webui.js';
 
 /**
@@ -342,17 +342,6 @@
   if (!isGuest()) {
     r.OS_PEOPLE = createSection(
         r.BASIC, routesMojom.PEOPLE_SECTION_PATH, Section.kPeople);
-
-    if (!isRevampWayfindingEnabled()) {
-      r.ACCOUNT_MANAGER = createSubpage(
-          r.OS_PEOPLE, routesMojom.MY_ACCOUNTS_SUBPAGE_PATH,
-          Subpage.kMyAccounts);
-      // TODO(b/305747266) : Disambiguate the names for OS_SYNC and SYNC.
-      r.OS_SYNC = createSubpage(
-          r.OS_PEOPLE, routesMojom.SYNC_SUBPAGE_PATH, Subpage.kSync);
-      r.SYNC = createSubpage(
-          r.OS_PEOPLE, routesMojom.SYNC_SETUP_SUBPAGE_PATH, Subpage.kSyncSetup);
-    }
   }
 
   // Kerberos section.
@@ -547,141 +536,103 @@
       r.ABOUT, routesMojom.INTERNAL_STORYBOOK_SUBPAGE_PATH,
       Subpage.kInternalStorybook);
 
-  if (isRevampWayfindingEnabled()) {
-    // Device section, Input subpages.
-    const inputParentRoute = isInputDeviceSettingsSplitEnabled() ?
-        r.PER_DEVICE_KEYBOARD :
-        r.KEYBOARD;
-    assert(inputParentRoute);
-    r.OS_LANGUAGES_INPUT = createSubpage(
-        inputParentRoute, routesMojom.INPUT_SUBPAGE_PATH, Subpage.kInput);
-    r.OS_LANGUAGES_INPUT_METHOD_OPTIONS = createSubpage(
-        r.OS_LANGUAGES_INPUT, routesMojom.INPUT_METHOD_OPTIONS_SUBPAGE_PATH,
-        Subpage.kInputMethodOptions);
-    r.OS_LANGUAGES_EDIT_DICTIONARY = createSubpage(
-        r.OS_LANGUAGES_INPUT, routesMojom.EDIT_DICTIONARY_SUBPAGE_PATH,
-        Subpage.kEditDictionary);
-    r.OS_LANGUAGES_JAPANESE_MANAGE_USER_DICTIONARY = createSubpage(
-        r.OS_LANGUAGES_INPUT,
-        routesMojom.JAPANESE_MANAGE_USER_DICTIONARY_SUBPAGE_PATH,
-        Subpage.kJapaneseManageUserDictionary);
+  // Device section, Input subpages.
+  const inputParentRoute =
+      isInputDeviceSettingsSplitEnabled() ? r.PER_DEVICE_KEYBOARD : r.KEYBOARD;
+  assert(inputParentRoute);
+  r.OS_LANGUAGES_INPUT = createSubpage(
+      inputParentRoute, routesMojom.INPUT_SUBPAGE_PATH, Subpage.kInput);
+  r.OS_LANGUAGES_INPUT_METHOD_OPTIONS = createSubpage(
+      r.OS_LANGUAGES_INPUT, routesMojom.INPUT_METHOD_OPTIONS_SUBPAGE_PATH,
+      Subpage.kInputMethodOptions);
+  r.OS_LANGUAGES_EDIT_DICTIONARY = createSubpage(
+      r.OS_LANGUAGES_INPUT, routesMojom.EDIT_DICTIONARY_SUBPAGE_PATH,
+      Subpage.kEditDictionary);
+  r.OS_LANGUAGES_JAPANESE_MANAGE_USER_DICTIONARY = createSubpage(
+      r.OS_LANGUAGES_INPUT,
+      routesMojom.JAPANESE_MANAGE_USER_DICTIONARY_SUBPAGE_PATH,
+      Subpage.kJapaneseManageUserDictionary);
 
-    // System Preferences section.
-    r.SYSTEM_PREFERENCES = createSection(
-        r.BASIC, routesMojom.SYSTEM_PREFERENCES_SECTION_PATH,
-        Section.kSystemPreferences);
+  // System Preferences section.
+  r.SYSTEM_PREFERENCES = createSection(
+      r.BASIC, routesMojom.SYSTEM_PREFERENCES_SECTION_PATH,
+      Section.kSystemPreferences);
 
-    // Date and Time subpages.
-    r.DATETIME_TIMEZONE_SUBPAGE = createSubpage(
-        r.SYSTEM_PREFERENCES, routesMojom.TIME_ZONE_SUBPAGE_PATH,
-        Subpage.kTimeZone);
+  // Date and Time subpages.
+  r.DATETIME_TIMEZONE_SUBPAGE = createSubpage(
+      r.SYSTEM_PREFERENCES, routesMojom.TIME_ZONE_SUBPAGE_PATH,
+      Subpage.kTimeZone);
 
-    // Files subpages.
-    if (!isGuest()) {
-      r.GOOGLE_DRIVE = createSubpage(
-          r.SYSTEM_PREFERENCES, routesMojom.GOOGLE_DRIVE_SUBPAGE_PATH,
-          Subpage.kGoogleDrive);
-      if (loadTimeData.getBoolean('showOfficeSettings')) {
-        r.OFFICE = createSubpage(
-            r.SYSTEM_PREFERENCES, routesMojom.OFFICE_FILES_SUBPAGE_PATH,
-            Subpage.kOfficeFiles);
-      }
-      if (loadTimeData.getBoolean('showOneDriveSettings')) {
-        r.ONE_DRIVE = createSubpage(
-            r.SYSTEM_PREFERENCES, routesMojom.ONE_DRIVE_SUBPAGE_PATH,
-            Subpage.kOneDrive);
-      }
-      r.SMB_SHARES = createSubpage(
-          r.SYSTEM_PREFERENCES, routesMojom.NETWORK_FILE_SHARES_SUBPAGE_PATH,
-          Subpage.kNetworkFileShares);
+  // Files subpages.
+  if (!isGuest()) {
+    r.GOOGLE_DRIVE = createSubpage(
+        r.SYSTEM_PREFERENCES, routesMojom.GOOGLE_DRIVE_SUBPAGE_PATH,
+        Subpage.kGoogleDrive);
+    if (loadTimeData.getBoolean('showOfficeSettings')) {
+      r.OFFICE = createSubpage(
+          r.SYSTEM_PREFERENCES, routesMojom.OFFICE_FILES_SUBPAGE_PATH,
+          Subpage.kOfficeFiles);
     }
-
-    // Language subpages.
-    r.OS_LANGUAGES_LANGUAGES = createSubpage(
-        r.SYSTEM_PREFERENCES, routesMojom.LANGUAGES_SUBPAGE_PATH,
-        Subpage.kLanguages);
-    if (loadTimeData.getBoolean('isPerAppLanguageEnabled')) {
-      r.OS_LANGUAGES_APP_LANGUAGES = createSubpage(
-          r.OS_LANGUAGES_LANGUAGES, routesMojom.APP_LANGUAGES_SUBPAGE_PATH,
-          Subpage.kAppLanguages);
+    if (loadTimeData.getBoolean('showOneDriveSettings')) {
+      r.ONE_DRIVE = createSubpage(
+          r.SYSTEM_PREFERENCES, routesMojom.ONE_DRIVE_SUBPAGE_PATH,
+          Subpage.kOneDrive);
     }
+    r.SMB_SHARES = createSubpage(
+        r.SYSTEM_PREFERENCES, routesMojom.NETWORK_FILE_SHARES_SUBPAGE_PATH,
+        Subpage.kNetworkFileShares);
+  }
 
-    // Search and Assistant subpages.
-    r.SEARCH_SUBPAGE = createSubpage(
-        r.SYSTEM_PREFERENCES, routesMojom.SEARCH_SUBPAGE_PATH, Subpage.kSearch);
-    r.GOOGLE_ASSISTANT = createSubpage(
-        r.SYSTEM_PREFERENCES, routesMojom.ASSISTANT_SUBPAGE_PATH,
-        Subpage.kAssistant);
+  // Language subpages.
+  r.OS_LANGUAGES_LANGUAGES = createSubpage(
+      r.SYSTEM_PREFERENCES, routesMojom.LANGUAGES_SUBPAGE_PATH,
+      Subpage.kLanguages);
+  if (loadTimeData.getBoolean('isPerAppLanguageEnabled')) {
+    r.OS_LANGUAGES_APP_LANGUAGES = createSubpage(
+        r.OS_LANGUAGES_LANGUAGES, routesMojom.APP_LANGUAGES_SUBPAGE_PATH,
+        Subpage.kAppLanguages);
+  }
 
-    // Storage and power subpages.
-    r.STORAGE = createSubpage(
-        r.SYSTEM_PREFERENCES, routesMojom.STORAGE_SUBPAGE_PATH,
-        Subpage.kStorage);
-    r.EXTERNAL_STORAGE_PREFERENCES = createSubpage(
-        r.STORAGE, routesMojom.EXTERNAL_STORAGE_SUBPAGE_PATH,
-        Subpage.kExternalStorage);
-    r.POWER = createSubpage(
-        r.SYSTEM_PREFERENCES, routesMojom.POWER_SUBPAGE_PATH, Subpage.kPower);
+  // Search and Assistant subpages.
+  r.SEARCH_SUBPAGE = createSubpage(
+      r.SYSTEM_PREFERENCES, routesMojom.SEARCH_SUBPAGE_PATH, Subpage.kSearch);
+  r.GOOGLE_ASSISTANT = createSubpage(
+      r.SYSTEM_PREFERENCES, routesMojom.ASSISTANT_SUBPAGE_PATH,
+      Subpage.kAssistant);
 
-    // Printing subpage.
-    r.CUPS_PRINTERS = createSubpage(
-        r.DEVICE, routesMojom.PRINTING_DETAILS_SUBPAGE_PATH,
-        Subpage.kPrintingDetails);
+  // Storage and power subpages.
+  r.STORAGE = createSubpage(
+      r.SYSTEM_PREFERENCES, routesMojom.STORAGE_SUBPAGE_PATH, Subpage.kStorage);
+  r.EXTERNAL_STORAGE_PREFERENCES = createSubpage(
+      r.STORAGE, routesMojom.EXTERNAL_STORAGE_SUBPAGE_PATH,
+      Subpage.kExternalStorage);
+  r.POWER = createSubpage(
+      r.SYSTEM_PREFERENCES, routesMojom.POWER_SUBPAGE_PATH, Subpage.kPower);
 
-    // Crostini subpages.
-    if (isCrostiniSupported()) {
-      r.CROSTINI_DETAILS = createSubpage(
-          r.ABOUT, routesMojom.CROSTINI_DETAILS_SUBPAGE_PATH,
-          Subpage.kCrostiniDetails);
+  // Printing subpage.
+  r.CUPS_PRINTERS = createSubpage(
+      r.DEVICE, routesMojom.PRINTING_DETAILS_SUBPAGE_PATH,
+      Subpage.kPrintingDetails);
 
-      r.BRUSCHETTA_DETAILS = createSubpage(
-          r.ABOUT, routesMojom.BRUSCHETTA_DETAILS_SUBPAGE_PATH,
-          Subpage.kBruschettaDetails);
-    }
+  // Crostini subpages.
+  if (isCrostiniSupported()) {
+    r.CROSTINI_DETAILS = createSubpage(
+        r.ABOUT, routesMojom.CROSTINI_DETAILS_SUBPAGE_PATH,
+        Subpage.kCrostiniDetails);
 
-    // Sync subpages.
-    if (!isGuest()) {
-      assert(r.OS_PRIVACY);
-      // TODO(b/305747266) : Disambiguate the names for OS_SYNC and SYNC.
-      r.OS_SYNC = createSubpage(
-          r.OS_PRIVACY, routesMojom.SYNC_SUBPAGE_PATH, Subpage.kSync);
-      r.SYNC = createSubpage(
-          r.OS_PRIVACY, routesMojom.SYNC_SETUP_SUBPAGE_PATH,
-          Subpage.kSyncSetup);
-    }
-  } else {
-    // Device section.
-    r.STORAGE = createSubpage(
-        r.DEVICE, routesMojom.STORAGE_SUBPAGE_PATH, Subpage.kStorage);
-    r.EXTERNAL_STORAGE_PREFERENCES = createSubpage(
-        r.STORAGE, routesMojom.EXTERNAL_STORAGE_SUBPAGE_PATH,
-        Subpage.kExternalStorage);
-    r.POWER =
-        createSubpage(r.DEVICE, routesMojom.POWER_SUBPAGE_PATH, Subpage.kPower);
+    r.BRUSCHETTA_DETAILS = createSubpage(
+        r.ABOUT, routesMojom.BRUSCHETTA_DETAILS_SUBPAGE_PATH,
+        Subpage.kBruschettaDetails);
+  }
 
-    // Languages and Input section.
-    r.OS_LANGUAGES = createSection(
-        r.ADVANCED, routesMojom.LANGUAGES_AND_INPUT_SECTION_PATH,
-        Section.kLanguagesAndInput);
-    r.OS_LANGUAGES_LANGUAGES = createSubpage(
-        r.OS_LANGUAGES, routesMojom.LANGUAGES_SUBPAGE_PATH, Subpage.kLanguages);
-    r.OS_LANGUAGES_INPUT = createSubpage(
-        r.OS_LANGUAGES, routesMojom.INPUT_SUBPAGE_PATH, Subpage.kInput);
-    r.OS_LANGUAGES_INPUT_METHOD_OPTIONS = createSubpage(
-        r.OS_LANGUAGES_INPUT, routesMojom.INPUT_METHOD_OPTIONS_SUBPAGE_PATH,
-        Subpage.kInputMethodOptions);
-    r.OS_LANGUAGES_EDIT_DICTIONARY = createSubpage(
-        r.OS_LANGUAGES_INPUT, routesMojom.EDIT_DICTIONARY_SUBPAGE_PATH,
-        Subpage.kEditDictionary);
-    r.OS_LANGUAGES_JAPANESE_MANAGE_USER_DICTIONARY = createSubpage(
-        r.OS_LANGUAGES_INPUT,
-        routesMojom.JAPANESE_MANAGE_USER_DICTIONARY_SUBPAGE_PATH,
-        Subpage.kJapaneseManageUserDictionary);
-    if (loadTimeData.getBoolean('isPerAppLanguageEnabled')) {
-      r.OS_LANGUAGES_APP_LANGUAGES = createSubpage(
-          r.OS_LANGUAGES_LANGUAGES, routesMojom.APP_LANGUAGES_SUBPAGE_PATH,
-          Subpage.kAppLanguages);
-    }
+  // Sync subpages.
+  if (!isGuest()) {
+    assert(r.OS_PRIVACY);
+    // TODO(b/305747266) : Disambiguate the names for OS_SYNC and SYNC.
+    r.OS_SYNC = createSubpage(
+        r.OS_PRIVACY, routesMojom.SYNC_SUBPAGE_PATH, Subpage.kSync);
+    r.SYNC = createSubpage(
+        r.OS_PRIVACY, routesMojom.SYNC_SETUP_SUBPAGE_PATH, Subpage.kSyncSetup);
   }
 
   // Crostini details subpages.
diff --git a/chrome/browser/resources/ash/settings/router.ts b/chrome/browser/resources/ash/settings/router.ts
index 0d78477..ad1f5e6 100644
--- a/chrome/browser/resources/ash/settings/router.ts
+++ b/chrome/browser/resources/ash/settings/router.ts
@@ -6,7 +6,6 @@
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 
 import {castExists} from './assert_extras.js';
-import {isRevampWayfindingEnabled} from './common/load_time_booleans.js';
 import type {RouteObserverMixinInterface} from './common/route_observer_mixin.js';
 import type {OsSettingsRoutes} from './os_settings_routes.js';
 import {createRoutes, PATH_REDIRECTS, Route} from './os_settings_routes.js';
@@ -169,10 +168,8 @@
     // Remove any trailing slash.
     let canonicalPath = path.replace(CANONICAL_PATH_REGEX, '$1$2');
 
-    // Handle redirects for obsolete paths.
-    if (isRevampWayfindingEnabled()) {
-      canonicalPath = PATH_REDIRECTS[canonicalPath] || canonicalPath;
-    }
+    // Handle redirects for paths (e.g. deprecated paths).
+    canonicalPath = PATH_REDIRECTS[canonicalPath] || canonicalPath;
 
     const matchingRoute = Object.values(this.routes_).find(route => {
       return route.path === canonicalPath && isNavigableRoute(route);
diff --git a/chrome/browser/resources/data_sharing/data_sharing.html b/chrome/browser/resources/data_sharing/data_sharing.html
index 4383bbea..b06c0bbc 100644
--- a/chrome/browser/resources/data_sharing/data_sharing.html
+++ b/chrome/browser/resources/data_sharing/data_sharing.html
@@ -6,6 +6,11 @@
     <!-- Add CSS variables for Chrome's themed material color equivalents -->
     <link rel="stylesheet" href="//theme/colors.css?sets=ui,chrome">
     <!-- Load desired system fonts onto the body -->
+    <style>
+      body {
+        margin: 0;
+      }
+    </style>
     <link rel="stylesheet" href="//resources/css/text_defaults_md.css">
     <link rel="stylesheet" href="data_sharing_sdk.css">
     <script type="module" src="data_sharing_app.js"></script>
diff --git a/chrome/browser/resources/data_sharing/data_sharing_app.html b/chrome/browser/resources/data_sharing/data_sharing_app.html
index df1b198f..4be4efec 100644
--- a/chrome/browser/resources/data_sharing/data_sharing_app.html
+++ b/chrome/browser/resources/data_sharing/data_sharing_app.html
@@ -2,6 +2,7 @@
   .container {
     width: 448px;
     min-height: 200px;
+    background-color: var(--color-sys-surface);
 
     --skw-color-primary: var(--color-sys-primary);
     --skw-color-surface-tint: var(--color-sys-surface-tint);
diff --git a/chrome/browser/resources/extensions/detail_view.ts b/chrome/browser/resources/extensions/detail_view.ts
index 0f9351d..7a142c21 100644
--- a/chrome/browser/resources/extensions/detail_view.ts
+++ b/chrome/browser/resources/extensions/detail_view.ts
@@ -673,7 +673,7 @@
   /**
    * Returns the HTML representation of the Manifest V2 deprecation message
    * subtitle string. We need the HTML representation instead of the string
-   * since the string holds a link.
+   * since the string holds substitutions.
    */
   protected getMv2DeprecationMessageSubtitle_(): TrustedHTML {
     switch (this.mv2ExperimentStage_) {
@@ -681,8 +681,11 @@
         return window.trustedTypes!.emptyHTML;
       case Mv2ExperimentStage.WARNING:
         return this.i18nAdvanced('mv2DeprecationMessageWarningSubtitle', {
-          substitutions:
-              ['https://chromewebstore.google.com/category/extensions'],
+          substitutions: [
+            'https://chromewebstore.google.com/category/extensions',
+            this.i18n('opensInNewTab'),
+          ],
+          attrs: ['aria-description'],
         });
       case Mv2ExperimentStage.DISABLE_WITH_REENABLE:
       case Mv2ExperimentStage.UNSUPPORTED:
@@ -690,7 +693,9 @@
           substitutions: [
             'https://support.google.com/chrome_webstore' +
                 '?p=unsupported_extensions',
+            this.i18n('opensInNewTab'),
           ],
+          attrs: ['aria-description'],
         });
       default:
         assertNotReached();
diff --git a/chrome/browser/resources/extensions/mv2_deprecation_panel.ts b/chrome/browser/resources/extensions/mv2_deprecation_panel.ts
index 40efaae..ae4b98f 100644
--- a/chrome/browser/resources/extensions/mv2_deprecation_panel.ts
+++ b/chrome/browser/resources/extensions/mv2_deprecation_panel.ts
@@ -130,6 +130,8 @@
     const subtitle = await PluralStringProxyImpl.getInstance().getPluralString(
         subtitleVar, this.extensions.length);
     this.subtitleString_ = subtitle.replace('$1', subtitleLink);
+    this.subtitleString_ =
+        this.subtitleString_.replace('$2', this.i18n('opensInNewTab'));
   }
 
   /**
@@ -247,7 +249,8 @@
    * representation instead of the string since the string holds a link.
    */
   protected getSubtitleString_(): TrustedHTML {
-    return sanitizeInnerHtml(this.subtitleString_);
+    return sanitizeInnerHtml(
+        this.subtitleString_, {attrs: ['aria-description']});
   }
 
   /**
diff --git a/chrome/browser/resources/glic/glic_api/glic_api.ts b/chrome/browser/resources/glic/glic_api/glic_api.ts
index 30ceb8ba..17f5d75 100644
--- a/chrome/browser/resources/glic/glic_api/glic_api.ts
+++ b/chrome/browser/resources/glic/glic_api/glic_api.ts
@@ -73,6 +73,9 @@
   resizeWindow(width: number, height: number):
       Promise<{actualWidth: number, actualHeight: number}>;
 
+  // Set the areas of the glic window from which it should be draggable.
+  setWindowDraggableAreas(areas: DraggableArea[]): Promise<void>;
+
   // Fetches page context for the currently focused tab, optionally including
   // more expensive-to-generate data. Undefined optional arguments indicate that
   // the respective data is not being requested.
@@ -192,3 +195,13 @@
 }
 
 export type GetTabContextError = ErrorWithReason<GetTabContextErrorReason>;
+
+/**
+ * A rectangular area based in the glic window's coordinate system.
+ */
+export declare interface DraggableArea {
+  x: number;
+  y: number;
+  width: number;
+  height: number;
+}
diff --git a/chrome/browser/resources/glic/glic_api/glic_api_client.ts b/chrome/browser/resources/glic/glic_api/glic_api_client.ts
index 679a91ad..02d5896d 100644
--- a/chrome/browser/resources/glic/glic_api/glic_api_client.ts
+++ b/chrome/browser/resources/glic/glic_api/glic_api_client.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import type {ErrorWithReason, GlicBrowserHost, GlicHostRegistry, GlicWebClient, TabContextResult, TabData} from '../glic_api/glic_api.js';
+import type {DraggableArea, ErrorWithReason, GlicBrowserHost, GlicHostRegistry, GlicWebClient, TabContextResult, TabData} from '../glic_api/glic_api.js';
 import {GetTabContextErrorReason} from '../glic_api/glic_api.js';
 
 import {PostMessageRequestReceiver, PostMessageRequestSender} from './post_message_transport.js';
@@ -141,6 +141,11 @@
     return this.sender.requestWithResponse(
         'glicBrowserResizeWindow', {width, height});
   }
+
+  async setWindowDraggableAreas(areas: DraggableArea[]) {
+    return this.sender.requestWithResponse(
+        'glicBrowserSetWindowDraggableAreas', {areas});
+  }
 }
 
 // Returns a promise which resolves to the `GlicHostRegistry`. This promise
diff --git a/chrome/browser/resources/glic/glic_api/request_types.ts b/chrome/browser/resources/glic/glic_api/request_types.ts
index dd675cb..3025b49 100644
--- a/chrome/browser/resources/glic/glic_api/request_types.ts
+++ b/chrome/browser/resources/glic/glic_api/request_types.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import type {GetTabContextErrorReason, TabContextResult, TabData} from '../glic_api/glic_api.js';
+import type {DraggableArea, GetTabContextErrorReason, TabContextResult, TabData} from '../glic_api/glic_api.js';
 
 /*
 This file defines messages sent over postMessage in-between the Glic WebUI
@@ -82,6 +82,12 @@
       actualHeight: number,
     },
   };
+  glicBrowserSetWindowDraggableAreas: {
+    request: {
+      areas: DraggableArea[],
+    },
+    response: void,
+  };
 }
 
 // Types of requests to the GlicWebClient.
diff --git a/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts b/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts
index a0dc2ead..8338fe42 100644
--- a/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts
+++ b/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts
@@ -18,7 +18,7 @@
 import type {BrowserProxy} from '../browser_proxy.js';
 import type {WebClientHandlerInterface, WebClientInterface} from '../glic.mojom-webui.js';
 import {GetTabContextErrorReason as MojoGetTabContextErrorReason, WebClientHandlerRemote, WebClientReceiver} from '../glic.mojom-webui.js';
-import type {Screenshot, WebPageData} from '../glic_api/glic_api.js';
+import type {DraggableArea, Screenshot, WebPageData} from '../glic_api/glic_api.js';
 import {GetTabContextErrorReason} from '../glic_api/glic_api.js';
 import type {PostMessageRequestHandler} from '../glic_api/post_message_transport.js';
 import {PostMessageRequestReceiver, PostMessageRequestSender} from '../glic_api/post_message_transport.js';
@@ -194,6 +194,10 @@
       actualHeight: response.actualSize.height,
     };
   }
+
+  async glicBrowserSetWindowDraggableAreas(request: {areas: DraggableArea[]}) {
+    this.handler.setPanelDraggableAreas(request.areas);
+  }
 }
 
 export class GlicApiHost implements PostMessageRequestHandler {
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index 515417aa..b257737 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -626,12 +626,10 @@
           </category-setting-exceptions>
         </settings-subpage>
       </template>
-      <template is="dom-if" if="[[privateStateTokensEnabled_]]">
-        <template is="dom-if" route-path="/content/autoVerify" no-search>
-          <settings-subpage page-title="$i18n{siteSettingsAntiAbuse}">
-            <settings-anti-abuse-page></settings-anti-abuse-page>
-          </settings-subpage>
-        </template>
+      <template is="dom-if" route-path="/content/autoVerify" no-search>
+        <settings-subpage page-title="$i18n{siteSettingsAntiAbuse}">
+          <settings-anti-abuse-page></settings-anti-abuse-page>
+        </settings-subpage>
       </template>
       <template is="dom-if" route-path="/content/microphone" no-search>
         <settings-subpage page-title="$i18n{siteSettingsCategoryMicrophone}"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.ts b/chrome/browser/resources/settings/privacy_page/privacy_page.ts
index 0db2fc6f..e09c5bd 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.ts
@@ -202,11 +202,6 @@
             loadTimeData.getBoolean('isPrivacySandboxRestrictedNoticeEnabled'),
       },
 
-      privateStateTokensEnabled_: {
-        type: Boolean,
-        value: () => loadTimeData.getBoolean('privateStateTokensEnabled'),
-      },
-
       autoPictureInPictureEnabled_: {
         type: Boolean,
         value: () => loadTimeData.getBoolean('autoPictureInPictureEnabled'),
diff --git a/chrome/browser/resources/settings/route.ts b/chrome/browser/resources/settings/route.ts
index 5ea1056..5f800ae 100644
--- a/chrome/browser/resources/settings/route.ts
+++ b/chrome/browser/resources/settings/route.ts
@@ -92,9 +92,7 @@
         r.SITE_SETTINGS.createChild('smartCardReaders');
   }
   // </if>
-  if (loadTimeData.getBoolean('privateStateTokensEnabled')) {
-    r.SITE_SETTINGS_AUTO_VERIFY = r.SITE_SETTINGS.createChild('autoVerify');
-  }
+  r.SITE_SETTINGS_AUTO_VERIFY = r.SITE_SETTINGS.createChild('autoVerify');
   if (!loadTimeData.getBoolean('enableAiSettingsPageRefresh') &&
       loadTimeData.getBoolean('enableComposeProactiveNudge')) {
     r.OFFER_WRITING_HELP = r.SITE_SETTINGS.createChild('offerWritingHelp');
diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_page.ts b/chrome/browser/resources/settings/site_settings_page/site_settings_page.ts
index 03c3df3e..ed942aa9 100644
--- a/chrome/browser/resources/settings/site_settings_page/site_settings_page.ts
+++ b/chrome/browser/resources/settings/site_settings_page/site_settings_page.ts
@@ -65,7 +65,6 @@
       icon: 'privacy20:person-check',
       enabledLabel: 'siteSettingsAntiAbuseEnabledSubLabel',
       disabledLabel: 'siteSettingsAntiAbuseDisabledSubLabel',
-      shouldShow: () => loadTimeData.getBoolean('privateStateTokensEnabled'),
     },
     {
       route: routes.SITE_SETTINGS_AR,
diff --git a/chrome/browser/safe_browsing/chrome_client_side_detection_service_delegate.cc b/chrome/browser/safe_browsing/chrome_client_side_detection_service_delegate.cc
index 74e84d9..3aa151a 100644
--- a/chrome/browser/safe_browsing/chrome_client_side_detection_service_delegate.cc
+++ b/chrome/browser/safe_browsing/chrome_client_side_detection_service_delegate.cc
@@ -25,6 +25,10 @@
         optimization_guide::OnDeviceModelEligibilityReason::
             kConfigNotAvailableForFeature,
         optimization_guide::OnDeviceModelEligibilityReason::kModelToBeInstalled,
+        optimization_guide::OnDeviceModelEligibilityReason::
+            kSafetyModelNotAvailable,
+        optimization_guide::OnDeviceModelEligibilityReason::
+            kLanguageDetectionModelNotAvailable,
     });
 }  // namespace
 
diff --git a/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc
index d4d9512..99df2fc 100644
--- a/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc
@@ -766,12 +766,28 @@
   CHECK(availability_observer);
 
   // Now that the delegate is observing, send `kConfigNotAvailableForFeature`
-  // first to the observer, which will not stop the observing.
+  // first to the observer, which will not stop the observing. We will then test
+  // for all the possible waitable reasons, which should also not stop
+  // observing.
   availability_observer->OnDeviceModelAvailabilityChanged(
       optimization_guide::ModelBasedCapabilityKey::kScamDetection,
       optimization_guide::OnDeviceModelEligibilityReason::
           kConfigNotAvailableForFeature);
 
+  availability_observer->OnDeviceModelAvailabilityChanged(
+      optimization_guide::ModelBasedCapabilityKey::kScamDetection,
+      optimization_guide::OnDeviceModelEligibilityReason::kModelToBeInstalled);
+
+  availability_observer->OnDeviceModelAvailabilityChanged(
+      optimization_guide::ModelBasedCapabilityKey::kScamDetection,
+      optimization_guide::OnDeviceModelEligibilityReason::
+          kSafetyModelNotAvailable);
+
+  availability_observer->OnDeviceModelAvailabilityChanged(
+      optimization_guide::ModelBasedCapabilityKey::kScamDetection,
+      optimization_guide::OnDeviceModelEligibilityReason::
+          kLanguageDetectionModelNotAvailable);
+
   histogram_tester.ExpectUniqueSample(
       "SBClientPhishing.OnDeviceModelDownloadSuccess", true, 0);
 
diff --git a/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_service_browsertest.cc b/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_service_browsertest.cc
index 749d140..a281f160 100644
--- a/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_service_browsertest.cc
@@ -74,7 +74,6 @@
     scoped_feature_list_.InitWithFeatures(
         /*enabled_features=*/
         {kExtensionTelemetryForEnterprise,
-         kExtensionTelemetryReportContactedHosts,
          kExtensionTelemetryDeclarativeNetRequestActionSignal,
          extensions_features::kIncludeJSCallStackInExtensionApiRequest},
         /*disabled_features=*/
@@ -870,8 +869,7 @@
     scoped_feature_list_.Reset();
     scoped_feature_list_.InitWithFeatures(
         /*enabled_features=*/
-        {kExtensionTelemetryInterceptRemoteHostsContactedInRenderer,
-         kExtensionTelemetryReportContactedHosts},
+        {kExtensionTelemetryInterceptRemoteHostsContactedInRenderer},
         /*disabled_features=*/{});
   }
 };
diff --git a/chrome/browser/search_engine_choice/search_engine_choice_dialog_service_unittest.cc b/chrome/browser/search_engine_choice/search_engine_choice_dialog_service_unittest.cc
index 2362931..3e3c6f4 100644
--- a/chrome/browser/search_engine_choice/search_engine_choice_dialog_service_unittest.cc
+++ b/chrome/browser/search_engine_choice/search_engine_choice_dialog_service_unittest.cc
@@ -49,8 +49,7 @@
       "https://%s/alt#quux={searchTerms}", kCustomSearchEngineDomain));
 
   if (created_by_policy) {
-    data.created_by_policy =
-        TemplateURLData::CreatedByPolicy::kDefaultSearchProvider;
+    data.policy_origin = TemplateURLData::PolicyOrigin::kDefaultSearchProvider;
   }
 
   TemplateURL* template_url =
diff --git a/chrome/browser/search_engines/template_url_service_sync_unittest.cc b/chrome/browser/search_engines/template_url_service_sync_unittest.cc
index 341c45b..4d30cec 100644
--- a/chrome/browser/search_engines/template_url_service_sync_unittest.cc
+++ b/chrome/browser/search_engines/template_url_service_sync_unittest.cc
@@ -499,7 +499,7 @@
   model()->Add(CreateTestTemplateURL(u"key2", "http://key2.com"));
   model()->Add(CreateTestTemplateURL(
       u"key3", "http://key3.com", std::string(), base::Time::FromTimeT(100),
-      false, TemplateURLData::CreatedByPolicy::kDefaultSearchProvider));
+      false, TemplateURLData::PolicyOrigin::kDefaultSearchProvider));
   syncer::SyncDataList all_sync_data =
       model()->GetAllSyncData(syncer::SEARCH_ENGINES);
 
@@ -510,8 +510,7 @@
     std::string guid = GetGUID(*iter);
     TemplateURL* service_turl = model()->GetTemplateURLForGUID(guid);
     std::unique_ptr<TemplateURL> deserialized(Deserialize(*iter));
-    ASSERT_EQ(service_turl->created_by_policy(),
-              TemplateURLData::CreatedByPolicy::kNoPolicy);
+    ASSERT_FALSE(service_turl->CreatedByPolicy());
     AssertEquals(*service_turl, *deserialized);
   }
 }
@@ -697,17 +696,17 @@
   // Duplicate keyword, same hostname
   model()->Add(CreateTestTemplateURL(
       u"key1", "http://key1.com", "localguid1", base::Time::FromTimeT(10),
-      false, TemplateURLData::CreatedByPolicy::kNoPolicy, 111));
+      false, TemplateURLData::PolicyOrigin::kNoPolicy, 111));
 
   // Duplicate keyword, different hostname
   model()->Add(CreateTestTemplateURL(
       u"key2", "http://expected.com", "localguid2", base::Time::FromTimeT(10),
-      false, TemplateURLData::CreatedByPolicy::kNoPolicy, 112));
+      false, TemplateURLData::PolicyOrigin::kNoPolicy, 112));
 
   // Add
   model()->Add(CreateTestTemplateURL(
       u"unique", "http://unique.com", "localguid3", base::Time::FromTimeT(10),
-      false, TemplateURLData::CreatedByPolicy::kNoPolicy, 113));
+      false, TemplateURLData::PolicyOrigin::kNoPolicy, 113));
 
   ASSERT_EQ(3U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
   MergeAndExpectNotify(CreateInitialSyncData(), 1);
@@ -749,8 +748,8 @@
   model()->Add(CreateTestTemplateURL(
       u"key1", "http://key1.com", "localguid1", base::Time::FromTimeT(100),
       /*safe_for_autoreplace=*/false,
-      /*created_by_policy=*/
-      TemplateURLData::CreatedByPolicy::kDefaultSearchProvider));
+      /*policy_origin=*/
+      TemplateURLData::PolicyOrigin::kDefaultSearchProvider));
 
   {
     auto play_api_engine = CreateTestTemplateURL(
@@ -969,7 +968,7 @@
       syncer::SyncChange::ACTION_ADD,
       CreateTestTemplateURL(u"keyword1", "http://aaa.com", std::string(),
                             base::Time::FromTimeT(100), true,
-                            TemplateURLData::CreatedByPolicy::kNoPolicy, 0)));
+                            TemplateURLData::PolicyOrigin::kNoPolicy, 0)));
   changes.push_back(CreateTestSyncChange(
       syncer::SyncChange::ACTION_ADD,
       CreateTestTemplateURL(u"keyword2", "http://bbb.com")));
@@ -1248,7 +1247,7 @@
   data.safe_for_autoreplace = false;
   data.date_created = Time::FromTimeT(100);
   data.last_modified = Time::FromTimeT(100);
-  data.created_by_policy = TemplateURLData::CreatedByPolicy::kNoPolicy;
+  data.policy_origin = TemplateURLData::PolicyOrigin::kNoPolicy;
   data.prepopulate_id = 999999;
   data.sync_guid = "guid2";
   std::unique_ptr<TemplateURL> turl2(new TemplateURL(data));
@@ -1326,7 +1325,7 @@
   data.safe_for_autoreplace = false;
   data.date_created = Time::FromTimeT(100);
   data.last_modified = Time::FromTimeT(100);
-  data.created_by_policy = TemplateURLData::CreatedByPolicy::kNoPolicy;
+  data.policy_origin = TemplateURLData::PolicyOrigin::kNoPolicy;
   data.prepopulate_id = 999999;
   data.sync_guid = "guid2";
   std::unique_ptr<TemplateURL> turl2(new TemplateURL(data));
@@ -2587,7 +2586,7 @@
   std::unique_ptr<TemplateURL> turl(
       CreateTestTemplateURL(u"what", "http://thewhat.com/{searchTerms}",
                             "normal_guid", base::Time::FromTimeT(10), true,
-                            TemplateURLData::CreatedByPolicy::kNoPolicy, 0));
+                            TemplateURLData::PolicyOrigin::kNoPolicy, 0));
   initial_data.push_back(
       TemplateURLService::CreateSyncDataFromTemplateURL(*turl));
 
diff --git a/chrome/browser/search_engines/template_url_service_test_util.cc b/chrome/browser/search_engines/template_url_service_test_util.cc
index d14bc52e..3a3b3801 100644
--- a/chrome/browser/search_engines/template_url_service_test_util.cc
+++ b/chrome/browser/search_engines/template_url_service_test_util.cc
@@ -105,7 +105,7 @@
     const std::string& guid,
     base::Time last_modified,
     bool safe_for_autoreplace,
-    TemplateURLData::CreatedByPolicy created_by_policy,
+    TemplateURLData::PolicyOrigin policy_origin,
     int prepopulate_id) {
   DCHECK(!base::StartsWith(guid, "key"))
       << "Don't use test GUIDs with the form \"key1\". Use \"guid1\" instead "
@@ -119,7 +119,7 @@
   data.safe_for_autoreplace = safe_for_autoreplace;
   data.date_created = base::Time::FromTimeT(100);
   data.last_modified = last_modified;
-  data.created_by_policy = created_by_policy;
+  data.policy_origin = policy_origin;
   data.prepopulate_id = prepopulate_id;
   if (!guid.empty()) {
     data.sync_guid = guid;
diff --git a/chrome/browser/search_engines/template_url_service_test_util.h b/chrome/browser/search_engines/template_url_service_test_util.h
index 3815c08..2caa5bc9 100644
--- a/chrome/browser/search_engines/template_url_service_test_util.h
+++ b/chrome/browser/search_engines/template_url_service_test_util.h
@@ -52,8 +52,8 @@
     const std::string& guid = std::string(),
     base::Time last_modified = base::Time::FromTimeT(100),
     bool safe_for_autoreplace = false,
-    TemplateURLData::CreatedByPolicy created_by_policy =
-        TemplateURLData::CreatedByPolicy::kNoPolicy,
+    TemplateURLData::PolicyOrigin policy_origin =
+        TemplateURLData::PolicyOrigin::kNoPolicy,
     int prepopulate_id = 999999);
 
 class TemplateURLServiceTestUtil : public TemplateURLServiceObserver {
diff --git a/chrome/browser/search_engines/template_url_service_unittest.cc b/chrome/browser/search_engines/template_url_service_unittest.cc
index 63a019f..87e5b960 100644
--- a/chrome/browser/search_engines/template_url_service_unittest.cc
+++ b/chrome/browser/search_engines/template_url_service_unittest.cc
@@ -2626,23 +2626,22 @@
 
 struct EnterpriseSearchTestParam {
   bool choice_enabled;
-  TemplateURLData::CreatedByPolicy created_by_policy;
+  TemplateURLData::PolicyOrigin policy_origin;
 };
 
 static std::string EnterpriseSearchTestParamToTestSuffix(
     const ::testing::TestParamInfo<EnterpriseSearchTestParam>& info) {
   // Note: ensures this only runs for site search and search aggregator
   // policies.
-  CHECK(info.param.created_by_policy ==
-            TemplateURLData::CreatedByPolicy::kSiteSearch ||
-        info.param.created_by_policy ==
-            TemplateURLData::CreatedByPolicy::kSearchAggregator);
+  CHECK(info.param.policy_origin ==
+            TemplateURLData::PolicyOrigin::kSiteSearch ||
+        info.param.policy_origin ==
+            TemplateURLData::PolicyOrigin::kSearchAggregator);
   return base::StringPrintf(
       "%s_%s",
       info.param.choice_enabled ? "SearchEngineChoiceEnabled"
                                 : "SearchEngineChoiceDisabled",
-      info.param.created_by_policy ==
-              TemplateURLData::CreatedByPolicy::kSiteSearch
+      info.param.policy_origin == TemplateURLData::PolicyOrigin::kSiteSearch
           ? "SiteSearch"
           : "SearchAggregator");
 }
@@ -2653,7 +2652,7 @@
  public:
   TemplateURLServiceEnterpriseSearchTest()
       : TemplateURLServiceTestBase(GetParam().choice_enabled),
-        created_by_policy_(GetParam().created_by_policy) {
+        policy_origin_(GetParam().policy_origin) {
     EXPECT_EQ(
         IsSearchEngineChoiceEnabled(),
         base::FeatureList::IsEnabled(switches::kSearchEngineChoiceTrigger));
@@ -2670,7 +2669,7 @@
     data->SetShortName(base::UTF8ToUTF16(keyword + "name"));
     data->SetKeyword(base::UTF8ToUTF16(keyword));
     data->SetURL(std::string("https://") + keyword + ".com/q={searchTerms}");
-    data->created_by_policy = created_by_policy_;
+    data->policy_origin = policy_origin_;
     data->enforced_by_policy = false;
     data->featured_by_policy = featured_by_policy;
     data->is_active = TemplateURLData::ActiveStatus::kTrue;
@@ -2690,7 +2689,7 @@
     return CreateEnterpriseSearchEntry(keyword, /*featured_by_policy=*/false);
   }
 
-  TemplateURLData::CreatedByPolicy created_by_policy_;
+  TemplateURLData::PolicyOrigin policy_origin_;
 };
 
 INSTANTIATE_TEST_SUITE_P(
@@ -2699,18 +2698,16 @@
     ::testing::Values(
         EnterpriseSearchTestParam{
             .choice_enabled = false,
-            .created_by_policy = TemplateURLData::CreatedByPolicy::kSiteSearch},
+            .policy_origin = TemplateURLData::PolicyOrigin::kSiteSearch},
         EnterpriseSearchTestParam{
             .choice_enabled = false,
-            .created_by_policy =
-                TemplateURLData::CreatedByPolicy::kSearchAggregator},
+            .policy_origin = TemplateURLData::PolicyOrigin::kSearchAggregator},
         EnterpriseSearchTestParam{
             .choice_enabled = true,
-            .created_by_policy = TemplateURLData::CreatedByPolicy::kSiteSearch},
+            .policy_origin = TemplateURLData::PolicyOrigin::kSiteSearch},
         EnterpriseSearchTestParam{
             .choice_enabled = true,
-            .created_by_policy =
-                TemplateURLData::CreatedByPolicy::kSearchAggregator}),
+            .policy_origin = TemplateURLData::PolicyOrigin::kSearchAggregator}),
     &EnterpriseSearchTestParamToTestSuffix);
 
 TEST_P(TemplateURLServiceEnterpriseSearchTest,
diff --git a/chrome/browser/sessions/session_data_deleter.cc b/chrome/browser/sessions/session_data_deleter.cc
index 0293b2c..81a37a4f4 100644
--- a/chrome/browser/sessions/session_data_deleter.cc
+++ b/chrome/browser/sessions/session_data_deleter.cc
@@ -8,7 +8,6 @@
 #include <stdint.h>
 
 #include "base/command_line.h"
-#include "base/feature_list.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/ref_counted.h"
@@ -30,15 +29,12 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/storage_usage_info.h"
-#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "net/cookies/cookie_util.h"
-#include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "storage/browser/quota/special_storage_policy.h"
-#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/storage_key/storage_key.h"
 
 namespace {
@@ -153,11 +149,9 @@
   cookie_manager_->DeleteSessionOnlyCookies(
       base::BindOnce(&SessionDataDeleterInternal::OnCookieDeletionDone, this));
 
-  if (base::FeatureList::IsEnabled(network::features::kPrivateStateTokens)) {
-    storage_partition->GetNetworkContext()->ClearTrustTokenSessionOnlyData(
-        base::BindOnce(&SessionDataDeleterInternal::OnTrustTokenDeletionDone,
-                       this));
-  }
+  storage_partition->GetNetworkContext()->ClearTrustTokenSessionOnlyData(
+      base::BindOnce(&SessionDataDeleterInternal::OnTrustTokenDeletionDone,
+                     this));
 
   // Note that from this point on |*this| is kept alive by scoped_refptr<>
   // references automatically taken by |Bind()|, so when the last callback
diff --git a/chrome/browser/speech/speech_recognition_client_browser_interface.cc b/chrome/browser/speech/speech_recognition_client_browser_interface.cc
index 3bd63c1..ced8c2f0 100644
--- a/chrome/browser/speech/speech_recognition_client_browser_interface.cc
+++ b/chrome/browser/speech/speech_recognition_client_browser_interface.cc
@@ -8,12 +8,7 @@
 
 #include "base/feature_list.h"
 #include "base/functional/bind.h"
-#include "base/unguessable_token.h"
-#include "build/build_config.h"
-#include "chrome/browser/accessibility/live_caption/live_caption_controller_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "components/live_caption/live_caption_controller.h"
-#include "components/live_caption/live_caption_ui_remote_driver.h"
 #include "components/live_caption/pref_names.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
@@ -29,7 +24,6 @@
     SpeechRecognitionClientBrowserInterface(content::BrowserContext* context) {
   Profile* profile = Profile::FromBrowserContext(context);
   profile_prefs_ = profile->GetPrefs();
-  controller_ = captions::LiveCaptionControllerFactory::GetForProfile(profile);
 
   pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
   pref_change_registrar_->Init(profile_prefs_);
@@ -50,7 +44,7 @@
       base::BindRepeating(&SpeechRecognitionClientBrowserInterface::
                               OnSpeechRecognitionMaskOffensiveWordsChanged,
                           base::Unretained(this)));
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   pref_change_registrar_->Add(
       prefs::kUserMicrophoneCaptionLanguageCode,
       base::BindRepeating(
@@ -79,7 +73,11 @@
   OnLiveCaptionAvailabilityChanged();
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+void SpeechRecognitionClientBrowserInterface::REMOVED_1() {
+  NOTREACHED();
+}
+
+#if BUILDFLAG(IS_CHROMEOS)
 void SpeechRecognitionClientBrowserInterface::
     BindBabelOrcaSpeechRecognitionBrowserObserver(
         mojo::PendingRemote<media::mojom::SpeechRecognitionBrowserObserver>
@@ -95,22 +93,6 @@
 }
 #endif
 
-void SpeechRecognitionClientBrowserInterface::BindRecognizerToRemoteClient(
-    mojo::PendingReceiver<media::mojom::SpeechRecognitionRecognizerClient>
-        client_receiver,
-    mojo::PendingReceiver<media::mojom::SpeechRecognitionSurfaceClient>
-        surface_client_receiver,
-    mojo::PendingRemote<media::mojom::SpeechRecognitionSurface> surface_remote,
-    media::mojom::SpeechRecognitionSurfaceMetadataPtr metadata) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  ui_drivers_.Add(
-      std::make_unique<captions::LiveCaptionUiRemoteDriver>(
-          controller_, std::move(surface_client_receiver),
-          std::move(surface_remote), metadata->session_id.ToString()),
-      std::move(client_receiver));
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-}
-
 void SpeechRecognitionClientBrowserInterface::OnSodaInstalled(
     speech::LanguageCode language_code) {
   if (waiting_on_live_caption_ &&
@@ -120,13 +102,13 @@
         profile_prefs_->GetBoolean(prefs::kLiveCaptionEnabled));
   }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   if (waiting_on_babel_orca_ && prefs::IsLanguageCodeForMicrophoneCaption(
                                     language_code, profile_prefs_)) {
     waiting_on_babel_orca_ = false;
     NotifyBabelOrcaCaptionObservers(babel_orca_enabled_);
   }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 }
 
 void SpeechRecognitionClientBrowserInterface::
@@ -178,7 +160,7 @@
   }
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 void SpeechRecognitionClientBrowserInterface::OnBabelOrcaAvailabilityChanged(
     bool enabled) {
   if (babel_orca_availability_observers_.empty()) {
@@ -217,5 +199,5 @@
     observer->SpeechRecognitionAvailabilityChanged(enabled);
   }
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 }  // namespace speech
diff --git a/chrome/browser/speech/speech_recognition_client_browser_interface.h b/chrome/browser/speech/speech_recognition_client_browser_interface.h
index 89237e8..3d9ba4a9 100644
--- a/chrome/browser/speech/speech_recognition_client_browser_interface.h
+++ b/chrome/browser/speech/speech_recognition_client_browser_interface.h
@@ -12,15 +12,10 @@
 #include "media/mojo/mojom/speech_recognition.mojom.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/remote_set.h"
-#include "mojo/public/cpp/bindings/unique_receiver_set.h"
 
 class PrefChangeRegistrar;
 class PrefService;
 
-namespace captions {
-class LiveCaptionController;
-}  // namespace captions
-
 namespace content {
 class BrowserContext;
 }  // namespace content
@@ -48,16 +43,10 @@
   void BindSpeechRecognitionBrowserObserver(
       mojo::PendingRemote<media::mojom::SpeechRecognitionBrowserObserver>
           pending_remote) override;
-  void BindRecognizerToRemoteClient(
-      mojo::PendingReceiver<media::mojom::SpeechRecognitionRecognizerClient>
-          client_receiver,
-      mojo::PendingReceiver<media::mojom::SpeechRecognitionSurfaceClient>
-          host_receiver,
-      mojo::PendingRemote<media::mojom::SpeechRecognitionSurface> origin_remote,
-      media::mojom::SpeechRecognitionSurfaceMetadataPtr metadata) override;
+  void REMOVED_1() override;
 
-  // BabelOrca feature methods are ash only.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // BabelOrca feature methods are chromeos only.
+#if BUILDFLAG(IS_CHROMEOS)
   void BindBabelOrcaSpeechRecognitionBrowserObserver(
       mojo::PendingRemote<media::mojom::SpeechRecognitionBrowserObserver>
           pending_remote) override;
@@ -100,12 +89,8 @@
   mojo::ReceiverSet<media::mojom::SpeechRecognitionClientBrowserInterface>
       speech_recognition_client_browser_interface_;
 
-  mojo::UniqueReceiverSet<media::mojom::SpeechRecognitionRecognizerClient>
-      ui_drivers_;
-
   std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
   raw_ptr<PrefService> profile_prefs_;
-  raw_ptr<captions::LiveCaptionController> controller_;
 };
 
 }  // namespace speech
diff --git a/chrome/browser/status_icons/status_icon.cc b/chrome/browser/status_icons/status_icon.cc
index 50667438..cee36cb 100644
--- a/chrome/browser/status_icons/status_icon.cc
+++ b/chrome/browser/status_icons/status_icon.cc
@@ -42,6 +42,11 @@
 
 void StatusIcon::ForceVisible() {}
 
+#if BUILDFLAG(IS_MAC)
+void StatusIcon::SetOpenMenuWithSecondaryClick(
+    bool open_menu_with_secondary_click) {}
+#endif
+
 void StatusIcon::SetContextMenu(std::unique_ptr<StatusIconMenuModel> menu) {
   // The UI may been showing a menu for the current model, don't destroy it
   // until we've notified the UI of the change.
diff --git a/chrome/browser/status_icons/status_icon.h b/chrome/browser/status_icons/status_icon.h
index 54811bb1..f72e8a4 100644
--- a/chrome/browser/status_icons/status_icon.h
+++ b/chrome/browser/status_icons/status_icon.h
@@ -75,6 +75,14 @@
   // thread to do it.  Use sparingly.
   virtual void ForceVisible();
 
+#if BUILDFLAG(IS_MAC)
+  // On mac, if there is a menu, by default primary click will open it and not
+  // call DispatchClickEvent(). Use this function to make the menu open on
+  // secondary click, and dispatch the click event on left click.
+  virtual void SetOpenMenuWithSecondaryClick(
+      bool open_menu_with_secondary_click);
+#endif
+
  protected:
   // Invoked after a call to SetContextMenu() to let the platform-specific
   // subclass update the native context menu based on the new model. If NULL is
diff --git a/chrome/browser/storage_access_api/api_browsertest.cc b/chrome/browser/storage_access_api/api_browsertest.cc
index e6e74f04..38b17cd 100644
--- a/chrome/browser/storage_access_api/api_browsertest.cc
+++ b/chrome/browser/storage_access_api/api_browsertest.cc
@@ -96,16 +96,16 @@
 
 namespace {
 
-constexpr char kHostA[] = "a.test";
-constexpr char kOriginA[] = "https://a.test";
-constexpr char kOriginB[] = "https://b.test";
-constexpr char kUrlA[] = "https://a.test/random.path";
-constexpr char kHostASubdomain[] = "subdomain.a.test";
-constexpr char kHostB[] = "b.test";
-constexpr char kHostBSubdomain[] = "subdomain.b.test";
-constexpr char kHostBSubdomain2[] = "subdomain2.b.test";
-constexpr char kHostC[] = "c.test";
-constexpr char kHostD[] = "d.test";
+constexpr std::string_view kHostA = "a.test";
+constexpr std::string_view kOriginA = "https://a.test";
+constexpr std::string_view kOriginB = "https://b.test";
+constexpr std::string_view kUrlA = "https://a.test/random.path";
+constexpr std::string_view kHostASubdomain = "subdomain.a.test";
+constexpr std::string_view kHostB = "b.test";
+constexpr std::string_view kHostBSubdomain = "subdomain.b.test";
+constexpr std::string_view kHostBSubdomain2 = "subdomain2.b.test";
+constexpr std::string_view kHostC = "c.test";
+constexpr std::string_view kHostD = "d.test";
 
 constexpr char kUseCounterHistogram[] = "Blink.UseCounter.Features";
 constexpr char kRequestOutcomeHistogram[] = "API.StorageAccess.RequestOutcome";
@@ -127,17 +127,17 @@
 enum class TestType { kFrame, kWorker };
 
 // Helpers to express expected
-std::pair<std::string, std::string> CookieBundle(const std::string& cookies) {
+std::pair<std::string, std::string> CookieBundle(std::string_view cookies) {
   DCHECK_NE(cookies, "None");
   DCHECK_NE(cookies, "");
-  return {cookies, cookies};
+  return {std::string(cookies), std::string(cookies)};
 }
 
 std::tuple<std::string, std::string, std::string> CookieBundleWithContent(
-    const std::string& cookies) {
+    std::string_view cookies) {
   DCHECK_NE(cookies, "None");
   DCHECK_NE(cookies, "");
-  return {cookies, cookies, cookies};
+  return {std::string(cookies), std::string(cookies), std::string(cookies)};
 }
 
 constexpr std::pair<const char*, const char*> kNoCookies =
@@ -355,7 +355,7 @@
 
   void TearDownOnMainThread() override { prompt_factory_.reset(); }
 
-  void SetCrossSiteCookieOnDomain(const std::string& domain) {
+  void SetCrossSiteCookieOnDomain(std::string_view domain) {
     GURL domain_url = GetURL(domain);
     std::string cookie = base::StrCat({"cross-site=", domain});
     ASSERT_TRUE(
@@ -365,8 +365,8 @@
                 testing::HasSubstr(cookie));
   }
 
-  void SetPartitionedCookieInContext(const std::string& top_level_host,
-                                     const std::string& embedded_host) {
+  void SetPartitionedCookieInContext(std::string_view top_level_host,
+                                     std::string_view embedded_host) {
     GURL host_url = GetURL(embedded_host);
     std::string cookie =
         base::StrCat({"cross-site=", embedded_host, "(partitioned)"});
@@ -385,7 +385,7 @@
                 testing::HasSubstr(cookie));
   }
 
-  void BlockAllCookiesOnHost(const std::string& host) {
+  void BlockAllCookiesOnHost(std::string_view host) {
     CookieSettingsFactory::GetForProfile(browser()->profile())
         ->SetCookieSetting(GetURL(host), ContentSetting::CONTENT_SETTING_BLOCK);
   }
@@ -404,39 +404,39 @@
                   : content_settings::CookieControlsMode::kOff));
   }
 
-  void NavigateToPage(const std::string& host, const std::string& path) {
+  void NavigateToPage(std::string_view host, std::string_view path) {
     GURL main_url(https_server_.GetURL(host, path));
     ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_url));
   }
 
-  void NavigateToPageWithFrame(const std::string& host,
+  void NavigateToPageWithFrame(std::string_view host,
                                Browser* browser_ptr = nullptr) {
     GURL main_url(https_server_.GetURL(host, "/iframe.html"));
     ASSERT_TRUE(ui_test_utils::NavigateToURL(
         browser_ptr ? browser_ptr : browser(), main_url));
   }
 
-  void NavigateToNewTabWithFrame(const std::string& host) {
+  void NavigateToNewTabWithFrame(std::string_view host) {
     GURL main_url(https_server_.GetURL(host, "/iframe.html"));
     ui_test_utils::NavigateToURLWithDisposition(
         browser(), main_url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
         ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
   }
 
-  void NavigateFrameTo(const std::string& host, const std::string& path) {
+  void NavigateFrameTo(std::string_view host, std::string_view path) {
     NavigateFrameTo(https_server_.GetURL(host, path));
   }
 
   void NavigateFrameTo(const GURL& url,
                        Browser* browser_ptr = nullptr,
-                       const std::string& iframe_id = "test") {
+                       std::string_view iframe_id = "test") {
     content::WebContents* web_contents = (browser_ptr ? browser_ptr : browser())
                                              ->tab_strip_model()
                                              ->GetActiveWebContents();
     EXPECT_TRUE(NavigateIframeToURL(web_contents, iframe_id, url));
   }
 
-  void NavigateNestedFrameTo(const std::string& host, const std::string& path) {
+  void NavigateNestedFrameTo(std::string_view host, std::string_view path) {
     NavigateNestedFrameTo(https_server_.GetURL(host, path));
   }
 
@@ -454,7 +454,7 @@
     load_observer.Wait();
   }
 
-  void NavigateToPageWithTwoFrames(const std::string& host) {
+  void NavigateToPageWithTwoFrames(std::string_view host) {
     GURL main_url(https_server_.GetURL(host, "/two_iframes_blank.html"));
     ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_url));
   }
@@ -471,11 +471,11 @@
     EXPECT_TRUE(NavigateIframeToURL(web_contents, "iframe2", url));
   }
 
-  GURL EchoCookiesURL(const std::string& host) {
+  GURL EchoCookiesURL(std::string_view host) {
     return https_server().GetURL(host, "/echoheader?cookie");
   }
 
-  GURL RedirectViaHosts(const std::vector<std::string>& hosts,
+  GURL RedirectViaHosts(const std::vector<std::string_view>& hosts,
                         const GURL& destination) {
     GURL url = destination;
 
@@ -508,7 +508,7 @@
   // consistent.
   std::pair<std::string, std::string> ReadCookies(
       content::RenderFrameHost* render_frame_host,
-      const std::string& subresource_host) {
+      std::string_view subresource_host) {
     return {
         content::EvalJs(render_frame_host, "document.cookie",
                         content::EXECUTE_SCRIPT_NO_USER_GESTURE)
@@ -525,7 +525,7 @@
   // (via `document.cookie`) are consistent with each other.
   std::tuple<std::string, std::string, std::string> ReadCookiesAndContent(
       content::RenderFrameHost* render_frame_host,
-      const std::string& subresource_host) {
+      std::string_view subresource_host) {
     auto [js_cookies, subresource_cookies] =
         ReadCookies(render_frame_host, subresource_host);
     return {
@@ -2379,7 +2379,7 @@
     : public StorageAccessAPIBaseBrowserTest,
       public testing::WithParamInterface<
           /* (origin, content_setting, is_storage_partitioned) */
-          std::tuple<const char*, ContentSetting, bool>> {
+          std::tuple<std::string_view, ContentSetting, bool>> {
  public:
   std::vector<base::test::FeatureRefAndParams> GetEnabledFeatures() override {
     return GetEnabledFeaturesForStorage(IsStoragePartitioned());
@@ -2415,7 +2415,7 @@
 
   // Derive a test name from parameter information.
   static std::string TestName(const ::testing::TestParamInfo<ParamType>& info) {
-    const char* origin = std::get<0>(info.param);
+    std::string_view origin = std::get<0>(info.param);
     ContentSetting content_setting = std::get<1>(info.param);
     bool is_storage_partitioned = std::get<2>(info.param);
     return base::JoinString(
@@ -2436,7 +2436,7 @@
 
  private:
   ContentSetting GetContentSetting() const { return std::get<1>(GetParam()); }
-  const char* GetContentOrigin() const { return std::get<0>(GetParam()); }
+  std::string_view GetContentOrigin() const { return std::get<0>(GetParam()); }
   bool IsStoragePartitioned() const { return std::get<2>(GetParam()); }
 };
 
diff --git a/chrome/browser/sync/test/integration/single_client_offer_sync_test.cc b/chrome/browser/sync/test/integration/single_client_offer_sync_test.cc
index f3375a8..e3403429 100644
--- a/chrome/browser/sync/test/integration/single_client_offer_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_offer_sync_test.cc
@@ -143,7 +143,7 @@
   // Make sure the data is in the DB.
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
   ASSERT_NE(nullptr, pdm);
-  std::vector<AutofillOfferData*> offers =
+  std::vector<const AutofillOfferData*> offers =
       pdm->payments_data_manager().GetAutofillOffers();
   ASSERT_EQ(1uL, offers.size());
   EXPECT_EQ(999, offers[0]->GetOfferId());
@@ -170,7 +170,7 @@
   // Make sure the card is in the DB.
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
   ASSERT_NE(nullptr, pdm);
-  std::vector<AutofillOfferData*> offers =
+  std::vector<const AutofillOfferData*> offers =
       pdm->payments_data_manager().GetAutofillOffers();
   ASSERT_EQ(1uL, offers.size());
   EXPECT_EQ(999, offers[0]->GetOfferId());
@@ -212,7 +212,7 @@
   // Make sure the card is in the DB.
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
   ASSERT_NE(nullptr, pdm);
-  std::vector<AutofillOfferData*> offers =
+  std::vector<const AutofillOfferData*> offers =
       pdm->payments_data_manager().GetAutofillOffers();
   ASSERT_EQ(1uL, offers.size());
   EXPECT_EQ(999, offers[0]->GetOfferId());
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 6fb7ea25..56976d7 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -202,10 +202,6 @@
     "webui/gcm_internals_ui.h",
     "webui/history_clusters/history_clusters_internals_ui_config.cc",
     "webui/history_clusters/history_clusters_internals_ui_config.h",
-    "webui/internal_debug_pages_disabled/internal_debug_pages_disabled_ui.cc",
-    "webui/internal_debug_pages_disabled/internal_debug_pages_disabled_ui.h",
-    "webui/internal_webui_config.cc",
-    "webui/internal_webui_config.h",
     "webui/interstitials/interstitial_ui.cc",
     "webui/interstitials/interstitial_ui.h",
     "webui/local_state/local_state_ui.cc",
@@ -426,6 +422,7 @@
     "//chrome/browser/ui/tab_contents",
     "//chrome/browser/ui/tab_contents:impl",
     "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:internal_webui_config",
     "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/bluetooth_internals",
     "//chrome/browser/ui/zoom",
diff --git a/chrome/browser/ui/android/device_lock/java/res/layout/device_lock_view.xml b/chrome/browser/ui/android/device_lock/java/res/layout/device_lock_view.xml
index e1a200e..084de81 100644
--- a/chrome/browser/ui/android/device_lock/java/res/layout/device_lock_view.xml
+++ b/chrome/browser/ui/android/device_lock/java/res/layout/device_lock_view.xml
@@ -54,6 +54,7 @@
                 android:layout_marginStart="16dp"
                 android:layout_marginTop="16dp"
                 android:layout_marginEnd="16dp"
+                android:gravity="center"
                 android:text="@string/device_lock_title"
                 android:textAppearance="@style/TextAppearance.Headline.Primary" />
 
@@ -65,9 +66,21 @@
                 android:layout_marginStart="16dp"
                 android:layout_marginTop="16dp"
                 android:layout_marginEnd="16dp"
+                android:gravity="center"
                 android:text="@string/device_lock_description"
                 android:textAppearance="@style/TextAppearance.TextMedium.Primary" />
 
+            <TextView
+                android:id="@+id/device_lock_notice"
+                android:layout_below="@id/device_lock_description"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_margin="20dp"
+                android:padding="16dp"
+                android:gravity="center"
+                android:text="@string/device_lock_notice"
+                android:textAppearance="@style/TextAppearance.TextMedium.Primary" />
+
             <FrameLayout
                 android:id="@+id/device_lock_notice_container"
                 android:layout_below="@id/device_lock_description"
@@ -79,7 +92,7 @@
                 android:background="@drawable/rounded_corner_card">
 
                 <org.chromium.components.browser_ui.widget.text.TextViewWithCompoundDrawables
-                    android:id="@+id/device_lock_notice"
+                    android:id="@+id/device_lock_notice_legacy"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:gravity="start|center_vertical"
diff --git a/chrome/browser/ui/android/device_lock/java/res/layout/missing_device_lock_view.xml b/chrome/browser/ui/android/device_lock/java/res/layout/missing_device_lock_view.xml
index 99a685f..fbd9d0a2 100644
--- a/chrome/browser/ui/android/device_lock/java/res/layout/missing_device_lock_view.xml
+++ b/chrome/browser/ui/android/device_lock/java/res/layout/missing_device_lock_view.xml
@@ -47,6 +47,7 @@
                 android:layout_marginStart="16dp"
                 android:layout_marginTop="16dp"
                 android:layout_marginEnd="16dp"
+                android:gravity="center"
                 android:text="@string/missing_device_lock_title"
                 android:textAppearance="@style/TextAppearance.Headline.Primary" />
 
@@ -58,6 +59,7 @@
                 android:layout_marginStart="16dp"
                 android:layout_marginTop="16dp"
                 android:layout_marginEnd="16dp"
+                android:gravity="center"
                 android:text="@string/missing_device_lock_description"
                 android:textAppearance="@style/TextAppearance.TextMedium.Primary" />
 
diff --git a/chrome/browser/ui/android/device_lock/java/src/org/chromium/chrome/browser/ui/device_lock/DeviceLockView.java b/chrome/browser/ui/android/device_lock/java/src/org/chromium/chrome/browser/ui/device_lock/DeviceLockView.java
index ad31667..84890d1f 100644
--- a/chrome/browser/ui/android/device_lock/java/src/org/chromium/chrome/browser/ui/device_lock/DeviceLockView.java
+++ b/chrome/browser/ui/android/device_lock/java/src/org/chromium/chrome/browser/ui/device_lock/DeviceLockView.java
@@ -7,6 +7,7 @@
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
+import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.LinearLayout;
@@ -16,6 +17,8 @@
 import org.chromium.components.browser_ui.widget.DualControlLayout.ButtonType;
 import org.chromium.components.browser_ui.widget.MaterialProgressBar;
 import org.chromium.components.browser_ui.widget.text.TextViewWithCompoundDrawables;
+import org.chromium.components.signin.SigninFeatureMap;
+import org.chromium.components.signin.SigninFeatures;
 
 /**
  * View that displays the device lock page to users and prompts them to create one if none are
@@ -25,7 +28,8 @@
     private MaterialProgressBar mProgressBar;
     private TextView mTitle;
     private TextView mDescription;
-    private TextViewWithCompoundDrawables mNoticeText;
+    private TextView mNoticeText;
+    private TextViewWithCompoundDrawables mNoticeTextLegacy;
     private DualControlLayout mButtonBar;
     private Button mContinueButton;
     private Button mDismissButton;
@@ -49,6 +53,15 @@
         mProgressBar.setIndeterminate(true);
         mDescription = findViewById(R.id.device_lock_description);
         mNoticeText = findViewById(R.id.device_lock_notice);
+        mNoticeTextLegacy = findViewById(R.id.device_lock_notice_legacy);
+
+        if (SigninFeatureMap.isEnabled(SigninFeatures.UNO_FOR_AUTO)) {
+            findViewById(R.id.device_lock_notice_container).setVisibility(View.GONE);
+            mNoticeText.setVisibility(View.VISIBLE);
+        } else {
+            findViewById(R.id.device_lock_notice_container).setVisibility(View.VISIBLE);
+            mNoticeText.setVisibility(View.GONE);
+        }
 
         mDismissButton =
                 DualControlLayout.createButtonForLayout(
@@ -82,8 +95,10 @@
         return mDescription;
     }
 
-    TextViewWithCompoundDrawables getNoticeText() {
-        return mNoticeText;
+    TextView getNoticeText() {
+        return SigninFeatureMap.isEnabled(SigninFeatures.UNO_FOR_AUTO)
+                ? mNoticeText
+                : mNoticeTextLegacy;
     }
 
     TextView getContinueButton() {
diff --git a/chrome/browser/ui/android/device_lock/java/src/org/chromium/chrome/browser/ui/device_lock/DeviceLockViewBinder.java b/chrome/browser/ui/android/device_lock/java/src/org/chromium/chrome/browser/ui/device_lock/DeviceLockViewBinder.java
index fa46e34..11a9c343 100644
--- a/chrome/browser/ui/android/device_lock/java/src/org/chromium/chrome/browser/ui/device_lock/DeviceLockViewBinder.java
+++ b/chrome/browser/ui/android/device_lock/java/src/org/chromium/chrome/browser/ui/device_lock/DeviceLockViewBinder.java
@@ -13,6 +13,9 @@
 import org.chromium.components.browser_ui.device_lock.DeviceLockActivityLauncher;
 import org.chromium.components.browser_ui.device_lock.DeviceLockDialogMetrics;
 import org.chromium.components.browser_ui.device_lock.DeviceLockDialogMetrics.DeviceLockDialogAction;
+import org.chromium.components.browser_ui.widget.text.TextViewWithCompoundDrawables;
+import org.chromium.components.signin.SigninFeatureMap;
+import org.chromium.components.signin.SigninFeatures;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
@@ -83,7 +86,11 @@
                             model.get(DeviceLockProperties.ON_USER_UNDERSTANDS_CLICKED));
             return;
         }
-        view.getContinueButton().setText(R.string.device_lock_create_lock_button);
+        if (SigninFeatureMap.isEnabled(SigninFeatures.UNO_FOR_AUTO)) {
+            view.getContinueButton().setText(R.string.history_sync_primary_action);
+        } else {
+            view.getContinueButton().setText(R.string.device_lock_create_lock_button);
+        }
         if (model.get(DeviceLockProperties.DEVICE_SUPPORTS_PIN_CREATION_INTENT)) {
             view.getContinueButton()
                     .setOnClickListener(
@@ -101,11 +108,13 @@
             view.getTitle().setTextAppearance(R.style.TextAppearance_Headline_Primary);
             view.getDescription().setTextAppearance(R.style.TextAppearance_TextMedium_Primary);
             view.getNoticeText().setTextAppearance(R.style.TextAppearance_TextMedium_Primary);
-            view.getNoticeText()
-                    .setDrawableTintColor(
-                            AppCompatResources.getColorStateList(
-                                    view.getContext(),
-                                    R.color.default_icon_color_accent1_tint_list));
+            if (!SigninFeatureMap.isEnabled(SigninFeatures.UNO_FOR_AUTO)) {
+                ((TextViewWithCompoundDrawables) view.getNoticeText())
+                        .setDrawableTintColor(
+                                AppCompatResources.getColorStateList(
+                                        view.getContext(),
+                                        R.color.default_icon_color_accent1_tint_list));
+            }
             view.getContinueButton().setEnabled(true);
             view.getDismissButton().setEnabled(true);
         } else {
@@ -113,10 +122,13 @@
             view.getTitle().setTextAppearance(R.style.TextAppearance_Headline_Disabled);
             view.getDescription().setTextAppearance(R.style.TextAppearance_TextMedium_Disabled);
             view.getNoticeText().setTextAppearance(R.style.TextAppearance_TextMedium_Disabled);
-            view.getNoticeText()
-                    .setDrawableTintColor(
-                            AppCompatResources.getColorStateList(
-                                    view.getContext(), R.color.default_text_color_disabled_list));
+            if (!SigninFeatureMap.isEnabled(SigninFeatures.UNO_FOR_AUTO)) {
+                ((TextViewWithCompoundDrawables) view.getNoticeText())
+                        .setDrawableTintColor(
+                                AppCompatResources.getColorStateList(
+                                        view.getContext(),
+                                        R.color.default_text_color_disabled_list));
+            }
             view.getContinueButton().setEnabled(false);
             view.getDismissButton().setEnabled(false);
         }
@@ -130,7 +142,11 @@
                         .setOnClickListener(
                                 model.get(DeviceLockProperties.ON_USE_WITHOUT_AN_ACCOUNT_CLICKED));
             } else {
-                view.getDismissButton().setText(R.string.dialog_not_now);
+                if (SigninFeatureMap.isEnabled(SigninFeatures.UNO_FOR_AUTO)) {
+                    view.getDismissButton().setText(R.string.history_sync_secondary_action);
+                } else {
+                    view.getDismissButton().setText(R.string.dialog_not_now);
+                }
                 view.getDismissButton()
                         .setOnClickListener(model.get(DeviceLockProperties.ON_DISMISS_CLICKED));
             }
diff --git a/chrome/browser/ui/android/device_lock/javatests/src/org/chromium/chrome/browser/ui/device_lock/DeviceLockCoordinatorTest.java b/chrome/browser/ui/android/device_lock/javatests/src/org/chromium/chrome/browser/ui/device_lock/DeviceLockCoordinatorTest.java
index 281c7130..467556e 100644
--- a/chrome/browser/ui/android/device_lock/javatests/src/org/chromium/chrome/browser/ui/device_lock/DeviceLockCoordinatorTest.java
+++ b/chrome/browser/ui/android/device_lock/javatests/src/org/chromium/chrome/browser/ui/device_lock/DeviceLockCoordinatorTest.java
@@ -27,14 +27,17 @@
 import org.chromium.base.test.BaseActivityTestRule;
 import org.chromium.base.test.util.ApplicationTestUtils;
 import org.chromium.base.test.util.Batch;
+import org.chromium.base.test.util.Features;
 import org.chromium.chrome.browser.device_reauth.ReauthenticatorBridge;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.components.browser_ui.device_lock.DeviceLockActivityLauncher;
+import org.chromium.components.signin.SigninFeatures;
 import org.chromium.ui.test.util.BlankUiTestActivity;
 
 /** Tests for {@link DeviceLockCoordinator}. */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @Batch(Batch.UNIT_TESTS)
+@Features.EnableFeatures(SigninFeatures.UNO_FOR_AUTO)
 public class DeviceLockCoordinatorTest {
     @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
 
diff --git a/chrome/browser/ui/android/device_lock/javatests/src/org/chromium/chrome/browser/ui/device_lock/DeviceLockViewBinderTest.java b/chrome/browser/ui/android/device_lock/javatests/src/org/chromium/chrome/browser/ui/device_lock/DeviceLockViewBinderTest.java
index 63db8b11..386ed44a 100644
--- a/chrome/browser/ui/android/device_lock/javatests/src/org/chromium/chrome/browser/ui/device_lock/DeviceLockViewBinderTest.java
+++ b/chrome/browser/ui/android/device_lock/javatests/src/org/chromium/chrome/browser/ui/device_lock/DeviceLockViewBinderTest.java
@@ -37,11 +37,13 @@
 import org.chromium.base.test.BaseActivityTestRule;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.DisabledTest;
+import org.chromium.base.test.util.Features;
 import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.components.browser_ui.device_lock.DeviceLockActivityLauncher;
+import org.chromium.components.signin.SigninFeatures;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 import org.chromium.ui.test.util.BlankUiTestActivity;
@@ -51,6 +53,7 @@
 /** Tests for {@link DeviceLockViewBinder}. */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @Batch(Batch.UNIT_TESTS)
+@Features.EnableFeatures(SigninFeatures.UNO_FOR_AUTO)
 public class DeviceLockViewBinderTest {
     @ClassRule
     public static BaseActivityTestRule<BlankUiTestActivity> sActivityTestRule =
@@ -168,7 +171,7 @@
                 mView.getNoticeText().getText());
         assertEquals(
                 "The continue button should match the version for creating a device lock.",
-                sActivity.getResources().getString(R.string.device_lock_create_lock_button),
+                sActivity.getResources().getString(R.string.history_sync_primary_action),
                 mView.getContinueButton().getText());
         assertEquals(
                 "The continue button should always be visible.",
@@ -227,14 +230,15 @@
     @Test
     @UiThreadTest
     @SmallTest
-    public void testDeviceLockView_inSignInFlowWithNoPreExistingLock_dismissButtonHasNotNowText() {
+    public void
+            testDeviceLockView_inSignInFlowWithNoPreExistingLock_dismissButtonHasNoThanksText() {
         mViewModel.set(SOURCE, DeviceLockActivityLauncher.Source.SYNC_CONSENT);
         mViewModel.set(PREEXISTING_DEVICE_LOCK, false);
 
         assertEquals(
                 "The dismiss button should show 'not now' text when in the sign in flow.",
                 mView.getDismissButton().getText(),
-                sActivity.getResources().getString(R.string.dialog_not_now));
+                sActivity.getResources().getString(R.string.history_sync_secondary_action));
     }
 
     @Test
diff --git a/chrome/browser/ui/android/device_lock/javatests/src/org/chromium/chrome/browser/ui/device_lock/MissingDeviceLockCoordinatorTest.java b/chrome/browser/ui/android/device_lock/javatests/src/org/chromium/chrome/browser/ui/device_lock/MissingDeviceLockCoordinatorTest.java
index 4269d0b..de13a57 100644
--- a/chrome/browser/ui/android/device_lock/javatests/src/org/chromium/chrome/browser/ui/device_lock/MissingDeviceLockCoordinatorTest.java
+++ b/chrome/browser/ui/android/device_lock/javatests/src/org/chromium/chrome/browser/ui/device_lock/MissingDeviceLockCoordinatorTest.java
@@ -30,8 +30,10 @@
 import org.chromium.base.test.BaseActivityTestRule;
 import org.chromium.base.test.util.ApplicationTestUtils;
 import org.chromium.base.test.util.Batch;
+import org.chromium.base.test.util.Features;
 import org.chromium.base.test.util.HistogramWatcher;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.components.signin.SigninFeatures;
 import org.chromium.ui.modaldialog.DialogDismissalCause;
 import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType;
 import org.chromium.ui.test.util.BlankUiTestActivity;
@@ -42,6 +44,7 @@
 /** Tests for {@link MissingDeviceLockCoordinator}. */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @Batch(Batch.UNIT_TESTS)
+@Features.EnableFeatures(SigninFeatures.UNO_FOR_AUTO)
 public class MissingDeviceLockCoordinatorTest {
     @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
 
diff --git a/chrome/browser/ui/android/device_lock/javatests/src/org/chromium/chrome/browser/ui/device_lock/MissingDeviceLockViewBinderTest.java b/chrome/browser/ui/android/device_lock/javatests/src/org/chromium/chrome/browser/ui/device_lock/MissingDeviceLockViewBinderTest.java
index c0029f9..e56ac15 100644
--- a/chrome/browser/ui/android/device_lock/javatests/src/org/chromium/chrome/browser/ui/device_lock/MissingDeviceLockViewBinderTest.java
+++ b/chrome/browser/ui/android/device_lock/javatests/src/org/chromium/chrome/browser/ui/device_lock/MissingDeviceLockViewBinderTest.java
@@ -28,7 +28,9 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseActivityTestRule;
 import org.chromium.base.test.util.Batch;
+import org.chromium.base.test.util.Features;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.components.signin.SigninFeatures;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 import org.chromium.ui.test.util.BlankUiTestActivity;
@@ -38,6 +40,7 @@
 /** Tests for {@link MissingDeviceLockViewBinder}. */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @Batch(Batch.UNIT_TESTS)
+@Features.EnableFeatures(SigninFeatures.UNO_FOR_AUTO)
 public class MissingDeviceLockViewBinderTest {
     @ClassRule
     public static BaseActivityTestRule<BlankUiTestActivity> sActivityTestRule =
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/signin_promo/NtpSigninPromoDelegate.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/signin_promo/NtpSigninPromoDelegate.java
index c6f39e7b..470c374c76 100644
--- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/signin_promo/NtpSigninPromoDelegate.java
+++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/signin_promo/NtpSigninPromoDelegate.java
@@ -30,6 +30,7 @@
     // 14 days in hours.
     @VisibleForTesting static final int NTP_SYNC_PROMO_NTP_SINCE_FIRST_TIME_SHOWN_LIMIT_HOURS = 336;
     @VisibleForTesting static final int NTP_SYNC_PROMO_RESET_AFTER_DAYS = 30;
+    private static final int NTP_SYNC_PROMO_INCREASE_SHOW_COUNT_AFTER_MINUTES = 30;
 
     /**
      * If the signin promo card has been hidden for longer than the {@link
@@ -116,6 +117,22 @@
 
     @Override
     void recordImpression() {
+        final long currentTime = System.currentTimeMillis();
+        final long lastShownTime =
+                ChromeSharedPreferences.getInstance()
+                        .readLong(ChromePreferenceKeys.SIGNIN_PROMO_NTP_LAST_SHOWN_TIME, 0L);
+        if (currentTime - lastShownTime
+                < NTP_SYNC_PROMO_INCREASE_SHOW_COUNT_AFTER_MINUTES * DateUtils.MINUTE_IN_MILLIS) {
+            return;
+        }
+        if (ChromeSharedPreferences.getInstance()
+                        .readLong(ChromePreferenceKeys.SIGNIN_PROMO_NTP_FIRST_SHOWN_TIME)
+                == 0) {
+            ChromeSharedPreferences.getInstance()
+                    .writeLong(ChromePreferenceKeys.SIGNIN_PROMO_NTP_FIRST_SHOWN_TIME, currentTime);
+        }
+        ChromeSharedPreferences.getInstance()
+                .writeLong(ChromePreferenceKeys.SIGNIN_PROMO_NTP_LAST_SHOWN_TIME, currentTime);
         ChromeSharedPreferences.getInstance().incrementInt(getPromoShowCountPreferenceName());
     }
 
diff --git a/chrome/browser/ui/ash/web_view/BUILD.gn b/chrome/browser/ui/ash/web_view/BUILD.gn
index 05491b1a..304e0e8 100644
--- a/chrome/browser/ui/ash/web_view/BUILD.gn
+++ b/chrome/browser/ui/ash/web_view/BUILD.gn
@@ -21,7 +21,6 @@
     "//base",
     "//chrome/browser/media/webrtc",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/ash/new_window:new_window",
     "//content/public/browser",
     "//ui/aura",
     "//ui/base",
diff --git a/chrome/browser/ui/ash/web_view/DEPS b/chrome/browser/ui/ash/web_view/DEPS
index 61a7308..f1f4dbc8 100644
--- a/chrome/browser/ui/ash/web_view/DEPS
+++ b/chrome/browser/ui/ash/web_view/DEPS
@@ -12,12 +12,5 @@
   # Whenever possible, avoid adding new //chrome dependencies to this list.
   "+chrome/browser/media/webrtc",
   "+chrome/browser/profiles",
-  "+chrome/browser/ui/ash/new_window",
   "+chrome/test",
 ]
-
-specific_include_rules = {
-  "ash_web_view_impl_browsertest.cc": [
-    "+chrome/browser/ui/browser.h"
-  ]
-}
diff --git a/chrome/browser/ui/ash/web_view/ash_web_view_impl.cc b/chrome/browser/ui/ash/web_view/ash_web_view_impl.cc
index 44be635..05fa4a72 100644
--- a/chrome/browser/ui/ash/web_view/ash_web_view_impl.cc
+++ b/chrome/browser/ui/ash/web_view/ash_web_view_impl.cc
@@ -4,13 +4,11 @@
 
 #include "chrome/browser/ui/ash/web_view/ash_web_view_impl.h"
 
-#include "ash/public/cpp/new_window_delegate.h"
 #include "ash/public/cpp/window_properties.h"
 #include "base/task/sequenced_task_runner.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/ash/new_window/chrome_new_window_client.h"
 #include "content/public/browser/focused_node_details.h"
 #include "content/public/browser/host_zoom_map.h"
 #include "content/public/browser/media_session.h"
@@ -147,24 +145,6 @@
       source, params, std::move(navigation_handle_callback));
 }
 
-void AshWebViewImpl::ActivateContents(content::WebContents* contents) {
-  // In cases where the widget is not activatable, an `activation_url` may be
-  // provided to show instead.
-  // This is currently used for Focus Mode YTM for when the user clicks on the
-  // media controls view. Since the media window is a custom hidden window, a
-  // separately provided URL tab (navigating to `activation_url`) is shown when
-  // the hidden media window is activated.
-  if (!GetWidget()->CanActivate() && !params_.activation_url.is_empty()) {
-    ChromeNewWindowClient::Get()->OpenUrl(
-        params_.activation_url,
-        ash::NewWindowDelegate::OpenUrlFrom::kUserInteraction,
-        ash::NewWindowDelegate::Disposition::kSwitchToTab);
-    return;
-  }
-
-  content::WebContentsDelegate::ActivateContents(contents);
-}
-
 void AshWebViewImpl::ResizeDueToAutoResize(content::WebContents* web_contents,
                                            const gfx::Size& new_size) {
   DCHECK_EQ(web_contents_.get(), web_contents);
diff --git a/chrome/browser/ui/ash/web_view/ash_web_view_impl.h b/chrome/browser/ui/ash/web_view/ash_web_view_impl.h
index 4fd8dff1..b078a4a 100644
--- a/chrome/browser/ui/ash/web_view/ash_web_view_impl.h
+++ b/chrome/browser/ui/ash/web_view/ash_web_view_impl.h
@@ -66,7 +66,6 @@
       const content::OpenURLParams& params,
       base::OnceCallback<void(content::NavigationHandle&)>
           navigation_handle_callback) override;
-  void ActivateContents(content::WebContents* contents) override;
   void ResizeDueToAutoResize(content::WebContents* web_contents,
                              const gfx::Size& new_size) override;
   bool TakeFocus(content::WebContents* web_contents, bool reverse) override;
diff --git a/chrome/browser/ui/ash/web_view/ash_web_view_impl_browsertest.cc b/chrome/browser/ui/ash/web_view/ash_web_view_impl_browsertest.cc
index 5e53e5d..d9d93dbdd 100644
--- a/chrome/browser/ui/ash/web_view/ash_web_view_impl_browsertest.cc
+++ b/chrome/browser/ui/ash/web_view/ash_web_view_impl_browsertest.cc
@@ -12,13 +12,11 @@
 #include "base/run_loop.h"
 #include "base/scoped_observation.h"
 #include "base/strings/stringprintf.h"
-#include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/browser/host_zoom_map.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/test/browser_test.h"
-#include "content/public/test/test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/views/view.h"
@@ -99,16 +97,12 @@
 
 // Helpers ---------------------------------------------------------------------
 
-std::unique_ptr<views::Widget> CreateWidget(bool activatable = true) {
+std::unique_ptr<views::Widget> CreateWidget() {
   auto widget = std::make_unique<views::Widget>();
 
   views::Widget::InitParams params(
       views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET,
       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
-  params.activatable = activatable
-                           ? views::Widget::InitParams::Activatable::kDefault
-                           : views::Widget::InitParams::Activatable::kNo;
-
   widget->Init(std::move(params));
   return widget;
 }
@@ -316,33 +310,3 @@
   EXPECT_DOUBLE_EQ(
       1.0, content::HostZoomMap::GetZoomLevel(web_view_impl->web_contents()));
 }
-
-// Tests that AshWebViewImpl will open a browser window if the AshWebView is
-// activated (while the widget is not activatable) and provided an
-// `activation_url`.
-IN_PROC_BROWSER_TEST_F(AshWebViewImplBrowserTest, ShouldOpenNewWindow) {
-  auto widget = CreateWidget(/*activatable=*/false);
-  AshWebView::InitParams init_params;
-  const GURL destination_url("https://www.google.com");
-  init_params.activation_url = destination_url;
-
-  AshWebView* web_view =
-      widget->SetContentsView(AshWebViewFactory::Get()->Create(init_params));
-  AshWebViewImpl* web_view_impl = static_cast<AshWebViewImpl*>(web_view);
-
-  web_view->Navigate(CreateDataUrl());
-  EXPECT_DID_STOP_LOADING(web_view);
-
-  content::WebContents* web_contents = web_view_impl->web_contents();
-  web_contents->GetDelegate()->ActivateContents(web_contents);
-
-  // Wait for the browser tab to load.
-  content::RunAllTasksUntilIdle();
-
-  // Verify that the browser was launched with the correct url as the active
-  // tab.
-  ASSERT_TRUE(browser());
-  EXPECT_EQ(
-      destination_url,
-      browser()->tab_strip_model()->GetActiveWebContents()->GetVisibleURL());
-}
diff --git a/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.cc b/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.cc
index d6ec96b..0da2387 100644
--- a/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.cc
+++ b/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.cc
@@ -21,18 +21,13 @@
 using bookmarks::BookmarkModel;
 using bookmarks::BookmarkNode;
 
-namespace {
-
-// Max number of most recently used folders.
-const size_t kMaxMRUFolders = 5;
-
-}  // namespace
-
 struct RecentlyUsedFoldersComboModel::Item {
   enum Type {
     TYPE_NODE,
     TYPE_ALL_BOOKMARKS_NODE,
     TYPE_SEPARATOR,
+    TYPE_ACCOUNT_BOOKMARK_HEADING,
+    TYPE_DEVICE_BOOKMARK_HEADING,
     TYPE_CHOOSE_ANOTHER_FOLDER
   };
 
@@ -62,34 +57,41 @@
     const BookmarkNode* node)
     : bookmark_model_(model), parent_node_(node->parent()) {
   bookmark_model_->AddObserver(this);
-  // Use + 2 to account for bookmark bar and other node.
-  std::vector<const BookmarkNode*> nodes =
-      bookmarks::GetMostRecentlyModifiedUserFolders(model, kMaxMRUFolders + 2);
 
-  for (size_t i = 0; i < nodes.size(); ++i)
-    items_.push_back(Item(nodes[i], Item::TYPE_NODE));
+  const bookmarks::RecentlyUsedFolders mru_bookmarks =
+      bookmarks::GetMostRecentlyUsedFoldersForDisplay(model, node);
 
-  // We special case the placement of these, so remove them from the list, then
-  // fix up the order.
-  RemoveNode(model->bookmark_bar_node());
-  RemoveNode(model->mobile_node());
-  RemoveNode(model->other_node());
-  RemoveNode(node->parent());
+  if (!mru_bookmarks.account_nodes.empty()) {
+    const bool show_labels = !mru_bookmarks.local_nodes.empty();
 
-  // Make the parent the first item, unless it's a permanent node, which is
-  // added below.
-  if (!model->is_permanent_node(node->parent()))
-    items_.insert(items_.begin(), Item(node->parent(), Item::TYPE_NODE));
+    // Add account nodes to `items_`.
+    if (show_labels) {
+      items_.emplace_back(nullptr, Item::TYPE_ACCOUNT_BOOKMARK_HEADING);
+    }
 
-  // Make sure we only have kMaxMRUFolders in the first chunk.
-  if (items_.size() > kMaxMRUFolders)
-    items_.erase(items_.begin() + kMaxMRUFolders, items_.end());
+    for (const BookmarkNode* mru_node : mru_bookmarks.account_nodes) {
+      items_.emplace_back(mru_node, mru_node == model->other_node()
+                                        ? Item::TYPE_ALL_BOOKMARKS_NODE
+                                        : Item::TYPE_NODE);
+    }
 
-  // And put the bookmark bar and other nodes at the end of the list.
-  items_.emplace_back(model->bookmark_bar_node(), Item::TYPE_NODE);
-  items_.emplace_back(model->other_node(), Item::TYPE_ALL_BOOKMARKS_NODE);
-  if (model->mobile_node()->IsVisible())
-    items_.emplace_back(model->mobile_node(), Item::TYPE_NODE);
+    // Add local nodes to `items_`.
+    if (show_labels) {
+      items_.emplace_back(nullptr, Item::TYPE_DEVICE_BOOKMARK_HEADING);
+    }
+
+    for (const BookmarkNode* mru_node : mru_bookmarks.local_nodes) {
+      items_.emplace_back(mru_node, mru_node == model->other_node()
+                                        ? Item::TYPE_ALL_BOOKMARKS_NODE
+                                        : Item::TYPE_NODE);
+    }
+  } else {
+    for (const BookmarkNode* mru_node : mru_bookmarks.local_nodes) {
+      items_.emplace_back(mru_node, Item::TYPE_NODE);
+    }
+  }
+
+  // Add a separator + choose another folder last regardless of account/local.
   items_.emplace_back(nullptr, Item::TYPE_SEPARATOR);
   items_.emplace_back(nullptr, Item::TYPE_CHOOSE_ANOTHER_FOLDER);
 }
@@ -106,6 +108,10 @@
   switch (items_[index].type) {
     case Item::TYPE_NODE:
       return items_[index].node->GetTitle();
+    case Item::TYPE_ACCOUNT_BOOKMARK_HEADING:
+      return l10n_util::GetStringUTF16(IDS_BOOKMARKS_ACCOUNT_BOOKMARKS);
+    case Item::TYPE_DEVICE_BOOKMARK_HEADING:
+      return l10n_util::GetStringUTF16(IDS_BOOKMARKS_DEVICE_BOOKMARKS);
     case Item::TYPE_ALL_BOOKMARKS_NODE:
       return l10n_util::GetStringUTF16(IDS_BOOKMARKS_ALL_BOOKMARKS);
     case Item::TYPE_SEPARATOR:
@@ -122,6 +128,20 @@
   return items_[index].type == Item::TYPE_SEPARATOR;
 }
 
+bool RecentlyUsedFoldersComboModel::IsItemTitleAt(size_t index) const {
+  switch (items_[index].type) {
+    case Item::TYPE_ACCOUNT_BOOKMARK_HEADING:
+    case Item::TYPE_DEVICE_BOOKMARK_HEADING:
+      return true;
+    case Item::TYPE_NODE:
+    case Item::TYPE_SEPARATOR:
+    case Item::TYPE_ALL_BOOKMARKS_NODE:
+    case Item::TYPE_CHOOSE_ANOTHER_FOLDER:
+      return false;
+  }
+  NOTREACHED();
+}
+
 std::optional<size_t> RecentlyUsedFoldersComboModel::GetDefaultIndex() const {
   // TODO(pbos): Ideally we shouldn't have to handle `parent_node_` removal
   // here, the dialog should instead close immediately (and destroy `this`).
diff --git a/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h b/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h
index dc2aa2d..7d5b611f 100644
--- a/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h
+++ b/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h
@@ -37,6 +37,7 @@
   size_t GetItemCount() const override;
   std::u16string GetItemAt(size_t index) const override;
   bool IsItemSeparatorAt(size_t index) const override;
+  bool IsItemTitleAt(size_t index) const override;
   std::optional<size_t> GetDefaultIndex() const override;
 
   // Overridden from bookmarks::BookmarkModelObserver:
diff --git a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
index 51eedd9..dce7ea8 100644
--- a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
+++ b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
@@ -12,6 +12,7 @@
 #include "base/gtest_prod_util.h"
 #include "chrome/browser/status_icons/desktop_notification_balloon.h"
 #include "chrome/browser/status_icons/status_icon.h"
+#include "chrome/browser/status_icons/status_tray.h"
 
 @class MenuControllerCocoa;
 @class NSStatusItem;
@@ -33,9 +34,21 @@
                       const std::u16string& title,
                       const std::u16string& contents,
                       const message_center::NotifierId& notifier_id) override;
+  void SetOpenMenuWithSecondaryClick(
+      bool open_menu_with_secondary_click) override;
 
   bool HasStatusIconMenu();
 
+  // When open_menu_with_secondary_click_ is true, do not set the status item's
+  // menu, so that left click will not open a menu. When a secondary click is
+  // detected, this function is called which creates and sets the menu on the
+  // status item, simulates a click, and then unsets the menu afterwards.
+  void CreateAndOpenMenu();
+
+  bool open_menu_with_secondary_click() {
+    return open_menu_with_secondary_click_;
+  }
+
  protected:
   // Overridden from StatusIcon.
   void UpdatePlatformContextMenu(StatusIconMenuModel* model) override;
@@ -43,6 +56,7 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(StatusIconMacTest, CreateMenu);
   FRIEND_TEST_ALL_PREFIXES(StatusIconMacTest, MenuToolTip);
+  FRIEND_TEST_ALL_PREFIXES(StatusIconMacTest, SecondaryClickMenuNoToolTip);
 
   void SetToolTip(NSString* tool_tip);
   void CreateMenu(ui::MenuModel* model, NSString* tool_tip);
@@ -61,6 +75,18 @@
   // Status menu shown when right-clicking the system icon, if it has been
   // created by |UpdatePlatformContextMenu|.
   MenuControllerCocoa* __strong menu_;
+
+  // Boolean which determines whether the menu should be opened with secondary
+  // clicks. When true, left click will dispatch a click event even if a menu
+  // exists, and right click/control-click will open the menu. Additionally, the
+  // tooltip will be shown when hovering the status icon and not as an entry in
+  // the menu.
+  bool open_menu_with_secondary_click_ = false;
+
+  // Stores the menu model so that it can be created later in
+  // CreateAndOpenMenu(). Only used when open_menu_with_secondary_click_ is
+  // true.
+  raw_ptr<ui::MenuModel> menu_model_ = nullptr;
 };
 
-#endif // CHROME_BROWSER_UI_COCOA_STATUS_ICONS_STATUS_ICON_MAC_H_
+#endif  // CHROME_BROWSER_UI_COCOA_STATUS_ICONS_STATUS_ICON_MAC_H_
diff --git a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm
index e33f89b..f01c4df 100644
--- a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm
+++ b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm
@@ -10,6 +10,7 @@
 #include "base/mac/mac_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/strings/sys_string_conversions.h"
+#include "chrome/browser/status_icons/status_tray.h"
 #include "skia/ext/skia_utils_mac.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/image/image_skia.h"
@@ -32,12 +33,24 @@
 }
 
 - (void)handleClick:(id)sender {
-  // Pass along the click notification to our owner.
   DCHECK(_statusIcon);
+
   // Bring up the status icon menu if there is one, relay the click event
   // otherwise.
-  if (!_statusIcon->HasStatusIconMenu())
+  if (!_statusIcon->HasStatusIconMenu()) {
     _statusIcon->DispatchClickEvent();
+  } else if (_statusIcon->open_menu_with_secondary_click()) {
+    NSEvent* event = [NSApp currentEvent];
+    BOOL secondary_click =
+        ([event type] == NSEventTypeLeftMouseDown &&
+         [event modifierFlags] & NSEventModifierFlagControl) ||
+        ([event type] == NSEventTypeRightMouseUp);
+    if (secondary_click) {
+      _statusIcon->CreateAndOpenMenu();
+    } else if ([event type] == NSEventTypeLeftMouseDown) {
+      _statusIcon->DispatchClickEvent();
+    }
+  }
 }
 
 @end
@@ -82,7 +95,7 @@
   // If we have a status icon menu, make the tool tip part of the menu instead
   // of a pop-up tool tip when hovering the mouse over the image.
   tool_tip_ = base::SysUTF16ToNSString(tool_tip);
-  if (menu_) {
+  if (menu_ && !open_menu_with_secondary_click_) {
     SetToolTip(nil);
     CreateMenu([menu_ model], tool_tip_);
   } else {
@@ -99,13 +112,29 @@
                                contents, notifier_id);
 }
 
+void StatusIconMac::SetOpenMenuWithSecondaryClick(
+    bool open_menu_with_secondary_click) {
+  open_menu_with_secondary_click_ = open_menu_with_secondary_click;
+  [[item() button]
+      sendActionOn:(NSEventMaskLeftMouseDown | NSEventMaskRightMouseUp)];
+}
+
 bool StatusIconMac::HasStatusIconMenu() {
-  return menu_ != nil;
+  return open_menu_with_secondary_click_ ? menu_model_ : menu_ != nil;
+}
+
+void StatusIconMac::CreateAndOpenMenu() {
+  CreateMenu(menu_model_, nil);
+  [[item() button] performClick:nil];
+  [item() setMenu:nil];
 }
 
 void StatusIconMac::UpdatePlatformContextMenu(StatusIconMenuModel* model) {
   if (!model) {
     menu_ = nil;
+  } else if (open_menu_with_secondary_click_) {
+    SetToolTip(tool_tip_);
+    menu_model_ = model;
   } else {
     SetToolTip(nil);
     CreateMenu(model, tool_tip_);
diff --git a/chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm b/chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm
index 7e57328..91cb254 100644
--- a/chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm
@@ -15,6 +15,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "ui/base/resource/resource_bundle.h"
+#import "ui/menus/cocoa/menu_controller.h"
 
 class SkBitmap;
 
@@ -63,3 +64,21 @@
   NSMenuItem* menu_item = [icon->item().menu itemAtIndex:1];
   EXPECT_NSEQ(base::SysUTF16ToNSString(menu_title), menu_item.title);
 }
+
+TEST_F(StatusIconMacTest, SecondaryClickMenuNoToolTip) {
+  // Create a status item with a secondary click menu and set a tool tip. Verify
+  // the tool tip is not inserted as the first menu item.
+  const char16_t menu_title[] = u"Menu Title";
+  const char16_t tool_tip[] = u"Tool tip";
+  std::unique_ptr<StatusIconMenuModel> model =
+      std::make_unique<StatusIconMenuModel>(nullptr);
+  model->AddItem(0, menu_title);
+
+  std::unique_ptr<StatusIconMac> icon = std::make_unique<StatusIconMac>();
+  icon->SetToolTip(tool_tip);
+  icon->SetOpenMenuWithSecondaryClick(true);
+  icon->SetContextMenu(std::move(model));
+  EXPECT_EQ(0, icon->menu_.menu.numberOfItems);
+
+  EXPECT_NSEQ(base::SysUTF16ToNSString(tool_tip), icon->item().button.toolTip);
+}
diff --git a/chrome/browser/ui/color/chrome_color_id.h b/chrome/browser/ui/color/chrome_color_id.h
index dff71d0..5b990c9 100644
--- a/chrome/browser/ui/color/chrome_color_id.h
+++ b/chrome/browser/ui/color/chrome_color_id.h
@@ -588,9 +588,6 @@
   /* Share-this-tab dialog colors. */ \
   E_CPONLY(kColorShareThisTabAudioToggleBackground) \
   E_CPONLY(kColorShareThisTabSourceViewBorder) \
-  /* Experimentation */ \
-  E_CPONLY(kColorShoppingPageActionIconBackgroundVariant) \
-  E_CPONLY(kColorShoppingPageActionIconForegroundVariant) \
   /* Side panel colors. */ \
   E_CPONLY(kColorSidePanelBackground) \
   E_CPONLY(kColorSidePanelBadgeBackground) \
diff --git a/chrome/browser/ui/color/chrome_color_mixer.cc b/chrome/browser/ui/color/chrome_color_mixer.cc
index 806c7b7..cc02478 100644
--- a/chrome/browser/ui/color/chrome_color_mixer.cc
+++ b/chrome/browser/ui/color/chrome_color_mixer.cc
@@ -385,10 +385,6 @@
   mixer[kColorShareThisTabAudioToggleBackground] = {
       ui::kColorSubtleEmphasisBackground};
   mixer[kColorShareThisTabSourceViewBorder] = {ui::kColorMidground};
-  mixer[kColorShoppingPageActionIconBackgroundVariant] = {
-      ui::kColorSysSecondary};
-  mixer[kColorShoppingPageActionIconForegroundVariant] = {
-      ui::kColorSysOnSecondary};
   mixer[kColorSidePanelBackground] = {kColorToolbar};
   mixer[kColorSidePanelContentAreaSeparator] = {ui::kColorSeparator};
   mixer[kColorSidePanelComboboxEntryIcon] = {ui::kColorIcon};
diff --git a/chrome/browser/ui/lens/lens_overlay_live_test.cc b/chrome/browser/ui/lens/lens_overlay_live_test.cc
index 9847be4..f09661fa 100644
--- a/chrome/browser/ui/lens/lens_overlay_live_test.cc
+++ b/chrome/browser/ui/lens/lens_overlay_live_test.cc
@@ -102,24 +102,6 @@
       findAndClickDivWithClass(document.body);
 )";
 
-constexpr char kFindDivWithClassScript[] = R"(
-      function kFindDivWithClassScript(parentElement) {
-        const div = parentElement.querySelector('div.' + $1);
-        if (div) {
-            return true;
-        }
-        for (const child of parentElement.children) {
-            if (kFindDivWithClassScript(child) ||
-                (child.shadowRoot &&
-                    kFindDivWithClassScript(child.shadowRoot))) {
-                return true;
-            }
-        }
-        return false;
-      }
-      kFindDivWithClassScript(document.body);
-)";
-
 // Helper script to fetch an element with a certain ID and click on it.
 constexpr char kFindAndClickElementWithIDScript[] = R"(
   function findAndClickElementWithID(root, id) {
@@ -146,11 +128,6 @@
   findAndClickElementWithID(document, $1);
 )";
 
-// Wait for an animation frame as it takes one to wait for the translated lines
-// to render properly.
-constexpr char kWaitForAnimationFrame[] =
-    "() => new Promise(resolve => requestAnimationFrame(() => resolve(true)))";
-
 const char kNpsUrl[] = "https://www.nps.gov/articles/route-66-overview.htm";
 const char kNpsObjectUrl[] =
     "https://www.nps.gov/common/commonspot/templates/images/graphics/404/"
@@ -159,7 +136,7 @@
     "https://www.nps.gov/subjects/historicpreservationfund/en-espanol.htm";
 }  // namespace
 
-// Live tests for Companion.
+// Live tests for Lens Overlay.
 // These tests can be run with:
 // browser_tests --gtest_filter=LensOverlayLiveTest.* --run-live-tests
 class LensOverlayLiveTest : public signin::test::LiveTest {
@@ -310,37 +287,6 @@
                     ".*source=chrome.cr.menu.*&gsc=2&hl=.*&biw=\\d+&bih=\\d+"));
   }
 
-  void ClickTranslateButtonAndThenText() {
-    // Find and click the translate enable button when it appears on the
-    // overlay.
-    ASSERT_TRUE(base::test::RunUntil([&]() {
-      return EvalJs(content::JsReplace(kFindAndClickElementWithIDScript,
-                                       kTranslateEnableButtonID))
-          .ExtractBool();
-    }));
-
-    // After, wait for the translated lines to appear.
-    ASSERT_TRUE(base::test::RunUntil([&]() {
-      return EvalJs(content::JsReplace(kFindDivWithClassScript,
-                                       kDivTranslatedLineClass))
-          .ExtractBool();
-    }));
-
-    // The translated lines render and then need one animation frame in order
-    // for the overlay to compute their bounding boxes for highlighted lines. If
-    // the overlay does not wait for this computation, then an assertion error
-    // will be thrown.
-    ASSERT_TRUE(content::ExecJs(GetOverlayWebContents()->GetPrimaryMainFrame(),
-                                kWaitForAnimationFrame));
-
-    // Click on the translated line.
-    ASSERT_TRUE(base::test::RunUntil([&]() {
-      return EvalJs(content::JsReplace(kFindAndClickDivWithClassScript,
-                                       kDivTranslatedLineClass))
-          .ExtractBool();
-    }));
-  }
-
   virtual void SetUpFeatureList() {
     feature_list_.InitAndEnableFeatureWithParameters(
         lens::features::kLensOverlay,
@@ -603,10 +549,45 @@
   VerifySidePanelLoaded();
 }
 
-IN_PROC_BROWSER_TEST_F(LensOverlayLiveTest, TranslateScreen_SignedInAndSynced) {
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(lens::features::kLensOverlayTranslateButton);
+// Live tests for LensOverlayTranslateButton.
+class LensOverlayTranslateLiveTest : public LensOverlayLiveTest {
+ public:
+  void ClickTranslateButtonAndThenText() {
+    // Find and click the translate enable button when it appears on the
+    // overlay.
+    ASSERT_TRUE(base::test::RunUntil([&]() {
+      return EvalJs(content::JsReplace(kFindAndClickElementWithIDScript,
+                                       kTranslateEnableButtonID))
+          .ExtractBool();
+    }));
 
+    // The translated lines render and need some time in order
+    // for the overlay to compute their bounding boxes for highlighted lines.
+    // For this reason, keep clicking on the line until the side panel actually
+    // opens.
+    auto* controller = browser()
+                           ->tab_strip_model()
+                           ->GetActiveTab()
+                           ->GetTabFeatures()
+                           ->lens_overlay_controller();
+    ASSERT_TRUE(base::test::RunUntil([&]() {
+      EvalJs(content::JsReplace(kFindAndClickDivWithClassScript,
+                                kDivTranslatedLineClass));
+      return controller->state() == State::kOverlayAndResults;
+    }));
+  }
+
+  void SetUpFeatureList() override {
+    feature_list_.InitWithFeaturesAndParameters(
+        {{lens::features::kLensOverlay,
+          {{"enable-shimmer", "false"}, {"use-blur", "false"}}},
+         {features::kLensOverlayTranslateButton, {}}},
+        {});
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(LensOverlayTranslateLiveTest,
+                       TranslateScreen_SignedInAndSynced) {
   std::optional<signin::TestAccountSigninCredentials> test_account =
       GetTestAccounts()->GetAccount("INTELLIGENCE_ACCOUNT");
   // Sign in and sync to opted in test account.
@@ -646,10 +627,8 @@
   VerifySidePanelLoaded();
 }
 
-IN_PROC_BROWSER_TEST_F(LensOverlayLiveTest, TranslateScreen_SignedInNotSynced) {
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(lens::features::kLensOverlayTranslateButton);
-
+IN_PROC_BROWSER_TEST_F(LensOverlayTranslateLiveTest,
+                       TranslateScreen_SignedInNotSynced) {
   std::optional<signin::TestAccountSigninCredentials> test_account =
       GetTestAccounts()->GetAccount("INTELLIGENCE_ACCOUNT");
   // Sign in but do not sync to opted in test account.
@@ -689,10 +668,8 @@
   VerifySidePanelLoaded();
 }
 
-IN_PROC_BROWSER_TEST_F(LensOverlayLiveTest, TranslateScreen_SignedOut) {
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(lens::features::kLensOverlayTranslateButton);
-
+IN_PROC_BROWSER_TEST_F(LensOverlayTranslateLiveTest,
+                       TranslateScreen_SignedOut) {
   // Navigate to a website and wait for paint before starting controller.
   WaitForPaint(kNpsTranslateUrl);
   EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
@@ -713,7 +690,7 @@
   ASSERT_EQ(side_panel_coordinator()->GetCurrentEntryId(), std::nullopt);
   ASSERT_TRUE(content::WaitForLoadStop(GetOverlayWebContents()));
 
-  // Confirm that the WebUI has reported that it is ready. This means the local
+  // Confirm that the WebUI has reported that i1t is ready. This means the local
   // DOM should be initialized on our WebUI.
   WaitForHistogram("Lens.Overlay.TimeToWebUIReady");
 
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer_unittest.cc b/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer_unittest.cc
index 1131948..587db02 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer_unittest.cc
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer_unittest.cc
@@ -108,8 +108,8 @@
 
   TemplateURLData policy_turl;
   policy_turl.SetKeyword(policy_search_keyword());
-  policy_turl.created_by_policy =
-      TemplateURLData::CreatedByPolicy::kDefaultSearchProvider;
+  policy_turl.policy_origin =
+      TemplateURLData::PolicyOrigin::kDefaultSearchProvider;
   factory_util.model()->Add(std::make_unique<TemplateURL>(policy_turl));
 
   TemplateURLData starter_pack_turl;
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
index b8e656f..69fbb9a 100644
--- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -1492,8 +1492,8 @@
         TemplateURLServiceFactory::GetForProfile(browser()->profile())
             ->GetTemplateURLForKeyword(kSiteSearchPolicyKeyword);
     ASSERT_TRUE(turl);
-    EXPECT_EQ(turl->created_by_policy(),
-              TemplateURLData::CreatedByPolicy::kSiteSearch);
+    EXPECT_EQ(turl->policy_origin(),
+              TemplateURLData::PolicyOrigin::kSiteSearch);
     EXPECT_EQ(turl->short_name(), kSiteSearchPolicyName);
     EXPECT_EQ(turl->url(), kSiteSearchPolicyURL);
     EXPECT_FALSE(turl->featured_by_policy());
@@ -1538,8 +1538,8 @@
         TemplateURLServiceFactory::GetForProfile(browser()->profile())
             ->GetTemplateURLForKeyword(kSiteSearchPolicyKeywordWithAtPrefix);
     ASSERT_TRUE(turl);
-    EXPECT_EQ(turl->created_by_policy(),
-              TemplateURLData::CreatedByPolicy::kSiteSearch);
+    EXPECT_EQ(turl->policy_origin(),
+              TemplateURLData::PolicyOrigin::kSiteSearch);
     EXPECT_EQ(turl->short_name(), kSiteSearchPolicyName);
     EXPECT_EQ(turl->url(), kSiteSearchPolicyURL);
     EXPECT_TRUE(turl->featured_by_policy());
@@ -1587,8 +1587,8 @@
         TemplateURLServiceFactory::GetForProfile(browser()->profile())
             ->GetTemplateURLForKeyword(kSiteSearchPolicyKeywordWithAtPrefix);
     ASSERT_TRUE(turl);
-    EXPECT_EQ(turl->created_by_policy(),
-              TemplateURLData::CreatedByPolicy::kSiteSearch);
+    EXPECT_EQ(turl->policy_origin(),
+              TemplateURLData::PolicyOrigin::kSiteSearch);
     EXPECT_EQ(turl->short_name(), kSiteSearchPolicyName);
     EXPECT_EQ(turl->url(), kSiteSearchPolicyURL);
     EXPECT_TRUE(turl->featured_by_policy());
@@ -1659,8 +1659,8 @@
         TemplateURLServiceFactory::GetForProfile(browser()->profile())
             ->GetTemplateURLForKeyword(kSearchAggregatorPolicyKeyword);
     ASSERT_TRUE(turl);
-    EXPECT_EQ(turl->created_by_policy(),
-              TemplateURLData::CreatedByPolicy::kSearchAggregator);
+    EXPECT_EQ(turl->policy_origin(),
+              TemplateURLData::PolicyOrigin::kSearchAggregator);
     EXPECT_EQ(turl->short_name(), kSearchAggregatorPolicyName);
     EXPECT_EQ(turl->url(), kSearchAggregatorPolicySearchUrl);
     EXPECT_EQ(turl->suggestions_url(), kSearchAggregatorPolicySuggestUrl);
@@ -1712,8 +1712,8 @@
             ->GetTemplateURLForKeyword(
                 kSearchAggregatorPolicyKeywordWithAtPrefix);
     ASSERT_TRUE(turl);
-    EXPECT_EQ(turl->created_by_policy(),
-              TemplateURLData::CreatedByPolicy::kSearchAggregator);
+    EXPECT_EQ(turl->policy_origin(),
+              TemplateURLData::PolicyOrigin::kSearchAggregator);
     EXPECT_EQ(turl->short_name(), kSearchAggregatorPolicyName);
     EXPECT_EQ(turl->url(), kSearchAggregatorPolicySearchUrl);
     EXPECT_EQ(turl->suggestions_url(), kSearchAggregatorPolicySuggestUrl);
@@ -1770,8 +1770,8 @@
             ->GetTemplateURLForKeyword(
                 kSearchAggregatorPolicyKeywordWithAtPrefix);
     ASSERT_TRUE(turl);
-    EXPECT_EQ(turl->created_by_policy(),
-              TemplateURLData::CreatedByPolicy::kSearchAggregator);
+    EXPECT_EQ(turl->policy_origin(),
+              TemplateURLData::PolicyOrigin::kSearchAggregator);
     EXPECT_EQ(turl->short_name(), kSearchAggregatorPolicyName);
     EXPECT_EQ(turl->url(), kSearchAggregatorPolicySearchUrl);
     EXPECT_EQ(turl->suggestions_url(), kSearchAggregatorPolicySuggestUrl);
diff --git a/chrome/browser/ui/search_engines/keyword_editor_controller.cc b/chrome/browser/ui/search_engines/keyword_editor_controller.cc
index a686767e..cacac31 100644
--- a/chrome/browser/ui/search_engines/keyword_editor_controller.cc
+++ b/chrome/browser/ui/search_engines/keyword_editor_controller.cc
@@ -95,13 +95,9 @@
 }
 
 bool KeywordEditorController::IsManaged(const TemplateURL* url) const {
-  return (url->created_by_policy() ==
-              TemplateURLData::CreatedByPolicy::kDefaultSearchProvider &&
+  return (url->CreatedByDefaultSearchProviderPolicy() &&
           url->enforced_by_policy()) ||
-         (url->created_by_policy() ==
-          TemplateURLData::CreatedByPolicy::kSiteSearch) ||
-         (url->created_by_policy() ==
-          TemplateURLData::CreatedByPolicy::kSearchAggregator);
+         url->CreatedByNonDefaultSearchProviderPolicy();
 }
 
 void KeywordEditorController::RemoveTemplateURL(int index) {
diff --git a/chrome/browser/ui/search_engines/keyword_editor_controller_unittest.cc b/chrome/browser/ui/search_engines/keyword_editor_controller_unittest.cc
index 6492848..285e51a7 100644
--- a/chrome/browser/ui/search_engines/keyword_editor_controller_unittest.cc
+++ b/chrome/browser/ui/search_engines/keyword_editor_controller_unittest.cc
@@ -81,8 +81,8 @@
     managed_engine.SetShortName(kManaged);
     managed_engine.SetKeyword(kManaged);
     managed_engine.SetURL(url);
-    managed_engine.created_by_policy =
-        TemplateURLData::CreatedByPolicy::kDefaultSearchProvider;
+    managed_engine.policy_origin =
+        TemplateURLData::PolicyOrigin::kDefaultSearchProvider;
     managed_engine.enforced_by_policy = is_mandatory;
     is_mandatory
         ? SetManagedDefaultSearchPreferences(managed_engine, true, &profile_)
@@ -388,12 +388,11 @@
   data.SetShortName(test_case.short_name);
   data.is_active = test_case.is_active ? TemplateURLData::ActiveStatus::kTrue
                                        : TemplateURLData::ActiveStatus::kFalse;
-  data.created_by_policy =
-      test_case.created_by_search_aggregator_policy
-          ? TemplateURLData::CreatedByPolicy::kSearchAggregator
-      : test_case.created_by_site_search_policy
-          ? TemplateURLData::CreatedByPolicy::kSiteSearch
-          : TemplateURLData::CreatedByPolicy::kNoPolicy;
+  data.policy_origin = test_case.created_by_search_aggregator_policy
+                           ? TemplateURLData::PolicyOrigin::kSearchAggregator
+                       : test_case.created_by_site_search_policy
+                           ? TemplateURLData::PolicyOrigin::kSiteSearch
+                           : TemplateURLData::PolicyOrigin::kNoPolicy;
   data.featured_by_policy = test_case.featured_by_policy;
   data.safe_for_autoreplace = test_case.safe_for_autoreplace;
   return std::make_unique<TemplateURL>(data);
diff --git a/chrome/browser/ui/search_engines/template_url_table_model.cc b/chrome/browser/ui/search_engines/template_url_table_model.cc
index f6a081d..90c7181e 100644
--- a/chrome/browser/ui/search_engines/template_url_table_model.cc
+++ b/chrome/browser/ui/search_engines/template_url_table_model.cc
@@ -65,8 +65,7 @@
   auto get_sort_key = [this](const TemplateURL* engine) {
     return std::make_tuple(
         // Enterprise site search engines are shown before other engines.
-        engine->created_by_policy() !=
-            TemplateURLData::CreatedByPolicy::kSiteSearch,
+        engine->policy_origin() != TemplateURLData::PolicyOrigin::kSiteSearch,
         // Try to compare short names ignoring case and diacriticals.
         collator_ ? GetShortNameSortKey(engine->short_name()) : std::string(),
         // If a collator is not available, fallback to regular string
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_observer.cc b/chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_observer.cc
index eaf4e3351e..77fc25b 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_observer.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_observer.cc
@@ -48,14 +48,11 @@
   return tab_strip;
 }
 
-// Returns the local tab group ID from the PersistentMessage. Asserts tab
-// group metadata exists and contains the group ID.
-LocalTabGroupID UnwrapTabGroupID(PersistentMessage message) {
+// Returns the local tab group ID from the PersistentMessage.
+std::optional<LocalTabGroupID> UnwrapTabGroupID(PersistentMessage message) {
   auto tab_group_metadata = message.attribution.tab_group_metadata;
   CHECK(tab_group_metadata.has_value());
-  auto local_tab_group_id = tab_group_metadata->local_tab_group_id;
-  CHECK(local_tab_group_id.has_value());
-  return local_tab_group_id.value();
+  return tab_group_metadata->local_tab_group_id;
 }
 
 // Returns the tab strip index of the tab. If the sync service is not
@@ -103,21 +100,30 @@
                                      Profile* profile) {
   // Get tab group ID.
   auto local_tab_group_id = UnwrapTabGroupID(message);
+  if (!local_tab_group_id) {
+    // The LocalTabGroupID is not guaranteed to be available from the
+    // MessagingBackenddService, so we need to handle this case gracefully.
+    return std::nullopt;
+  }
 
   // Get tab ID.
   auto tab_metadata = message.attribution.tab_metadata;
   CHECK(tab_metadata.has_value());
   auto local_tab_id = tab_metadata->local_tab_id;
-  CHECK(local_tab_id.has_value());
+  if (!local_tab_id.has_value()) {
+    // The LocalTabID is not guaranteed to be available from the
+    // MessagingBackenddService, so we need to handle this case gracefully.
+    return std::nullopt;
+  }
 
   // Get tab index.
   auto tabstrip_index =
-      GetTabStripIndex(*local_tab_id, local_tab_group_id, profile);
+      GetTabStripIndex(*local_tab_id, *local_tab_group_id, profile);
   if (!tabstrip_index.has_value()) {
     return std::nullopt;
   }
 
-  return TabInfo(*local_tab_id, local_tab_group_id, *tabstrip_index);
+  return TabInfo(*local_tab_id, *local_tab_group_id, *tabstrip_index);
 }
 
 }  // namespace
@@ -127,10 +133,15 @@
     MessageDisplayStatus display) {
   // DIRTY_TAB_GROUP notifications may not have tab metadata. Only the
   // group metadata is needed here.
-  LocalTabGroupID local_tab_group_id = UnwrapTabGroupID(message);
+  std::optional<LocalTabGroupID> local_tab_group_id = UnwrapTabGroupID(message);
+  if (!local_tab_group_id) {
+    // The LocalTabGroupID is not guaranteed to be available from the
+    // MessagingBackenddService, so we need to handle this case gracefully.
+    return;
+  }
 
-  GetTabStripWithGroup(local_tab_group_id)
-      ->SetTabGroupNeedsAttention(local_tab_group_id,
+  GetTabStripWithGroup(*local_tab_group_id)
+      ->SetTabGroupNeedsAttention(*local_tab_group_id,
                                   display == MessageDisplayStatus::kDisplay);
 }
 
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc
index fb3a58f..89784b38 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc
@@ -37,15 +37,18 @@
 #include "components/feature_engagement/public/feature_constants.h"
 #include "components/feature_engagement/test/mock_tracker.h"
 #include "components/signin/public/identity_manager/identity_test_utils.h"
+#include "components/sync/base/features.h"
 #include "components/sync/test/test_sync_service.h"
 #include "components/ukm/test_ukm_recorder.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "ui/base/interaction/element_identifier.h"
 #include "ui/base/interaction/element_tracker.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
+#include "ui/views/controls/combobox/combobox.h"
 #include "ui/views/interaction/element_tracker_views.h"
 #include "ui/views/test/widget_test.h"
 #include "ui/views/widget/unique_widget_ptr.h"
+
 using bookmarks::BookmarkModel;
 
 namespace {
@@ -140,14 +143,17 @@
 
   const bookmarks::BookmarkNode* GetBookmark() { return bookmark_node_; }
 
-  PriceTrackingView* GetPriceTrackingView() {
+  views::View* GetViewInBookmarkBubble(ui::ElementIdentifier id) {
     const ui::ElementContext context =
         views::ElementTrackerViews::GetContextForView(
             BookmarkBubbleView::bookmark_bubble()->GetAnchorView());
-    views::View* matched_view =
-        views::ElementTrackerViews::GetInstance()->GetFirstMatchingView(
-            kPriceTrackingBookmarkViewElementId, context);
+    return views::ElementTrackerViews::GetInstance()->GetFirstMatchingView(
+        id, context);
+  }
 
+  PriceTrackingView* GetPriceTrackingView() {
+    views::View* const matched_view =
+        GetViewInBookmarkBubble(kPriceTrackingBookmarkViewElementId);
     return matched_view ? views::AsViewClass<PriceTrackingView>(matched_view)
                         : nullptr;
   }
@@ -416,7 +422,7 @@
   const ui::ElementContext context =
       views::ElementTrackerViews::GetContextForView(
           BookmarkBubbleView::bookmark_bubble()->GetAnchorView());
-  views::View* iph_root =
+  views::View* const iph_root =
       views::ElementTrackerViews::GetInstance()->GetFirstMatchingView(
           commerce::kShoppingCollectionIPHViewId, context);
 
@@ -425,3 +431,29 @@
   EXPECT_FALSE(
       BookmarkBubbleView::bookmark_bubble()->GetFootnoteViewForTesting());
 }
+
+class BookmarkBubbleViewWithAccountBookmarksTest
+    : public BookmarkBubbleViewTestBase {
+ public:
+  BookmarkBubbleViewWithAccountBookmarksTest() {
+    test_features_.InitAndEnableFeature(
+        syncer::kSyncEnableBookmarksInTransportMode);
+  }
+};
+
+// Verifies that the bookmark bubble correctly instantiates a combobox that
+// separates account bookmarks and local bookmarks with headers. It also
+// verifies that RecentlyUsedFoldersComboModel correctly reports those as
+// "title" items and that ComboboxMenuModel correctly translates that to a
+// TYPE_TITLE item that can be rendered differently when the popup menu is
+// displayed.
+TEST_F(BookmarkBubbleViewWithAccountBookmarksTest,
+       ComboboxUsesTitlesForHeaders) {
+  GetBookmarkModel()->CreateAccountPermanentFolders();
+  CreateBubbleView();
+  EXPECT_EQ(ui::MenuModel::TYPE_TITLE,
+            views::AsViewClass<views::Combobox>(
+                GetViewInBookmarkBubble(kBookmarkFolderFieldId))
+                ->menu_model_for_testing()
+                ->GetTypeAt(0));
+}
diff --git a/chrome/browser/ui/views/commerce/price_insights_icon_view.cc b/chrome/browser/ui/views/commerce/price_insights_icon_view.cc
index 40fd0fa..c542e8d 100644
--- a/chrome/browser/ui/views/commerce/price_insights_icon_view.cc
+++ b/chrome/browser/ui/views/commerce/price_insights_icon_view.cc
@@ -42,11 +42,6 @@
   SetProperty(views::kElementIdentifierKey, kPriceInsightsChipElementId);
   GetViewAccessibility().SetName(
       l10n_util::GetStringUTF16(IDS_SHOPPING_INSIGHTS_ICON_TOOLTIP_TEXT));
-
-  if (base::FeatureList::IsEnabled(commerce::kShoppingIconColorVariant)) {
-    SetCustomForegroundColorId(kColorShoppingPageActionIconForegroundVariant);
-    SetCustomBackgroundColorId(kColorShoppingPageActionIconBackgroundVariant);
-  }
 }
 PriceInsightsIconView::~PriceInsightsIconView() = default;
 
diff --git a/chrome/browser/ui/views/commerce/price_tracking_icon_view.cc b/chrome/browser/ui/views/commerce/price_tracking_icon_view.cc
index 2a3ade6..765bd9b 100644
--- a/chrome/browser/ui/views/commerce/price_tracking_icon_view.cc
+++ b/chrome/browser/ui/views/commerce/price_tracking_icon_view.cc
@@ -86,14 +86,6 @@
   SetProperty(views::kElementIdentifierKey, kPriceTrackingChipElementId);
   GetViewAccessibility().SetName(
       l10n_util::GetStringUTF16(IDS_OMNIBOX_TRACK_PRICE));
-
-  SetUseTonalColorsWhenExpanded(
-      base::FeatureList::IsEnabled(commerce::kPriceTrackingIconColors));
-
-  if (base::FeatureList::IsEnabled(commerce::kShoppingIconColorVariant)) {
-    SetCustomForegroundColorId(kColorShoppingPageActionIconForegroundVariant);
-    SetCustomBackgroundColorId(kColorShoppingPageActionIconBackgroundVariant);
-  }
 }
 
 PriceTrackingIconView::~PriceTrackingIconView() = default;
diff --git a/chrome/browser/ui/views/glic/glic_view.cc b/chrome/browser/ui/views/glic/glic_view.cc
index 36fa299..711f74a 100644
--- a/chrome/browser/ui/views/glic/glic_view.cc
+++ b/chrome/browser/ui/views/glic/glic_view.cc
@@ -56,4 +56,18 @@
 
   return {std::move(widget), raw_glic_view};
 }
+
+void GlicView::SetDraggableAreas(
+    const std::vector<gfx::Rect>& draggable_areas) {
+  draggable_areas_.assign(draggable_areas.begin(), draggable_areas.end());
+}
+
+bool GlicView::IsPointWithinDraggableArea(const gfx::Point& point) {
+  for (const gfx::Rect& rect : draggable_areas_) {
+    if (rect.Contains(point)) {
+      return true;
+    }
+  }
+  return false;
+}
 }  // namespace glic
diff --git a/chrome/browser/ui/views/glic/glic_view.h b/chrome/browser/ui/views/glic/glic_view.h
index 6a1d9914..0b5d9669 100644
--- a/chrome/browser/ui/views/glic/glic_view.h
+++ b/chrome/browser/ui/views/glic/glic_view.h
@@ -36,10 +36,17 @@
       Profile* profile,
       const gfx::Rect& initial_bounds);
 
+  void SetDraggableAreas(const std::vector<gfx::Rect>& draggable_areas);
+
+  bool IsPointWithinDraggableArea(const gfx::Point& point);
+
   views::WebView* web_view() { return web_view_; }
 
  private:
   raw_ptr<GlicWebView> web_view_;
+  // Defines the areas of the view from which it can be dragged. These areas can
+  // be updated by the glic web client.
+  std::vector<gfx::Rect> draggable_areas_;
 
   // Ensures that the profile associated with this view isn't destroyed while
   // it is visible.
diff --git a/chrome/browser/ui/views/location_bar/intent_chip_button_browsertest.cc b/chrome/browser/ui/views/location_bar/intent_chip_button_browsertest.cc
index 6250612..0cb422d4b 100644
--- a/chrome/browser/ui/views/location_bar/intent_chip_button_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/intent_chip_button_browsertest.cc
@@ -11,6 +11,7 @@
 #include "base/functional/callback.h"
 #include "base/functional/callback_forward.h"
 #include "base/scoped_observation.h"
+#include "base/strings/strcat.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/user_action_tester.h"
@@ -309,26 +310,21 @@
 
     const auto* const test_info =
         testing::UnitTest::GetInstance()->current_test_info();
+    // Verify against the Skia gold result baseline from crrev.com/c/6092068.
+    // TODO(crbug.com/384567062): Support set_baseline() in UiBrowserTest.
+    const std::string screenshot_name = base::StrCat(
+        {test_info->test_suite_name(), "_", test_info->name(), "_6092068"});
     return VerifyPixelUi(location_bar, test_info->test_suite_name(),
-                         test_info->name()) != ui::test::ActionResult::kFailed;
+                         screenshot_name) != ui::test::ActionResult::kFailed;
   }
 
-  void WaitForUserDismissal() override {
-    // Consider closing the browser to be dismissal.
-    ui_test_utils::WaitForBrowserToClose();
-  }
+  void WaitForUserDismissal() override {}
 
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-// TODO(crbug.com/340814277): Flaky on Windows.
-#if BUILDFLAG(IS_WIN)
-#define MAYBE_InvokeUi_default DISABLED_InvokeUi_default
-#else
-#define MAYBE_InvokeUi_default InvokeUi_default
-#endif
-IN_PROC_BROWSER_TEST_P(IntentChipButtonBrowserUiTest, MAYBE_InvokeUi_default) {
+IN_PROC_BROWSER_TEST_P(IntentChipButtonBrowserUiTest, InvokeUi_default) {
   ShowAndVerifyUi();
 }
 
diff --git a/chrome/browser/ui/webauthn/sheet_models.cc b/chrome/browser/ui/webauthn/sheet_models.cc
index 7897f8dd..74f6795 100644
--- a/chrome/browser/ui/webauthn/sheet_models.cc
+++ b/chrome/browser/ui/webauthn/sheet_models.cc
@@ -1381,6 +1381,16 @@
     RecordOnboardingEvent(webauthn::metrics::OnboardingEvents::kFailure);
   }
   webauthn::user_actions::RecordGpmFailureShown();
+  switch (dialog_model->request_type) {
+    case device::FidoRequestType::kGetAssertion:
+      RecordGPMGetAssertionEvent(
+          webauthn::metrics::GPMGetAssertionEvents::kFailure);
+      break;
+    case device::FidoRequestType::kMakeCredential:
+      RecordGPMMakeCredentialEvent(
+          webauthn::metrics::GPMMakeCredentialEvents::kFailure);
+      break;
+  }
 }
 
 AuthenticatorGPMErrorSheetModel::~AuthenticatorGPMErrorSheetModel() = default;
diff --git a/chrome/browser/ui/webui/BUILD.gn b/chrome/browser/ui/webui/BUILD.gn
index 73bb6d8..281c5e7 100644
--- a/chrome/browser/ui/webui/BUILD.gn
+++ b/chrome/browser/ui/webui/BUILD.gn
@@ -63,6 +63,30 @@
   }
 }
 
+source_set("internal_webui_config") {
+  sources = [
+    "internal_debug_pages_disabled/internal_debug_pages_disabled_ui.cc",
+    "internal_debug_pages_disabled/internal_debug_pages_disabled_ui.h",
+    "internal_webui_config.cc",
+    "internal_webui_config.h",
+  ]
+
+  public_deps = [ "//base" ]
+
+  deps = [
+    "//chrome/app:branded_strings",
+    "//chrome/app:generated_resources",
+    "//chrome/browser:browser_process",
+    "//chrome/browser/profiles:profile",
+    "//chrome/browser/resources:dev_ui_resources",
+    "//chrome/common",
+    "//components/prefs",
+    "//content/public/browser",
+    "//content/public/common",
+    "//url",
+  ]
+}
+
 source_set("webui_util") {
   sources = [
     "webui_util.cc",
diff --git a/chrome/browser/ui/webui/ash/scanner_feedback_dialog/scanner_feedback_dialog.cc b/chrome/browser/ui/webui/ash/scanner_feedback_dialog/scanner_feedback_dialog.cc
index 650ecaf4..580541a 100644
--- a/chrome/browser/ui/webui/ash/scanner_feedback_dialog/scanner_feedback_dialog.cc
+++ b/chrome/browser/ui/webui/ash/scanner_feedback_dialog/scanner_feedback_dialog.cc
@@ -4,16 +4,31 @@
 
 #include "chrome/browser/ui/webui/ash/scanner_feedback_dialog/scanner_feedback_dialog.h"
 
+#include <utility>
+#include <variant>
+
+#include "ash/public/cpp/scanner/scanner_feedback_info.h"
+#include "ash/webui/scanner_feedback_ui/scanner_feedback_browser_context_data.h"
+#include "ash/webui/scanner_feedback_ui/scanner_feedback_page_handler.h"
+#include "ash/webui/scanner_feedback_ui/scanner_feedback_untrusted_ui.h"
 #include "ash/webui/scanner_feedback_ui/url_constants.h"
+#include "base/check.h"
+#include "base/check_deref.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
 #include "chrome/browser/ui/webui/ash/system_web_dialog/system_web_dialog_delegate.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui_controller.h"
 #include "ui/gfx/geometry/size.h"
 #include "url/gurl.h"
 
 namespace ash {
 
-ScannerFeedbackDialog::ScannerFeedbackDialog()
+ScannerFeedbackDialog::ScannerFeedbackDialog(ScannerFeedbackInfo info)
     : SystemWebDialogDelegate(GURL(kScannerFeedbackUntrustedUrl),
-                              /*title=*/u"") {
+                              /*title=*/u""),
+      feedback_info_(std::move(info)) {
   set_show_close_button(false);
   // Taken from orca-feedback.ts's `IDEAL_WIDTH` and `IDEAL_HEIGHT`.
   set_dialog_size(gfx::Size(/*width=*/512, /*height=*/600));
@@ -21,4 +36,43 @@
 
 ScannerFeedbackDialog::~ScannerFeedbackDialog() = default;
 
+void ScannerFeedbackDialog::OnDialogShown(content::WebUI* webui) {
+  // This is called from `ui::WebDialogUIBase::HandleRenderFrameCreated`, right
+  // after the `content::RenderFrameHost` is created - before any JavaScript is
+  // run.
+  SystemWebDialogDelegate::OnDialogShown(webui);
+
+  auto* controller =
+      CHECK_DEREF(webui->GetController()).GetAs<ScannerFeedbackUntrustedUI>();
+
+  CHECK(controller);
+
+  auto* feedback_info = std::get_if<ScannerFeedbackInfo>(&feedback_info_);
+  // `OnDialogShown` should never be called multiple times. If it was previously
+  // called, a UAF may occur after the previous dialog is closed - as that would
+  // destroy `this` while the new `SystemWebDialogView` is still storing a (now
+  // invalid) pointer to `this`.
+  CHECK(feedback_info);
+
+  CHECK(webui);
+  content::WebContents* web_contents = webui->GetWebContents();
+  CHECK(web_contents);
+  content::BrowserContext* browser_context = web_contents->GetBrowserContext();
+  CHECK(browser_context);
+
+  base::ScopedClosureRunner feedback_info_cleanup =
+      SetScannerFeedbackInfoForBrowserContext(*browser_context,
+                                              controller->page_handler().id(),
+                                              std::move(*feedback_info));
+
+  feedback_info_ = std::move(feedback_info_cleanup);
+
+  ScannerFeedbackPageHandler& page_handler = controller->page_handler();
+
+  // This is safe to run twice, as `Widget::Close()` explicitly handles the case
+  // where a widget is attempted to be closed while it is already closed.
+  page_handler.SetCloseDialogCallback(base::BindRepeating(
+      &ScannerFeedbackDialog::Close, weak_ptr_factory_.GetWeakPtr()));
+}
+
 }  // namespace ash
diff --git a/chrome/browser/ui/webui/ash/scanner_feedback_dialog/scanner_feedback_dialog.h b/chrome/browser/ui/webui/ash/scanner_feedback_dialog/scanner_feedback_dialog.h
index d4d5d85a..63d99b8f 100644
--- a/chrome/browser/ui/webui/ash/scanner_feedback_dialog/scanner_feedback_dialog.h
+++ b/chrome/browser/ui/webui/ash/scanner_feedback_dialog/scanner_feedback_dialog.h
@@ -5,8 +5,17 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_ASH_SCANNER_FEEDBACK_DIALOG_SCANNER_FEEDBACK_DIALOG_H_
 #define CHROME_BROWSER_UI_WEBUI_ASH_SCANNER_FEEDBACK_DIALOG_SCANNER_FEEDBACK_DIALOG_H_
 
+#include <variant>
+
+#include "ash/public/cpp/scanner/scanner_feedback_info.h"
+#include "base/functional/callback_helpers.h"
+#include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/webui/ash/system_web_dialog/system_web_dialog_delegate.h"
 
+namespace content {
+class WebUI;
+}
+
 namespace ash {
 
 // Dialog delegate for the Scanner feedback form WebUI.
@@ -16,12 +25,24 @@
 // be destroyed when the dialog is closed.
 class ScannerFeedbackDialog : public SystemWebDialogDelegate {
  public:
-  ScannerFeedbackDialog();
+  explicit ScannerFeedbackDialog(ScannerFeedbackInfo info);
 
   ScannerFeedbackDialog(const ScannerFeedbackDialog&) = delete;
   ScannerFeedbackDialog& operator=(const ScannerFeedbackDialog&) = delete;
 
   ~ScannerFeedbackDialog() override;
+
+  // SystemWebDialogDelegate:
+  void OnDialogShown(content::WebUI* webui) override;
+
+ private:
+  // Set to a `ScannerFeedbackInfo` on construction.
+  // `OnDialogShown` will move the `ScannerFeedbackInfo` into the WebUI's
+  // browser context, and set this to `base::ScopedClosureRunner` to clean it
+  // up once the dialog is closed.
+  std::variant<ScannerFeedbackInfo, base::ScopedClosureRunner> feedback_info_;
+
+  base::WeakPtrFactory<ScannerFeedbackDialog> weak_ptr_factory_{this};
 };
 
 }  // namespace ash
diff --git a/chrome/browser/ui/webui/ash/settings/constants/constants_util.cc b/chrome/browser/ui/webui/ash/settings/constants/constants_util.cc
index 20a55b9..90a764b 100644
--- a/chrome/browser/ui/webui/ash/settings/constants/constants_util.cc
+++ b/chrome/browser/ui/webui/ash/settings/constants/constants_util.cc
@@ -6,7 +6,6 @@
 
 #include <vector>
 
-#include "ash/constants/ash_features.h"
 #include "base/no_destructor.h"
 
 namespace ash::settings {
@@ -39,28 +38,11 @@
   return all;
 }
 
-void IncludeRevampSectionsOnly(std::vector<mojom::Section>& sections) {
-  std::erase_if(sections, [](mojom::Section section) {
-    //  An old Section can be filtered out once it has been fully incorporated
-    // into the new revamp Section.
-    return section == mojom::Section::kLanguagesAndInput;
-  });
-}
-
-void RemoveRevampSections(std::vector<mojom::Section>& sections) {
-  std::erase(sections, mojom::Section::kSystemPreferences);
-}
-
 }  // namespace
 
 const std::vector<mojom::Section>& AllSections() {
   static const base::NoDestructor<std::vector<mojom::Section>> all_sections([] {
     std::vector<mojom::Section> sections = All<mojom::Section>();
-    if (ash::features::IsOsSettingsRevampWayfindingEnabled()) {
-      IncludeRevampSectionsOnly(sections);
-    } else {
-      RemoveRevampSections(sections);
-    }
     return sections;
   }());
 
diff --git a/chrome/browser/ui/webui/ash/settings/pages/languages/languages_section.cc b/chrome/browser/ui/webui/ash/settings/pages/languages/languages_section.cc
index 22485d1..9c7ab23 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/languages/languages_section.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/languages/languages_section.cc
@@ -32,7 +32,6 @@
 
 namespace mojom {
 using ::chromeos::settings::mojom::kAppLanguagesSubpagePath;
-using ::chromeos::settings::mojom::kLanguagesAndInputSectionPath;
 using ::chromeos::settings::mojom::kLanguagesSubpagePath;
 using ::chromeos::settings::mojom::kSystemPreferencesSectionPath;
 using ::chromeos::settings::mojom::Section;
diff --git a/chrome/browser/ui/webui/data_sharing_internals/data_sharing_internals_ui.cc b/chrome/browser/ui/webui/data_sharing_internals/data_sharing_internals_ui.cc
index fdcd18cc..1799b5a4 100644
--- a/chrome/browser/ui/webui/data_sharing_internals/data_sharing_internals_ui.cc
+++ b/chrome/browser/ui/webui/data_sharing_internals/data_sharing_internals_ui.cc
@@ -15,8 +15,7 @@
 #include "content/public/browser/web_ui_data_source.h"
 
 DataSharingInternalsUIConfig::DataSharingInternalsUIConfig()
-    : DefaultWebUIConfig(content::kChromeUIScheme,
-                         chrome::kChromeUIDataSharingInternalsHost) {}
+    : DefaultInternalWebUIConfig(chrome::kChromeUIDataSharingInternalsHost) {}
 
 DataSharingInternalsUIConfig::~DataSharingInternalsUIConfig() = default;
 
diff --git a/chrome/browser/ui/webui/data_sharing_internals/data_sharing_internals_ui.h b/chrome/browser/ui/webui/data_sharing_internals/data_sharing_internals_ui.h
index d6af97e..f08bddc1 100644
--- a/chrome/browser/ui/webui/data_sharing_internals/data_sharing_internals_ui.h
+++ b/chrome/browser/ui/webui/data_sharing_internals/data_sharing_internals_ui.h
@@ -6,16 +6,16 @@
 #define CHROME_BROWSER_UI_WEBUI_DATA_SHARING_INTERNALS_DATA_SHARING_INTERNALS_UI_H_
 
 #include "chrome/browser/ui/webui/data_sharing_internals/data_sharing_internals.mojom.h"
+#include "chrome/browser/ui/webui/internal_webui_config.h"
 #include "components/data_sharing/public/protocol/group_data.mojom.h"
 #include "content/public/browser/web_ui_controller.h"
-#include "content/public/browser/webui_config.h"
 #include "ui/webui/mojo_web_ui_controller.h"
 
 class DataSharingInternalsPageHandlerImpl;
 class DataSharingInternalsUI;
 
 class DataSharingInternalsUIConfig
-    : public content::DefaultWebUIConfig<DataSharingInternalsUI> {
+    : public webui::DefaultInternalWebUIConfig<DataSharingInternalsUI> {
  public:
   DataSharingInternalsUIConfig();
   ~DataSharingInternalsUIConfig() override;
diff --git a/chrome/browser/ui/webui/discards/discards_ui.h b/chrome/browser/ui/webui/discards/discards_ui.h
index eee3e6db..d009906 100644
--- a/chrome/browser/ui/webui/discards/discards_ui.h
+++ b/chrome/browser/ui/webui/discards/discards_ui.h
@@ -9,19 +9,17 @@
 
 #include "chrome/browser/ui/webui/discards/discards.mojom-forward.h"
 #include "chrome/browser/ui/webui/discards/site_data.mojom-forward.h"
+#include "chrome/browser/ui/webui/internal_webui_config.h"
 #include "chrome/common/webui_url_constants.h"
-#include "content/public/browser/webui_config.h"
-#include "content/public/common/url_constants.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "ui/webui/mojo_web_ui_controller.h"
 
 class DiscardsUI;
 
-class DiscardsUIConfig : public content::DefaultWebUIConfig<DiscardsUI> {
+class DiscardsUIConfig : public webui::DefaultInternalWebUIConfig<DiscardsUI> {
  public:
   DiscardsUIConfig()
-      : DefaultWebUIConfig(content::kChromeUIScheme,
-                           chrome::kChromeUIDiscardsHost) {}
+      : DefaultInternalWebUIConfig(chrome::kChromeUIDiscardsHost) {}
 };
 
 // Controller for chrome://discards. Corresponding resources are in
diff --git a/chrome/browser/ui/webui/glic/glic.mojom b/chrome/browser/ui/webui/glic/glic.mojom
index 01c2fe3..3115532 100644
--- a/chrome/browser/ui/webui/glic/glic.mojom
+++ b/chrome/browser/ui/webui/glic/glic.mojom
@@ -62,6 +62,9 @@
 
   // Set the bounds of the widget hosting the WebUI to the given size.
   ResizeWidget(gfx.mojom.Size size) => (gfx.mojom.Size? actual_size);
+  // Set the areas of the Glic panel from which it should be draggable. If
+  // `draggable_areas` is empty, the panel will use the top bar area by default.
+  SetPanelDraggableAreas(array<gfx.mojom.Rect> draggable_areas);
 };
 
 // Access from the browser to the Glic web client by proxy of the WebUI page.
@@ -134,4 +137,4 @@
   string mime_type;
   // Image annotations for this screenshot.
   ImageOriginAnnotations origin_annotations;
-};
+};
\ No newline at end of file
diff --git a/chrome/browser/ui/webui/glic/glic_page_handler.cc b/chrome/browser/ui/webui/glic/glic_page_handler.cc
index af3dadfd..48f775ba 100644
--- a/chrome/browser/ui/webui/glic/glic_page_handler.cc
+++ b/chrome/browser/ui/webui/glic/glic_page_handler.cc
@@ -51,6 +51,18 @@
     std::move(callback).Run(actual_size);
   }
 
+  void SetPanelDraggableAreas(
+      const std::vector<gfx::Rect>& draggable_areas) override {
+    if (!draggable_areas.empty()) {
+      glic_service_->SetPanelDraggableAreas(draggable_areas);
+
+    } else {
+      // Default to the top bar area of the panel.
+      // TODO(cuianthony): Define panel dimensions constants in shared location.
+      glic_service_->SetPanelDraggableAreas({{0, 0, 400, 80}});
+    }
+  }
+
   void GetContextFromFocusedTab(
       bool include_inner_text,
       bool include_viewport_screenshot,
diff --git a/chrome/browser/ui/webui/location_internals/location_internals_ui.h b/chrome/browser/ui/webui/location_internals/location_internals_ui.h
index a03f4f5..fe7173c 100644
--- a/chrome/browser/ui/webui/location_internals/location_internals_ui.h
+++ b/chrome/browser/ui/webui/location_internals/location_internals_ui.h
@@ -5,10 +5,9 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_LOCATION_INTERNALS_LOCATION_INTERNALS_UI_H_
 #define CHROME_BROWSER_UI_WEBUI_LOCATION_INTERNALS_LOCATION_INTERNALS_UI_H_
 
+#include "chrome/browser/ui/webui/internal_webui_config.h"
 #include "chrome/browser/ui/webui/location_internals/location_internals.mojom-forward.h"
 #include "chrome/common/webui_url_constants.h"
-#include "content/public/browser/webui_config.h"
-#include "content/public/common/url_constants.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "ui/webui/mojo_web_ui_controller.h"
 
@@ -17,11 +16,10 @@
 
 // WebUIConfig for chrome://location-internals
 class LocationInternalsUIConfig
-    : public content::DefaultWebUIConfig<LocationInternalsUI> {
+    : public webui::DefaultInternalWebUIConfig<LocationInternalsUI> {
  public:
   LocationInternalsUIConfig()
-      : DefaultWebUIConfig(content::kChromeUIScheme,
-                           chrome::kChromeUILocationInternalsHost) {}
+      : DefaultInternalWebUIConfig(chrome::kChromeUILocationInternalsHost) {}
 };
 
 // The WebUI for chrome://location-internals
diff --git a/chrome/browser/ui/webui/media_router/media_router_internals_ui.h b/chrome/browser/ui/webui/media_router/media_router_internals_ui.h
index 65e31aa8..94427124 100644
--- a/chrome/browser/ui/webui/media_router/media_router_internals_ui.h
+++ b/chrome/browser/ui/webui/media_router/media_router_internals_ui.h
@@ -5,9 +5,9 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_MEDIA_ROUTER_MEDIA_ROUTER_INTERNALS_UI_H_
 #define CHROME_BROWSER_UI_WEBUI_MEDIA_ROUTER_MEDIA_ROUTER_INTERNALS_UI_H_
 
+#include "chrome/browser/ui/webui/internal_webui_config.h"
 #include "chrome/common/webui_url_constants.h"
 #include "content/public/browser/web_ui_controller.h"
-#include "content/public/browser/webui_config.h"
 #include "content/public/common/url_constants.h"
 
 namespace media_router {
@@ -15,11 +15,10 @@
 class MediaRouterInternalsUI;
 
 class MediaRouterInternalsUIConfig
-    : public content::DefaultWebUIConfig<MediaRouterInternalsUI> {
+    : public webui::DefaultInternalWebUIConfig<MediaRouterInternalsUI> {
  public:
   MediaRouterInternalsUIConfig()
-      : DefaultWebUIConfig(content::kChromeUIScheme,
-                           chrome::kChromeUIMediaRouterInternalsHost) {}
+      : DefaultInternalWebUIConfig(chrome::kChromeUIMediaRouterInternalsHost) {}
 
   // content::WebUIConfig:
   bool IsWebUIEnabled(content::BrowserContext* browser_context) override;
diff --git a/chrome/browser/ui/webui/on_device_internals/on_device_internals_ui.h b/chrome/browser/ui/webui/on_device_internals/on_device_internals_ui.h
index 46b6973..e76c71b 100644
--- a/chrome/browser/ui/webui/on_device_internals/on_device_internals_ui.h
+++ b/chrome/browser/ui/webui/on_device_internals/on_device_internals_ui.h
@@ -6,9 +6,9 @@
 #define CHROME_BROWSER_UI_WEBUI_ON_DEVICE_INTERNALS_ON_DEVICE_INTERNALS_UI_H_
 
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/ui/webui/internal_webui_config.h"
 #include "chrome/browser/ui/webui/on_device_internals/on_device_internals_page.mojom.h"
 #include "chrome/common/webui_url_constants.h"
-#include "content/public/browser/webui_config.h"
 #include "content/public/common/url_constants.h"
 #include "services/on_device_model/public/mojom/on_device_model.mojom.h"
 #include "ui/webui/mojo_web_ui_controller.h"
@@ -17,11 +17,10 @@
 
 // WebUIConfig for chrome://on-device-internals
 class OnDeviceInternalsUIConfig
-    : public content::DefaultWebUIConfig<OnDeviceInternalsUI> {
+    : public webui::DefaultInternalWebUIConfig<OnDeviceInternalsUI> {
  public:
   OnDeviceInternalsUIConfig()
-      : DefaultWebUIConfig(content::kChromeUIScheme,
-                           chrome::kChromeUIOnDeviceInternalsHost) {}
+      : DefaultInternalWebUIConfig(chrome::kChromeUIOnDeviceInternalsHost) {}
 
   // content::WebUIConfig:
   bool IsWebUIEnabled(content::BrowserContext* browser_context) override;
diff --git a/chrome/browser/ui/webui/profile_internals/profile_internals_ui.h b/chrome/browser/ui/webui/profile_internals/profile_internals_ui.h
index dc2c775..9207a9a 100644
--- a/chrome/browser/ui/webui/profile_internals/profile_internals_ui.h
+++ b/chrome/browser/ui/webui/profile_internals/profile_internals_ui.h
@@ -6,9 +6,9 @@
 #define CHROME_BROWSER_UI_WEBUI_PROFILE_INTERNALS_PROFILE_INTERNALS_UI_H_
 
 #include "build/build_config.h"
+#include "chrome/browser/ui/webui/internal_webui_config.h"
 #include "chrome/common/webui_url_constants.h"
 #include "content/public/browser/web_ui_controller.h"
-#include "content/public/browser/webui_config.h"
 #include "content/public/common/url_constants.h"
 
 #if BUILDFLAG(IS_ANDROID)
@@ -20,11 +20,10 @@
 class ProfileInternalsUI;
 
 class ProfileInternalsUIConfig
-    : public content::DefaultWebUIConfig<ProfileInternalsUI> {
+    : public webui::DefaultInternalWebUIConfig<ProfileInternalsUI> {
  public:
   ProfileInternalsUIConfig()
-      : DefaultWebUIConfig(content::kChromeUIScheme,
-                           chrome::kChromeUIProfileInternalsHost) {}
+      : DefaultInternalWebUIConfig(chrome::kChromeUIProfileInternalsHost) {}
 };
 
 // Controller for chrome://profile-internals page.
diff --git a/chrome/browser/ui/webui/safe_browsing/BUILD.gn b/chrome/browser/ui/webui/safe_browsing/BUILD.gn
index 6696dfd..c149ed0 100644
--- a/chrome/browser/ui/webui/safe_browsing/BUILD.gn
+++ b/chrome/browser/ui/webui/safe_browsing/BUILD.gn
@@ -10,6 +10,7 @@
     "chrome_safe_browsing_ui.h",
   ]
   public_deps = [
+    "//chrome/browser/ui/webui:internal_webui_config",
     "//components/safe_browsing/content/browser/web_ui",
     "//components/safe_browsing/core/common",
     "//content/public/browser",
diff --git a/chrome/browser/ui/webui/safe_browsing/chrome_safe_browsing_ui.h b/chrome/browser/ui/webui/safe_browsing/chrome_safe_browsing_ui.h
index e8028cf8..0e097001 100644
--- a/chrome/browser/ui/webui/safe_browsing/chrome_safe_browsing_ui.h
+++ b/chrome/browser/ui/webui/safe_browsing/chrome_safe_browsing_ui.h
@@ -5,10 +5,10 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_SAFE_BROWSING_CHROME_SAFE_BROWSING_UI_H_
 #define CHROME_BROWSER_UI_WEBUI_SAFE_BROWSING_CHROME_SAFE_BROWSING_UI_H_
 
+#include "chrome/browser/ui/webui/internal_webui_config.h"
 #include "components/safe_browsing/content/browser/web_ui/safe_browsing_ui.h"
 #include "components/safe_browsing/core/common/web_ui_constants.h"
 #include "content/public/browser/web_ui.h"
-#include "content/public/browser/webui_config.h"
 #include "content/public/common/url_constants.h"
 
 namespace safe_browsing {
@@ -16,11 +16,10 @@
 class ChromeSafeBrowsingUI;
 
 class ChromeSafeBrowsingUIConfig
-    : public content::DefaultWebUIConfig<ChromeSafeBrowsingUI> {
+    : public webui::DefaultInternalWebUIConfig<ChromeSafeBrowsingUI> {
  public:
   ChromeSafeBrowsingUIConfig()
-      : DefaultWebUIConfig(content::kChromeUIScheme,
-                           safe_browsing::kChromeUISafeBrowsingHost) {}
+      : DefaultInternalWebUIConfig(safe_browsing::kChromeUISafeBrowsingHost) {}
 };
 
 class ChromeSafeBrowsingUI : public SafeBrowsingUI {
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 79c9614..ee70403 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -1081,10 +1081,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   html_source->AddString(
       "osSettingsLanguagesPageUrl",
-      chrome::GetOSSettingsUrl(
-          ash::features::IsOsSettingsRevampWayfindingEnabled()
-              ? chromeos::settings::mojom::kLanguagesSubpagePath
-              : chromeos::settings::mojom::kLanguagesAndInputSectionPath)
+      chrome::GetOSSettingsUrl(chromeos::settings::mojom::kLanguagesSubpagePath)
           .spec());
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index adb781d..b4c8e43 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -493,11 +493,6 @@
                           is_restricted_notice_enabled);
 
   html_source->AddBoolean(
-      "privateStateTokensEnabled",
-      base::FeatureList::IsEnabled(network::features::kPrivateStateTokens) ||
-          base::FeatureList::IsEnabled(network::features::kFledgePst));
-
-  html_source->AddBoolean(
       "safetyHubAbusiveNotificationRevocationEnabled",
       base::FeatureList::IsEnabled(
           safe_browsing::kSafetyHubAbusiveNotificationRevocation));
diff --git a/chrome/browser/ui/webui/user_actions/user_actions_ui.h b/chrome/browser/ui/webui/user_actions/user_actions_ui.h
index 7a50df8..ab22a8a 100644
--- a/chrome/browser/ui/webui/user_actions/user_actions_ui.h
+++ b/chrome/browser/ui/webui/user_actions/user_actions_ui.h
@@ -5,18 +5,17 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_USER_ACTIONS_USER_ACTIONS_UI_H_
 #define CHROME_BROWSER_UI_WEBUI_USER_ACTIONS_USER_ACTIONS_UI_H_
 
-#include "chrome/common/url_constants.h"
+#include "chrome/browser/ui/webui/internal_webui_config.h"
 #include "chrome/common/webui_url_constants.h"
 #include "content/public/browser/web_ui_controller.h"
-#include "content/public/browser/webui_config.h"
 
 class UserActionsUI;
 
-class UserActionsUIConfig : public content::DefaultWebUIConfig<UserActionsUI> {
+class UserActionsUIConfig
+    : public webui::DefaultInternalWebUIConfig<UserActionsUI> {
  public:
   UserActionsUIConfig()
-      : DefaultWebUIConfig(content::kChromeUIScheme,
-                           chrome::kChromeUIUserActionsHost) {}
+      : DefaultInternalWebUIConfig(chrome::kChromeUIUserActionsHost) {}
 };
 
 // The UI for chrome://user-actions/
diff --git a/chrome/browser/ui/webui/webui_gallery/webui_gallery_ui.h b/chrome/browser/ui/webui/webui_gallery/webui_gallery_ui.h
index cffea3ef..7351c44 100644
--- a/chrome/browser/ui/webui/webui_gallery/webui_gallery_ui.h
+++ b/chrome/browser/ui/webui/webui_gallery/webui_gallery_ui.h
@@ -7,7 +7,6 @@
 
 #include "chrome/browser/ui/webui/internal_webui_config.h"
 #include "chrome/common/webui_url_constants.h"
-#include "content/public/common/url_constants.h"
 #include "ui/webui/mojo_web_ui_controller.h"
 #include "ui/webui/resources/cr_components/color_change_listener/color_change_listener.mojom.h"
 
diff --git a/chrome/browser/ui/webui/webui_js_error/webui_js_error_ui.h b/chrome/browser/ui/webui/webui_js_error/webui_js_error_ui.h
index 839bdbc..a45e432f 100644
--- a/chrome/browser/ui/webui/webui_js_error/webui_js_error_ui.h
+++ b/chrome/browser/ui/webui/webui_js_error/webui_js_error_ui.h
@@ -5,19 +5,17 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_WEBUI_JS_ERROR_WEBUI_JS_ERROR_UI_H_
 #define CHROME_BROWSER_UI_WEBUI_WEBUI_JS_ERROR_WEBUI_JS_ERROR_UI_H_
 
+#include "chrome/browser/ui/webui/internal_webui_config.h"
 #include "chrome/common/webui_url_constants.h"
 #include "content/public/browser/web_ui_controller.h"
-#include "content/public/browser/webui_config.h"
-#include "content/public/common/url_constants.h"
 
 class WebUIJsErrorUI;
 
 class WebUIJsErrorUIConfig
-    : public content::DefaultWebUIConfig<WebUIJsErrorUI> {
+    : public webui::DefaultInternalWebUIConfig<WebUIJsErrorUI> {
  public:
   WebUIJsErrorUIConfig()
-      : DefaultWebUIConfig(content::kChromeUIScheme,
-                           chrome::kChromeUIWebUIJsErrorHost) {}
+      : DefaultInternalWebUIConfig(chrome::kChromeUIWebUIJsErrorHost) {}
 };
 
 // The WebUI that controls chrome://webuijserror.
diff --git a/chrome/browser/web_applications/commands/fetch_manifest_and_install_command.cc b/chrome/browser/web_applications/commands/fetch_manifest_and_install_command.cc
index 0a4f8b60..7853534 100644
--- a/chrome/browser/web_applications/commands/fetch_manifest_and_install_command.cc
+++ b/chrome/browser/web_applications/commands/fetch_manifest_and_install_command.cc
@@ -693,9 +693,21 @@
 
   bool is_shortcut_created = IsShortcutCreated(app_lock_->registrar(), app_id);
   DCHECK(app_lock_);
+
+  const WebAppTabHelper* tab_helper =
+      WebAppTabHelper::FromWebContents(web_contents_.get());
+  bool is_in_app_window = false;
+  if (tab_helper) {
+    // The tab helper doesn't exist in unit tests.
+    is_in_app_window = tab_helper->is_in_app_window();
+  }
+
+  // TODO(https://crbug.com/383360269): Turn the is_in_app_window into a CHECK
+  // after all user installs can no longer overlap each other.
   const bool can_reparent_tab =
       app_lock_->ui_manager().CanReparentAppTabToWindow(app_id,
-                                                        is_shortcut_created);
+                                                        is_shortcut_created) &&
+      !is_in_app_window;
 
   SCOPED_CRASH_KEY_NUMBER("PWA", "install_surface",
                           static_cast<int>(install_surface_));
@@ -703,8 +715,6 @@
       "PWA", "install_url",
       web_contents_->GetLastCommittedURL().possibly_invalid_spec());
   SCOPED_CRASH_KEY_STRING64("PWA", "install_app_id", app_id);
-  WebAppTabHelper* tab_helper =
-      WebAppTabHelper::FromWebContents(web_contents_.get());
   if (tab_helper) {
     SCOPED_CRASH_KEY_STRING64("PWA", "source_window_app_id",
                               tab_helper->window_app_id().value_or("<none>"));
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
index b533b61..7a60eacf 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -509,6 +509,16 @@
     if (dialog_model_->in_onboarding_flow) {
       RecordOnboardingEvent(webauthn::metrics::OnboardingEvents::kSucceeded);
     }
+    switch (request_type) {
+      case device::FidoRequestType::kGetAssertion:
+        RecordGPMGetAssertionEvent(
+            webauthn::metrics::GPMGetAssertionEvents::kSuccess);
+        break;
+      case device::FidoRequestType::kMakeCredential:
+        RecordGPMMakeCredentialEvent(
+            webauthn::metrics::GPMMakeCredentialEvents::kSuccess);
+        break;
+    }
     webauthn::user_actions::RecordGpmSuccess();
   }
 }
diff --git a/chrome/browser/webauthn/enclave_manager.cc b/chrome/browser/webauthn/enclave_manager.cc
index b4c3ebc..ff227e4 100644
--- a/chrome/browser/webauthn/enclave_manager.cc
+++ b/chrome/browser/webauthn/enclave_manager.cc
@@ -32,6 +32,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/notreached.h"
 #include "base/numerics/checked_math.h"
 #include "base/numerics/safe_conversions.h"
@@ -2608,6 +2609,15 @@
               trusted_vault_access_token_fetcher_frontend_->GetWeakPtr()))),
       identity_observer_(
           std::make_unique<IdentityObserver>(identity_manager_, this)) {
+  // Automatically load the enclave state shortly after startup so that any
+  // renewals will be considered without the user having to do something to
+  // trigger a WebAuthn operation.
+  load_timer_.Start(
+      FROM_HERE, base::Minutes(4),
+      base::BindOnce(&EnclaveManager::Load, weak_ptr_factory_.GetWeakPtr(),
+                     base::DoNothing()));
+  // Also consider renewing the PIN every day, for users who keep Chrome open
+  // for long periods.
   renewal_timer_.Start(FROM_HERE, base::Hours(24),
                        base::BindRepeating(&EnclaveManager::ConsiderPinRenewal,
                                            weak_ptr_factory_.GetWeakPtr()));
@@ -3781,12 +3791,37 @@
   secret_ = std::vector<uint8_t>(secret.begin(), secret.end());
 }
 
+// A list of PIN-renewal events that are reported to UMA. Do not renumber
+// as the values are persisted.
+enum class PinRenewalEvent {
+  kConsidered = 0,
+  kNothingToRenew = 1,
+  kConcurrentRenewal = 2,
+  kNotYetTime = 3,
+  kStarted = 4,
+  kSuccess = 5,
+  kFailure = 6,
+
+  kMaxValue = kFailure,
+};
+
+static const char kPinRenewalHistogram[] = "WebAuthentication.PinRenewalEvent";
+
 void EnclaveManager::ConsiderPinRenewal() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  base::UmaHistogramEnumeration(kPinRenewalHistogram,
+                                PinRenewalEvent::kConsidered);
 
   renewal_checks_++;
-  if (!user_ || !user_->registered() || !user_->has_wrapped_pin() ||
-      is_renewing_) {
+  if (!user_ || !user_->registered() || !user_->has_wrapped_pin()) {
+    base::UmaHistogramEnumeration(kPinRenewalHistogram,
+                                  PinRenewalEvent::kNothingToRenew);
+    return;
+  }
+
+  if (is_renewing_) {
+    base::UmaHistogramEnumeration(kPinRenewalHistogram,
+                                  PinRenewalEvent::kConcurrentRenewal);
     return;
   }
 
@@ -3797,12 +3832,21 @@
     FIDO_LOG(EVENT) << "Renewing GPM PIN based on time since last renewal";
     renewal_attempts_++;
     is_renewing_ = true;
+    base::UmaHistogramEnumeration(kPinRenewalHistogram,
+                                  PinRenewalEvent::kStarted);
     RenewPIN(base::BindOnce(&EnclaveManager::OnRenewalComplete,
                             weak_ptr_factory_.GetWeakPtr()));
+  } else {
+    base::UmaHistogramEnumeration(kPinRenewalHistogram,
+                                  PinRenewalEvent::kNotYetTime);
   }
 }
 
 void EnclaveManager::OnRenewalComplete(bool success) {
+  base::UmaHistogramEnumeration(
+      kPinRenewalHistogram,
+      success ? PinRenewalEvent::kSuccess : PinRenewalEvent::kFailure);
+
   is_renewing_ = false;
 }
 
diff --git a/chrome/browser/webauthn/enclave_manager.h b/chrome/browser/webauthn/enclave_manager.h
index 517c26c..886d872d 100644
--- a/chrome/browser/webauthn/enclave_manager.h
+++ b/chrome/browser/webauthn/enclave_manager.h
@@ -404,6 +404,7 @@
   std::unique_ptr<StateMachine> state_machine_;
   std::vector<base::OnceClosure> load_callbacks_;
   std::deque<std::unique_ptr<PendingAction>> pending_actions_;
+  base::OneShotTimer load_timer_;
   base::RepeatingTimer renewal_timer_;
   unsigned renewal_checks_ = 0;
   unsigned renewal_attempts_ = 0;
diff --git a/chrome/browser/webauthn/enclave_manager_factory.cc b/chrome/browser/webauthn/enclave_manager_factory.cc
index b7ee1ea..6b449326 100644
--- a/chrome/browser/webauthn/enclave_manager_factory.cc
+++ b/chrome/browser/webauthn/enclave_manager_factory.cc
@@ -89,3 +89,15 @@
                           : profile->GetDefaultStoragePartition()
                                 ->GetURLLoaderFactoryForBrowserProcess());
 }
+
+bool EnclaveManagerFactory::ServiceIsCreatedWithBrowserContext() const {
+  // In order that the GPM PIN can be considered for renewal, the
+  // EnclaveManager should be created when a Profile is created. At the time of
+  // writing, this happens because a `TrustedVaultEncryptionKeysTabHelper` is
+  // created for each tab, and that triggers the creation of the EnclaveManager
+  // too.
+  //
+  // It would be nice to return `true` here to ensure the creation in a more
+  // direct fashion, but this appears to upset a large number of tests.
+  return false;
+}
diff --git a/chrome/browser/webauthn/enclave_manager_factory.h b/chrome/browser/webauthn/enclave_manager_factory.h
index 2b23d7c..0fe5b9b 100644
--- a/chrome/browser/webauthn/enclave_manager_factory.h
+++ b/chrome/browser/webauthn/enclave_manager_factory.h
@@ -38,6 +38,8 @@
   // BrowserContextKeyedServiceFactory:
   std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
+
+  bool ServiceIsCreatedWithBrowserContext() const override;
 };
 
 #endif  // CHROME_BROWSER_WEBAUTHN_ENCLAVE_MANAGER_FACTORY_H_
diff --git a/chrome/browser/webauthn/gpm_enclave_controller.cc b/chrome/browser/webauthn/gpm_enclave_controller.cc
index fbf5139..b08a262 100644
--- a/chrome/browser/webauthn/gpm_enclave_controller.cc
+++ b/chrome/browser/webauthn/gpm_enclave_controller.cc
@@ -902,6 +902,14 @@
     return;
   }
 
+  if (account_state_ != AccountState::kLoading &&
+      account_state_ != AccountState::kChecking) {
+    // `kLoading` and `kChecking` will call `OnGPMSelected` again,
+    // therefore we don't emit in these states.
+    RecordGPMMakeCredentialEvent(
+        webauthn::metrics::GPMMakeCredentialEvents::kStarted);
+  }
+
   switch (account_state_) {
     case AccountState::kEmpty:
       // Set to true to indicate that the user has entered the GPM onboarding
@@ -963,6 +971,15 @@
 void GPMEnclaveController::OnGPMPasskeySelected(
     std::vector<uint8_t> credential_id) {
   selected_cred_id_ = std::move(credential_id);
+
+  if (account_state_ != AccountState::kLoading &&
+      account_state_ != AccountState::kChecking) {
+    // `kLoading` and `kChecking` will call `OnGPMPasskeySelected` again,
+    // therefore we don't emit in these states.
+    RecordGPMGetAssertionEvent(
+        webauthn::metrics::GPMGetAssertionEvents::kStarted);
+  }
+
   switch (account_state_) {
     case AccountState::kReady:
       uv_method_ = PickEnclaveUserVerificationMethod(
diff --git a/chrome/browser/webauthn/webauthn_metrics_util.cc b/chrome/browser/webauthn/webauthn_metrics_util.cc
index dcbb90a99..0d220aa 100644
--- a/chrome/browser/webauthn/webauthn_metrics_util.cc
+++ b/chrome/browser/webauthn/webauthn_metrics_util.cc
@@ -19,6 +19,16 @@
                                 passkey_count, kPasskeyCountMax);
 }
 
+void RecordGPMMakeCredentialEvent(
+    webauthn::metrics::GPMMakeCredentialEvents event) {
+  base::UmaHistogramEnumeration("WebAuthentication.GPM.MakeCredential", event);
+}
+
+void RecordGPMGetAssertionEvent(
+    webauthn::metrics::GPMGetAssertionEvents event) {
+  base::UmaHistogramEnumeration("WebAuthentication.GPM.GetAssertion", event);
+}
+
 void RecordOnboardingEvent(webauthn::metrics::OnboardingEvents event) {
   base::UmaHistogramEnumeration("WebAuthentication.OnboardingEvents", event);
 }
diff --git a/chrome/browser/webauthn/webauthn_metrics_util.h b/chrome/browser/webauthn/webauthn_metrics_util.h
index be99d9a6..e39ba44d 100644
--- a/chrome/browser/webauthn/webauthn_metrics_util.h
+++ b/chrome/browser/webauthn/webauthn_metrics_util.h
@@ -8,6 +8,28 @@
 namespace webauthn::metrics {
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused.
+enum class GPMMakeCredentialEvents {
+  // LINT.IfChange
+  kStarted = 0,
+  kSuccess = 1,
+  kFailure = 2,
+  kMaxValue = kFailure,
+  // LINT.ThenChange(//tools/metrics/histograms/metadata/webauthn/enums.xml)
+};
+
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class GPMGetAssertionEvents {
+  // LINT.IfChange
+  kStarted = 0,
+  kSuccess = 1,
+  kFailure = 2,
+  kMaxValue = kFailure,
+  // LINT.ThenChange(//tools/metrics/histograms/metadata/webauthn/enums.xml)
+};
+
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
 enum class OnboardingEvents {
   // LINT.IfChange
   kStarted = 0,
@@ -22,6 +44,9 @@
 }  // namespace webauthn::metrics
 
 void ReportConditionalUiPasskeyCount(int passkey_count);
+void RecordGPMMakeCredentialEvent(
+    webauthn::metrics::GPMMakeCredentialEvents event);
+void RecordGPMGetAssertionEvent(webauthn::metrics::GPMGetAssertionEvents event);
 void RecordOnboardingEvent(webauthn::metrics::OnboardingEvents event);
 
 #endif  // CHROME_BROWSER_WEBAUTHN_WEBAUTHN_METRICS_UTIL_H_
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index d176da03..3fbe47c 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1734371937-f283eb344a78e960bbe1d12884eec0619e778216-5ef1114e1ac2ac62c2c14b1881eba5993e27a4b3.profdata
+chrome-android32-main-1734436763-9e3e8a340774f52deff33a13402447b20bcfd2d0-350bd3a6bf626f7a1187774fd5cad80e7a73499d.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 8de95f9..cb2f3d49 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1734380526-c6699d9ec30d9dd3d49bf3caeda97f8ff7895036-72f63dc6e666795c3e09838960688ee4a9722994.profdata
+chrome-android64-main-1734438468-bc76c19d196bd9dfcd0558ab69b05aa46102178a-5088537f95148d6e49f57b52c42ad9af5b086d8f.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 447138b..ba187481 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1734371937-a4631cb7c5858ddfe9c7d266350cd4da67704c99-5ef1114e1ac2ac62c2c14b1881eba5993e27a4b3.profdata
+chrome-linux-main-1734414938-be471abd254f3257ee224a25e0c7a2a0f0f1c376-648c84c49041f27a9f6a1910c89a1ef550cfd0ef.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 04fa364..27e1542 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1734378930-3d3508afefb827952020baf0a68aa30bd835367f-3242557f0985555df85fba80075279bac73e9300.profdata
+chrome-mac-arm-main-1734436763-3947ce6fc1cc00d0aabc4342f0f5aaaa6dfdb5af-350bd3a6bf626f7a1187774fd5cad80e7a73499d.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 6e9a59d..a690b15 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1734371937-43d425a3f9349a913834fb3d57775306e85e10fd-5ef1114e1ac2ac62c2c14b1881eba5993e27a4b3.profdata
+chrome-mac-main-1734414938-6adcd2b459696221606fcd528610be9567203fed-648c84c49041f27a9f6a1910c89a1ef550cfd0ef.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index e63c43c..72df09f1 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1734371937-47ee10c431b1c653c5a55c161ecc854615d2408c-5ef1114e1ac2ac62c2c14b1881eba5993e27a4b3.profdata
+chrome-win-arm64-main-1734436763-0edd328847c0406d552fc56ebe92019d1fac4230-350bd3a6bf626f7a1187774fd5cad80e7a73499d.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 09793b9..2839e28 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1734371937-a97c35dfd76e40fe468471f303b8c2be15d7cfb6-5ef1114e1ac2ac62c2c14b1881eba5993e27a4b3.profdata
+chrome-win32-main-1734403932-4e67c016f81772ce2ab4fe4f226c3d972a1054fe-f3de0a77fd31b0fcf0dfa90a5e39c7ae2e827023.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index af2e8a9..fdaa9d1d 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1734360969-cb6d5ec9cd9e906febddfa4e31e6e2d1e77cd84c-2e49645b1352adcee7eca1f6e888f0895f6ce3fd.profdata
+chrome-win64-main-1734414938-d74b38f64d083b4df5bd3809dbd72b91a3dd2f7d-648c84c49041f27a9f6a1910c89a1ef550cfd0ef.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 3b9300f9..09c9d4fe 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -314,6 +314,9 @@
 // Controls whether the Glic feature is enabled.
 BASE_FEATURE(kGlic, "Glic", base::FEATURE_DISABLED_BY_DEFAULT);
 
+const base::FeatureParam<bool> kGlicStatusIconOpenMenuWithSecondaryClick{
+    &kGlic, "open-status-icon-menu-with-secondary-click", false};
+
 BASE_FEATURE(kGlicURLConfig,
              "GlicURLConfig",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index f3455f6..4f34f1be 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -206,6 +206,8 @@
 COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kGeoLanguage);
 
 COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kGlic);
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<bool> kGlicStatusIconOpenMenuWithSecondaryClick;
 
 COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kGlicURLConfig);
 COMPONENT_EXPORT(CHROME_FEATURES)
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index e7a666aa..5733b59 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -3952,14 +3952,6 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-// Enum pref indicating how to launch the Lacros browser. It is managed by
-// LacrosAvailability policy and can have one of the following values:
-// 0: User choice (default value).
-// 1: Lacros is disallowed.
-// 4: Lacros is the only available browser.
-// Values 2 and 3 were removed and should not be reused.
-inline constexpr char kLacrosLaunchSwitch[] = "lacros_launch_switch";
-
 // Enum pref indicating which Lacros browser to launch: rootfs or stateful. It
 // is managed by LacrosSelection policy and can have one of the following
 // values:
diff --git a/chrome/common/profiler/core_unwinders_android.cc b/chrome/common/profiler/core_unwinders_android.cc
index c9fdacf7..b26e578 100644
--- a/chrome/common/profiler/core_unwinders_android.cc
+++ b/chrome/common/profiler/core_unwinders_android.cc
@@ -46,6 +46,8 @@
 #include "base/android/library_loader/anchor_functions.h"
 #include "base/files/memory_mapped_file.h"
 #include "base/profiler/chrome_unwinder_android_32.h"
+#include "chrome/android/modules/stack_unwinder/public/module.h"
+#include "chrome/common/profiler/native_unwinder_android_map_delegate_impl.h"
 #endif  // ARM32_UNWINDING_SUPPORTED
 
 #if ARM64_UNWINDING_SUPPORTED
@@ -55,8 +57,6 @@
 #if UNWINDING_SUPPORTED
 #include "base/profiler/libunwindstack_unwinder_android.h"
 #include "base/profiler/native_unwinder_android.h"
-#include "chrome/android/modules/stack_unwinder/public/module.h"
-#include "chrome/common/profiler/native_unwinder_android_map_delegate_impl.h"
 
 extern "C" {
 // The address of |__executable_start| is the base address of the executable or
@@ -124,6 +124,8 @@
   // For now, we only use Libunwindstack on 64 bit (no other unwinders).
   return CreateLibunwindstackUnwinders();
 #else
+  // The ARM32_UNWINDING_SUPPORTED branch, since this code is within an #if
+  // UNWINDING_SUPPORTED.
   static base::NoDestructor<NativeUnwinderAndroidMapDelegateImpl> map_delegate;
   static base::NoDestructor<ChromeUnwinderCreator> chrome_unwinder_creator;
 
@@ -137,7 +139,9 @@
   return unwinders;
 #endif
 }
+#endif  // UNWINDING_SUPPORTED
 
+#if ARM32_UNWINDING_SUPPORTED
 // Manages installation of the module prerequisite for unwinding. Android, in
 // particular, requires a dynamic feature module to provide the native unwinder.
 class ModuleUnwindPrerequisitesDelegate : public UnwindPrerequisitesDelegate {
@@ -150,7 +154,7 @@
     return stack_unwinder::Module::IsInstalled();
   }
 };
-#endif  // UNWINDING_SUPPORTED
+#endif  // ARM32_UNWINDING_SUPPORTED
 
 }  // namespace
 
@@ -159,15 +163,17 @@
     UnwindPrerequisitesDelegate* prerequites_delegate) {
   CHECK_EQ(sampling_profiler::ProfilerProcessType::kBrowser,
            GetProfilerProcessType(*base::CommandLine::ForCurrentProcess()));
+#if ARM32_UNWINDING_SUPPORTED && defined(OFFICIAL_BUILD) && \
+    BUILDFLAG(GOOGLE_CHROME_BRANDING)
   if (AreUnwindPrerequisitesAvailable(channel, prerequites_delegate)) {
     return;
   }
-#if UNWINDING_SUPPORTED && defined(OFFICIAL_BUILD) && \
-    BUILDFLAG(GOOGLE_CHROME_BRANDING)
+
   ModuleUnwindPrerequisitesDelegate default_delegate;
   if (prerequites_delegate == nullptr) {
     prerequites_delegate = &default_delegate;
   }
+
   // We only want to incur the cost of universally downloading the module in
   // early channels, where profiling will occur over substantially all of
   // the population. When supporting later channels in the future we will
@@ -187,7 +193,8 @@
     UnwindPrerequisitesDelegate* prerequites_delegate) {
 // While non-Android platforms do not need any specific prerequisites beyond
 // what is already bundled and available with Chrome for their platform-specific
-// unwinders to work, Android, in particular, requires a DFM to be installed.
+// unwinders to work, Android, in particular, requires a DFM to be installed on
+// arm32.
 //
 // Therefore, unwind prerequisites for non-supported Android platforms are not
 // considered to be available by default, but prerequisites for non-Android
@@ -197,7 +204,7 @@
 // non-Android platforms. Regardless of the provided delegate, unwind
 // prerequisites are always considered to be available for non-Android
 // platforms.
-#if UNWINDING_SUPPORTED
+#if ARM32_UNWINDING_SUPPORTED
 #if defined(OFFICIAL_BUILD) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Sometimes, DFMs can be installed even if not requested by Chrome
   // explicitly (for instance, in some app stores). Therefore, even if the
@@ -214,25 +221,29 @@
     prerequites_delegate = &default_delegate;
   }
   return prerequites_delegate->AreAvailable(channel);
-#else   // UNWINDING_SUPPORTED
+#elif ARM64_UNWINDING_SUPPORTED
+  return true;
+#else
   return false;
-#endif  // UNWINDING_SUPPORTED
+#endif  // ARM32_UNWINDING_SUPPORTED
 }
 
-#if UNWINDING_SUPPORTED
+#if ARM32_UNWINDING_SUPPORTED
 void LoadModule() {
   CHECK(AreUnwindPrerequisitesAvailable(chrome::GetChannel()));
   static base::NoDestructor<std::unique_ptr<stack_unwinder::Module>>
       stack_unwinder_module(stack_unwinder::Module::Load());
 }
-#endif  // UNWINDING_SUPPORTED
+#endif  // ARM32_UNWINDING_SUPPORTED
 
 base::StackSamplingProfiler::UnwindersFactory CreateCoreUnwindersFactory() {
   if (!AreUnwindPrerequisitesAvailable(chrome::GetChannel())) {
     return base::StackSamplingProfiler::UnwindersFactory();
   }
 #if UNWINDING_SUPPORTED
+#if ARM32_UNWINDING_SUPPORTED
   LoadModule();
+#endif  // ARM32_UNWINDING_SUPPORTED
   return base::BindOnce(CreateCoreUnwinders);
 #else   // UNWINDING_SUPPORTED
   return base::StackSamplingProfiler::UnwindersFactory();
diff --git a/chrome/common/profiler/core_unwinders_android_unittest.cc b/chrome/common/profiler/core_unwinders_android_unittest.cc
index 36e8471..f9345e9c 100644
--- a/chrome/common/profiler/core_unwinders_android_unittest.cc
+++ b/chrome/common/profiler/core_unwinders_android_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/common/profiler/core_unwinders.h"
 
 #include "base/command_line.h"
+#include "base/debug/debugging_buildflags.h"
 #include "base/feature_list.h"
 #include "base/memory/raw_ptr.h"
 #include "base/profiler/profiler_buildflags.h"
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index b367aaff..38c8151 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2079,6 +2079,7 @@
       "//chrome/browser/ui/views/webid:test_support",
       "//chrome/browser/ui/web_applications:browser_tests",
       "//chrome/browser/ui/webui",
+      "//chrome/browser/ui/webui:internal_webui_config",
       "//chrome/browser/ui/webui:webui_util",
       "//chrome/browser/ui/webui/commerce",
       "//chrome/browser/ui/webui/privacy_sandbox:mojo_bindings",
@@ -2823,6 +2824,7 @@
       "../browser/lookalikes/lookalike_test_helper.cc",
       "../browser/lookalikes/lookalike_test_helper.h",
       "../browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc",
+      "../browser/media/audio_ducker_browsertest.cc",
       "../browser/media/autoplay_metrics_browsertest.cc",
       "../browser/media/cast_mirroring_service_host_browsertest.cc",
       "../browser/media/defer_background_media_browsertest.cc",
@@ -5769,7 +5771,6 @@
     "../browser/component_updater/privacy_sandbox_attestations_component_installer_unittest.cc",
     "../browser/component_updater/subresource_filter_component_installer_unittest.cc",
     "../browser/component_updater/tpcd_metadata_component_installer_unittest.cc",
-    "../browser/component_updater/trust_token_key_commitments_component_installer_unittest.cc",
     "../browser/content_index/content_index_provider_unittest.cc",
     "../browser/custom_handlers/chrome_protocol_handler_registry_unittest.cc",
     "../browser/data_sharing/data_sharing_navigation_throttle_unittest.cc",
@@ -6370,6 +6371,7 @@
     "//chrome/browser/ui/page_info:unit_tests",
     "//chrome/browser/ui/safety_hub:test_support",
     "//chrome/browser/ui/webui",
+    "//chrome/browser/ui/webui:internal_webui_config",
     "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/updates/announcement_notification:unit_tests",
     "//chrome/browser/web_share_target:unit_tests",
diff --git a/chrome/test/chromedriver/capabilities.cc b/chrome/test/chromedriver/capabilities.cc
index 4638590..a4d1a62 100644
--- a/chrome/test/chromedriver/capabilities.cc
+++ b/chrome/test/chromedriver/capabilities.cc
@@ -846,6 +846,11 @@
   parser_map["devToolsEventsToLog"] =
       base::BindRepeating(&ParseDevToolsEventsLoggingPrefs);
   parser_map["windowTypes"] = base::BindRepeating(&ParseWindowTypes);
+
+  // Enable Chrome extension related targets
+  parser_map["enableExtensionTargets"] = base::BindRepeating(
+      &ParseBoolean, &capabilities->enable_extension_targets);
+
   // Compliance is read when session is initialized and correct response is
   // sent if not parsed correctly.
   parser_map["w3c"] = base::BindRepeating(&IgnoreCapability);
@@ -1163,10 +1168,6 @@
         base::BindRepeating(&ParseChromeOptions);
   }
 
-  // Enable Chrome extension related targets
-  parser_map["enableExtensionTargets"] =
-      base::BindRepeating(&ParseBoolean, &enable_extension_targets);
-
   // se:options.loggingPrefs and goog:loggingPrefs is spec-compliant name,
   // but loggingPrefs is still supported in legacy mode.
   const std::string prefixed_logging_prefs_key =
diff --git a/chrome/test/chromedriver/client/chromedriver.py b/chrome/test/chromedriver/client/chromedriver.py
index 23a5341e..26f0a9fc 100644
--- a/chrome/test/chromedriver/client/chromedriver.py
+++ b/chrome/test/chromedriver/client/chromedriver.py
@@ -115,8 +115,8 @@
       send_w3c_capability=True, send_w3c_request=True,
       page_load_strategy=None, unexpected_alert_behaviour=None,
       devtools_events_to_log=None, accept_insecure_certs=None,
-      enable_extension_targets=None, timeouts=None, test_name=None,
-      web_socket_url=None, browser_name=None, http_timeout=None):
+      timeouts=None, test_name=None, web_socket_url=None, browser_name=None,
+      http_timeout=None):
     self._executor = command_executor.CommandExecutor(server_url,
                                                       http_timeout=http_timeout)
     self._server_url = server_url
@@ -228,9 +228,6 @@
     if accept_insecure_certs is not None:
       params['acceptInsecureCerts'] = accept_insecure_certs
 
-    if enable_extension_targets is not None:
-      params['enableExtensionTargets'] = enable_extension_targets
-
     if timeouts is not None:
       params['timeouts'] = timeouts
 
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index ff31fc57..272956a 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -6426,8 +6426,8 @@
     # This test can be removed entirely when support for MV2 extensions is
     # removed.
     driver = self.CreateDriver(
-        # Chrome Extension inspection requires enable_extension_targets = True.
-        enable_extension_targets = True,
+        # Chrome Extension inspection requires enableExtensionTargets = True.
+        experimental_options={'enableExtensionTargets': True},
         chrome_extensions=[self._PackExtension(crx)],
         chrome_switches=['disable-features=ExtensionManifestV2Disabled'])
     handles = driver.GetWindowHandles()
@@ -6441,9 +6441,9 @@
 
   def testCanInspectExtensionTargetsWithMigratedSwitch(self):
     crx = os.path.join(_TEST_DATA_DIR, 'ext_bg_page.crx')
-    # Chrome Extension inspection requires enable_extension_targets = True.
+    # Chrome Extension inspection requires enableExtensionTargets = True.
     # We migrate experimental_options={'windowTypes': ['background_page']} to
-    # the new switch.
+    # the new chrome option.
     # This test exercises inspection of an extension background page, which
     # is only valid for manifest V2 extensions. Explicitly disable the
     # experiment that disallows MV2 extensions.
diff --git a/chrome/test/data/extensions/api_test/user_scripts/configure_world/worker.js b/chrome/test/data/extensions/api_test/user_scripts/configure_world/worker.js
index 61d033f..11bb945 100644
--- a/chrome/test/data/extensions/api_test/user_scripts/configure_world/worker.js
+++ b/chrome/test/data/extensions/api_test/user_scripts/configure_world/worker.js
@@ -140,6 +140,40 @@
     await navigateToRequestedUrl();
   },
 
+  // Tests that calling configureWorld() will only change the properties present
+  // in the `configureWorld` parameters.
+  async function callingConfigureWorldOnlyChangesPresentProperties() {
+    await cleanUpState();
+
+    const customCsp = 'some csp';
+    const customMessaging = true;
+
+    // Configure a world with a custom messaging and CSP state, and verify its
+    // values.
+    await chrome.userScripts.configureWorld(
+        {csp: customCsp, messaging: customMessaging});
+    let worldConfig = (await chrome.userScripts.getWorldConfigurations())[0];
+    chrome.test.assertEq(customCsp, worldConfig.csp);
+    chrome.test.assertEq(customMessaging, worldConfig.messaging);
+
+    // Update the world, but don't pass any changes. The world configuration
+    // should be unchanged.
+    await chrome.userScripts.configureWorld({});
+    worldConfig = (await chrome.userScripts.getWorldConfigurations())[0];
+    chrome.test.assertEq(customCsp, worldConfig.csp);
+    chrome.test.assertEq(customMessaging, worldConfig.messaging);
+
+    // Update the world with only a new CSP. The CSP should be updated, but the
+    // messaging state should stay the same (at its custom value).
+    const secondCustomCsp = 'some other csp';
+    await chrome.userScripts.configureWorld({csp: secondCustomCsp});
+    worldConfig = (await chrome.userScripts.getWorldConfigurations())[0];
+    chrome.test.assertEq(secondCustomCsp, worldConfig.csp);
+    chrome.test.assertEq(customMessaging, worldConfig.messaging);
+
+    chrome.test.succeed();
+  },
+
   // Tests that a registered user script in the MAIN world cannot send or
   // receive messages when messaging is enabled.
   async function mainWorld_messagingAlwaysDisabled() {
@@ -226,9 +260,8 @@
     // User script uses the customized csp.
     chrome.test.assertEq('eval allowed', tab.title);
 
-    // Reset the csp. Currently this is only achievable by calling
-    // userScripts.configureWorld with no csp value (crbug.com/1497059).
-    await chrome.userScripts.configureWorld({});
+    // Reset the csp.
+    await chrome.userScripts.resetWorldConfiguration();
     tab = await navigateToRequestedUrl()
 
     // User script eses the extension's csp.
diff --git a/chrome/test/data/extensions/api_test/user_scripts/persistent_configure_world/worker.js b/chrome/test/data/extensions/api_test/user_scripts/persistent_configure_world/worker.js
index 0806d38..6b09d01 100644
--- a/chrome/test/data/extensions/api_test/user_scripts/persistent_configure_world/worker.js
+++ b/chrome/test/data/extensions/api_test/user_scripts/persistent_configure_world/worker.js
@@ -94,8 +94,8 @@
   // Verify user script still uses the customized csp.
   chrome.test.assertEq(['customized_csp'], await getInjectedElementIds(tab.id));
 
-  // Disable messaging and csp (by omitting its entry).
-  chrome.userScripts.configureWorld({messaging: false});
+  // Reset to defaults.
+  chrome.userScripts.resetWorldConfiguration();
   chrome.test.succeed();
 }
 
diff --git a/chrome/test/data/media/start-with-no-player.html b/chrome/test/data/media/start-with-no-player.html
new file mode 100644
index 0000000..1ee9cc1
--- /dev/null
+++ b/chrome/test/data/media/start-with-no-player.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Test page that adds a player on demand</title>
+  <meta name=viewport content='width=device-width initial-scale=1.0'>
+</head>
+<body>
+</body>
+<script>
+  function addVideo() {
+    const video = document.createElement('video');
+    video.src = 'bigbuck.webm';
+    document.body.append(video);
+  }
+</script>
+</html>
diff --git a/chrome/test/data/webui/chromeos/settings/os_settings_ui/os_settings_ui_page_visibility_revamp_test.ts b/chrome/test/data/webui/chromeos/settings/os_settings_ui/os_settings_ui_page_visibility_revamp_test.ts
index 258a6fa..4e10b23 100644
--- a/chrome/test/data/webui/chromeos/settings/os_settings_ui/os_settings_ui_page_visibility_revamp_test.ts
+++ b/chrome/test/data/webui/chromeos/settings/os_settings_ui/os_settings_ui_page_visibility_revamp_test.ts
@@ -6,8 +6,6 @@
  * @fileoverview
  * Suite of tests for page visibility in the CrOS Settings UI.
  *
- * - These tests expect the OsSettingsRevampWayfinding feature flag to be
- *   enabled.
  * - This suite is separated into a dedicated file to mitigate test timeouts
  *   since the element is very large.
  */
@@ -138,9 +136,6 @@
   suiteSetup(async () => {
     browserProxy = new TestAccountManagerBrowserProxy();
     AccountManagerBrowserProxyImpl.setInstanceForTesting(browserProxy);
-    assertTrue(
-        loadTimeData.getBoolean('isRevampWayfindingEnabled'),
-        'This suite expects OsSettingsRevampWayfinding to be enabled.');
     loadTimeData.overrideValues({
       isKerberosEnabled: true,  // Simulate kerberos route exists
     });
diff --git a/chrome/test/data/webui/settings/site_settings_page_test.ts b/chrome/test/data/webui/settings/site_settings_page_test.ts
index 37e5922..285a91f2 100644
--- a/chrome/test/data/webui/settings/site_settings_page_test.ts
+++ b/chrome/test/data/webui/settings/site_settings_page_test.ts
@@ -104,15 +104,6 @@
         defaultSettingLabel(ContentSetting.IMPORTANT_CONTENT, 'a', 'b', 'c'));
   });
 
-  test('AntiAbuseLinkRowHidden', async function() {
-    loadTimeData.overrideValues({
-      privateStateTokensEnabled: false,
-    });
-    setupPage();
-    assertFalse(isChildVisible(
-        page.$.advancedContentList, `#${ContentSettingsTypes.ANTI_ABUSE}`));
-  });
-
   test('CookiesLinkRowSublabel', async function() {
     // This test verifies the pre-3PCD label.
     loadTimeData.overrideValues({
diff --git a/chrome/test/fuzzing/atspi_in_process_fuzzer.cc b/chrome/test/fuzzing/atspi_in_process_fuzzer.cc
index 47b46b7c..9477495 100644
--- a/chrome/test/fuzzing/atspi_in_process_fuzzer.cc
+++ b/chrome/test/fuzzing/atspi_in_process_fuzzer.cc
@@ -40,6 +40,7 @@
 #include "sql/database.h"
 #include "sql/statement.h"
 #include "sql/test/test_helpers.h"
+#include "sql/transaction.h"
 #include "testing/libfuzzer/libfuzzer_exports.h"
 #include "ui/accessibility/platform/inspect/ax_inspect_scenario.h"
 #include "ui/accessibility/platform/inspect/ax_inspect_utils_auralinux.h"
@@ -1069,6 +1070,9 @@
   db_path = db_path.AppendASCII("atspi_in_process_fuzzer_controls.db");
   CHECK(db_->Open(db_path));
   CHECK(db_->Execute("PRAGMA foreign_keys = ON"));
+  // Atomically delete and create tables
+  sql::Transaction transaction(db_.get());
+  CHECK(transaction.Begin());
   // Delete some tables from older versions of this fuzzer
   DropTableIfExists("roles");
   DropTableIfExists("names");
@@ -1097,6 +1101,7 @@
         "controlsv4(id) ON DELETE CASCADE,  FOREIGN KEY(action_id) REFERENCES "
         "actionsv2(id) ON DELETE CASCADE, unique(control_id, action_id))"));
   }
+  CHECK(transaction.Commit());
 }
 
 void Database::DropTableIfExists(const std::string& table_name) {
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 2555654..0c3de52 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-16124.0.0-1065359
\ No newline at end of file
+16130.0.0-1065442
\ No newline at end of file
diff --git a/chromeos/ash/components/standalone_browser/BUILD.gn b/chromeos/ash/components/standalone_browser/BUILD.gn
index 103996fa..d637475f 100644
--- a/chromeos/ash/components/standalone_browser/BUILD.gn
+++ b/chromeos/ash/components/standalone_browser/BUILD.gn
@@ -13,8 +13,6 @@
   sources = [
     "channel_util.cc",
     "channel_util.h",
-    "lacros_availability.cc",
-    "lacros_availability.h",
     "lacros_selection.cc",
     "lacros_selection.h",
     "standalone_browser_features.cc",
@@ -41,7 +39,6 @@
 
   sources = [
     "channel_util_unittest.cc",
-    "lacros_availability_unittest.cc",
     "lacros_selection_unittest.cc",
   ]
 
diff --git a/chromeos/ash/components/standalone_browser/DEPS b/chromeos/ash/components/standalone_browser/DEPS
index cb61470b..6be56c0 100644
--- a/chromeos/ash/components/standalone_browser/DEPS
+++ b/chromeos/ash/components/standalone_browser/DEPS
@@ -1,23 +1,9 @@
 specific_include_rules = {
-  "lacros_availability\.cc": [
-    "+components/policy/core/common/policy_map.h",
-    "+components/policy/policy_constants.h",
-    "+components/user_manager/user.h",
-  ],
   "lacros_selection\.cc": [
     "+components/policy/core/common/policy_map.h",
     "+components/policy/policy_constants.h",
     "+components/user_manager/user_manager.h",
   ],
-  "browser_support\.cc": [
-    "+ash/constants/ash_switches.h",
-    "+components/user_manager/user.h",
-    "+components/user_manager/user_manager.h",
-    "+components/user_manager/user_type.h",
-  ],
-  "lacros_availability_unittest\.cc": [
-    "+components/user_manager/fake_user_manager.h",
-  ],
   "lacros_selection_unittest\.cc": [
     "+ash/constants/ash_switches.h",
     "+components/account_id/account_id.h",
diff --git a/chromeos/ash/components/standalone_browser/lacros_availability.cc b/chromeos/ash/components/standalone_browser/lacros_availability.cc
deleted file mode 100644
index 17ebc71..0000000
--- a/chromeos/ash/components/standalone_browser/lacros_availability.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
-
-#include "ash/constants/ash_switches.h"
-#include "base/command_line.h"
-#include "base/containers/fixed_flat_map.h"
-#include "base/logging.h"
-#include "base/notreached.h"
-#include "components/policy/core/common/policy_map.h"
-#include "components/policy/policy_constants.h"
-#include "components/user_manager/user.h"
-#include "google_apis/gaia/gaia_auth_util.h"
-
-namespace ash::standalone_browser {
-namespace {
-
-// The conversion map for LacrosAvailability policy data. The values must match
-// the ones from LacrosAvailability.yaml.
-// TODO(crbug.com/40269372): Remove the side_by_side and lacros_primary values
-// from the policy.
-constexpr auto kLacrosAvailabilityMap =
-    base::MakeFixedFlatMap<std::string_view, LacrosAvailability>({
-        {"user_choice", LacrosAvailability::kUserChoice},
-        {"lacros_disallowed", LacrosAvailability::kLacrosDisallowed},
-        {"side_by_side", LacrosAvailability::kLacrosDisallowed},
-        {"lacros_primary", LacrosAvailability::kLacrosDisallowed},
-        {"lacros_only", LacrosAvailability::kLacrosOnly},
-    });
-
-}  // namespace
-
-BASE_FEATURE(kLacrosGooglePolicyRollout,
-             "LacrosGooglePolicyRollout",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
-std::optional<LacrosAvailability> ParseLacrosAvailability(
-    std::string_view value) {
-  auto it = kLacrosAvailabilityMap.find(value);
-  if (it != kLacrosAvailabilityMap.end()) {
-    return it->second;
-  }
-
-  LOG(ERROR) << "Unknown LacrosAvailability policy value is passed: " << value;
-  return std::nullopt;
-}
-
-std::string_view GetLacrosAvailabilityPolicyName(LacrosAvailability value) {
-  for (const auto& entry : kLacrosAvailabilityMap) {
-    if (entry.second == value) {
-      return entry.first;
-    }
-  }
-
-  NOTREACHED();
-}
-
-bool IsGoogleInternal(const user_manager::User* user) {
-  if (!user) {
-    return false;
-  }
-
-  const std::string_view email = user->GetAccountId().GetUserEmail();
-  return gaia::IsGoogleInternalAccountEmail(email) ||
-         gaia::IsGoogleRobotAccountEmail(email) ||
-         gaia::ExtractDomainName(gaia::SanitizeEmail(email)) ==
-             "managedchrome.com";
-}
-
-LacrosAvailability DetermineLacrosAvailabilityFromPolicyValue(
-    const user_manager::User* user,
-    std::string_view policy_value) {
-  // Users can set this switch in chrome://flags to disable the effect of the
-  // lacros-availability policy. This should only be allowed for Googlers.
-  // Note: Flag actively used by CfM to bypass LaCrOS Availability Policy.
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(ash::switches::kLacrosAvailabilityIgnore) &&
-      IsGoogleInternal(user)) {
-    return LacrosAvailability::kUserChoice;
-  }
-
-  if (policy_value.empty()) {
-    // Some tests call IsLacrosAllowedToBeEnabled but don't have the value set.
-    return LacrosAvailability::kUserChoice;
-  }
-
-  auto result = ParseLacrosAvailability(policy_value);
-  if (!result.has_value()) {
-    return LacrosAvailability::kUserChoice;
-  }
-
-  if (IsGoogleInternal(user) &&
-      !base::FeatureList::IsEnabled(kLacrosGooglePolicyRollout) &&
-      result != LacrosAvailability::kLacrosDisallowed) {
-    return LacrosAvailability::kUserChoice;
-  }
-
-  return result.value();
-}
-
-LacrosAvailability GetLacrosAvailability(const user_manager::User* user,
-                                         const policy::PolicyMap& policy_map) {
-  const base::Value* value = policy_map.GetValue(
-      policy::key::kLacrosAvailability, base::Value::Type::STRING);
-  return DetermineLacrosAvailabilityFromPolicyValue(
-      user, value ? value->GetString() : std::string_view());
-}
-
-}  // namespace ash::standalone_browser
diff --git a/chromeos/ash/components/standalone_browser/lacros_availability.h b/chromeos/ash/components/standalone_browser/lacros_availability.h
deleted file mode 100644
index 2b015f5..0000000
--- a/chromeos/ash/components/standalone_browser/lacros_availability.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_COMPONENTS_STANDALONE_BROWSER_LACROS_AVAILABILITY_H_
-#define CHROMEOS_ASH_COMPONENTS_STANDALONE_BROWSER_LACROS_AVAILABILITY_H_
-
-#include <optional>
-#include <string_view>
-
-#include "base/component_export.h"
-#include "base/feature_list.h"
-
-namespace policy {
-class PolicyMap;
-}
-
-namespace user_manager {
-class User;
-}
-
-namespace ash::standalone_browser {
-// Represents the policy indicating how to launch Lacros browser, named
-// LacrosAvailability. The values shall be consistent with the controlling
-// policy.
-// Values 2 and 3 were removed and should not be reused.
-enum class LacrosAvailability {
-  // Indicates that the user decides whether to enable Lacros (if allowed) and
-  // make it the primary/only browser.
-  kUserChoice = 0,
-  // Indicates that Lacros is not allowed to be enabled.
-  kLacrosDisallowed = 1,
-  // Indicates that Lacros (if allowed) is the only available browser.
-  kLacrosOnly = 4
-};
-
-// The internal name in about_flags.cc for the lacros-availablility-policy
-// config.
-inline constexpr char kLacrosAvailabilityPolicyInternalName[] =
-    "lacros-availability-policy";
-
-// The commandline flag name of lacros-availability-policy.
-// The value should be the policy value as defined just below.
-// The values need to be consistent with kLacrosAvailabilityMap above.
-inline constexpr char kLacrosAvailabilityPolicySwitch[] =
-    "lacros-availability-policy";
-inline constexpr char kLacrosAvailabilityPolicyUserChoice[] = "user_choice";
-inline constexpr char kLacrosAvailabilityPolicyLacrosDisabled[] =
-    "lacros_disabled";
-inline constexpr char kLacrosAvailabilityPolicyLacrosOnly[] = "lacros_only";
-
-// When this feature is enabled, Lacros is allowed to roll out by policy to
-// Googlers.
-COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_STANDALONE_BROWSER)
-BASE_DECLARE_FEATURE(kLacrosGooglePolicyRollout);
-
-// Parses the string representation of LacrosAvailability policy value into
-// the enum value. Returns nullopt on unknown value.
-COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_STANDALONE_BROWSER)
-std::optional<LacrosAvailability> ParseLacrosAvailability(
-    std::string_view value);
-
-// Returns the policy value name from the given value.
-COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_STANDALONE_BROWSER)
-std::string_view GetLacrosAvailabilityPolicyName(LacrosAvailability value);
-
-// Given a raw policy value, decides what LacrosAvailability value should be
-// used as a result of policy application.
-COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_STANDALONE_BROWSER)
-LacrosAvailability DetermineLacrosAvailabilityFromPolicyValue(
-    const user_manager::User* user,
-    std::string_view policy_value);
-
-// Returns LacrosAvailability policy for the given `user` and its `policy_map`.
-// This function may take a look at more surrounding context.
-LacrosAvailability GetLacrosAvailability(const user_manager::User* user,
-                                         const policy::PolicyMap& policy_map);
-
-// Returns true if the given user's profile is associated with a google internal
-// account. This includes @managedchrome.com accounts.
-// TODO(andreaorru): conceptually, this is an internal utility function
-// and should not be exported. Currently, `crosapi::browser_util` still
-// depends on it. Remove once the IsLacrosEnabled* refactoring is complete.
-COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_STANDALONE_BROWSER)
-bool IsGoogleInternal(const user_manager::User* user);
-
-}  // namespace ash::standalone_browser
-
-#endif  // CHROMEOS_ASH_COMPONENTS_STANDALONE_BROWSER_LACROS_AVAILABILITY_H_
diff --git a/chromeos/ash/components/standalone_browser/lacros_availability_unittest.cc b/chromeos/ash/components/standalone_browser/lacros_availability_unittest.cc
deleted file mode 100644
index 0cc4a46..0000000
--- a/chromeos/ash/components/standalone_browser/lacros_availability_unittest.cc
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
-
-#include "ash/constants/ash_switches.h"
-#include "base/test/scoped_command_line.h"
-#include "base/test/scoped_feature_list.h"
-#include "components/account_id/account_id.h"
-#include "components/user_manager/fake_user_manager.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using user_manager::User;
-
-namespace ash::standalone_browser {
-
-class LacrosAvailabilityTest : public testing::Test {
- public:
-  const User* AddRegularUser(const std::string& email) {
-    AccountId account_id = AccountId::FromUserEmail(email);
-    const User* user = fake_user_manager_.AddUser(account_id);
-    fake_user_manager_.UserLoggedIn(account_id, user->username_hash(),
-                                    /*browser_restart=*/false,
-                                    /*is_child=*/false);
-    return user;
-  }
-
-  user_manager::FakeUserManager fake_user_manager_;
-};
-
-TEST_F(LacrosAvailabilityTest,
-       DetermineLacrosAvailabilityFromPolicyValueExternal) {
-  const User* const user = AddRegularUser("user@random.com");
-
-  // For non-Googlers, the policy can't be ignored by command line flag.
-  {
-    base::test::ScopedCommandLine command_line;
-    command_line.GetProcessCommandLine()->AppendSwitch(
-        ash::switches::kLacrosAvailabilityIgnore);
-    EXPECT_EQ(LacrosAvailability::kLacrosOnly,
-              DetermineLacrosAvailabilityFromPolicyValue(user, "lacros_only"));
-  }
-
-  // If there's no policy value, the choice is left to the user.
-  EXPECT_EQ(LacrosAvailability::kUserChoice,
-            DetermineLacrosAvailabilityFromPolicyValue(user, ""));
-
-  // If the policy value is valid and there is no command line flag, the policy
-  // should be respected.
-  EXPECT_EQ(LacrosAvailability::kLacrosOnly,
-            DetermineLacrosAvailabilityFromPolicyValue(user, "lacros_only"));
-
-  // If the policy value is invalid, the choice is left to the user.
-  EXPECT_EQ(
-      LacrosAvailability::kUserChoice,
-      DetermineLacrosAvailabilityFromPolicyValue(user, "lacros_tertiary"));
-
-  // Whether LacrosGooglePolicyRollout is enabled or not makes no difference for
-  // normal users.
-  {
-    // Disable LacrosGooglePolicyRollout.
-    base::test::ScopedFeatureList feature_list;
-    feature_list.InitWithFeatures({}, {kLacrosGooglePolicyRollout});
-    EXPECT_EQ(
-        LacrosAvailability::kLacrosDisallowed,
-        DetermineLacrosAvailabilityFromPolicyValue(user, "lacros_disallowed"));
-    EXPECT_EQ(LacrosAvailability::kLacrosOnly,
-              DetermineLacrosAvailabilityFromPolicyValue(user, "lacros_only"));
-  }
-  {
-    // Enable LacrosGooglePolicyRollout.
-    base::test::ScopedFeatureList feature_list;
-    feature_list.InitWithFeatures({kLacrosGooglePolicyRollout}, {});
-    EXPECT_EQ(
-        LacrosAvailability::kLacrosDisallowed,
-        DetermineLacrosAvailabilityFromPolicyValue(user, "lacros_disallowed"));
-    EXPECT_EQ(LacrosAvailability::kLacrosOnly,
-              DetermineLacrosAvailabilityFromPolicyValue(user, "lacros_only"));
-  }
-}
-
-struct LacrosAvailabilityInternalParams {
-  std::string test_name;
-  std::string test_account;
-};
-
-class LacrosAvailabilityInternalTest
-    : public LacrosAvailabilityTest,
-      public testing::WithParamInterface<LacrosAvailabilityInternalParams> {};
-
-TEST_P(LacrosAvailabilityInternalTest,
-       DetermineLacrosAvailabilityFromPolicyValueInternal) {
-  const User* const user = AddRegularUser(GetParam().test_account);
-
-  // For Googlers, the policy can be ignored by command line flag.
-  {
-    base::test::ScopedCommandLine command_line;
-    command_line.GetProcessCommandLine()->AppendSwitch(
-        ash::switches::kLacrosAvailabilityIgnore);
-    EXPECT_EQ(LacrosAvailability::kUserChoice,
-              DetermineLacrosAvailabilityFromPolicyValue(user, "lacros_only"));
-  }
-
-  // If there's no policy value, the choice is left to the user.
-  EXPECT_EQ(LacrosAvailability::kUserChoice,
-            DetermineLacrosAvailabilityFromPolicyValue(user, ""));
-
-  // If the policy value is invalid, the choice is left to the user.
-  EXPECT_EQ(
-      LacrosAvailability::kUserChoice,
-      DetermineLacrosAvailabilityFromPolicyValue(user, "lacros_tertiary"));
-
-  {
-    // Disable LacrosGooglePolicyRollout.
-    base::test::ScopedFeatureList feature_list;
-    feature_list.InitWithFeatures({}, {kLacrosGooglePolicyRollout});
-
-    // For Googlers, if the GooglePolicyRollout feature is disabled, the choice
-    // is left to the user...
-    EXPECT_EQ(LacrosAvailability::kUserChoice,
-              DetermineLacrosAvailabilityFromPolicyValue(user, "lacros_only"));
-
-    // ...unless the policy is that Lacros is explicitly disallowed.
-    EXPECT_EQ(
-        LacrosAvailability::kLacrosDisallowed,
-        DetermineLacrosAvailabilityFromPolicyValue(user, "lacros_disallowed"));
-  }
-
-  {
-    // Enable LacrosGooglePolicyRollout.
-    base::test::ScopedFeatureList feature_list;
-    feature_list.InitWithFeatures({kLacrosGooglePolicyRollout}, {});
-
-    // For Googlers, if the GooglePolicyRollout feature is enabled, the policy
-    // should be respected.
-    EXPECT_EQ(LacrosAvailability::kLacrosOnly,
-              DetermineLacrosAvailabilityFromPolicyValue(user, "lacros_only"));
-  }
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    LacrosAvailabilityInternalTests,
-    LacrosAvailabilityInternalTest,
-    testing::ValuesIn<LacrosAvailabilityInternalParams>(
-        {{"Google_Internal", "user@google.com"},
-         {"Enterprise", "user@managedchrome.com"},
-         {"Robot_Account", "something@blah.iam.gserviceaccount.com"},
-         {"Auth", "service@blah.apps.googleusercontent.com"}}),
-    [](const testing::TestParamInfo<LacrosAvailabilityInternalTest::ParamType>&
-           info) { return info.param.test_name; });
-
-}  // namespace ash::standalone_browser
diff --git a/chromeos/ash/components/standalone_browser/lacros_selection.cc b/chromeos/ash/components/standalone_browser/lacros_selection.cc
index 46db268..d7a440a 100644
--- a/chromeos/ash/components/standalone_browser/lacros_selection.cc
+++ b/chromeos/ash/components/standalone_browser/lacros_selection.cc
@@ -10,10 +10,10 @@
 #include "base/containers/flat_map.h"
 #include "base/logging.h"
 #include "base/notreached.h"
-#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/policy_constants.h"
 #include "components/user_manager/user_manager.h"
+#include "google_apis/gaia/gaia_auth_util.h"
 
 namespace ash::standalone_browser {
 
@@ -33,6 +33,18 @@
         {"rootfs", LacrosSelectionPolicy::kRootfs},
     });
 
+bool IsGoogleInternal(const user_manager::User* user) {
+  if (!user) {
+    return false;
+  }
+
+  const std::string_view email = user->GetAccountId().GetUserEmail();
+  return gaia::IsGoogleInternalAccountEmail(email) ||
+         gaia::IsGoogleRobotAccountEmail(email) ||
+         gaia::ExtractDomainName(gaia::SanitizeEmail(email)) ==
+             "managedchrome.com";
+}
+
 }  // namespace
 
 void CacheLacrosSelection(const policy::PolicyMap& map) {
diff --git a/chromeos/ash/services/ime/public/cpp/shared_lib/interfaces.h b/chromeos/ash/services/ime/public/cpp/shared_lib/interfaces.h
index 3bebdb4..726e2f8 100644
--- a/chromeos/ash/services/ime/public/cpp/shared_lib/interfaces.h
+++ b/chromeos/ash/services/ime/public/cpp/shared_lib/interfaces.h
@@ -263,6 +263,11 @@
 __attribute__((visibility("default"))) bool InitializeConnectionFactory(
     uint32_t receiver_connection_factory_handle);
 
+// Bootstraps an implementation of a ConnectionFactory in the IME shared lib.
+// Returns false if the connection attempt was unsuccessful.
+__attribute__((visibility("default"))) bool InitializeConnectionFactoryV2(
+    uintptr_t receiver_connection_factory_handle);
+
 // Returns whether there's a direct Mojo connection to an input method.
 __attribute__((visibility("default"))) bool IsInputMethodConnected();
 
diff --git a/chromeos/ash/services/orca/public/cpp/orca_entry.h b/chromeos/ash/services/orca/public/cpp/orca_entry.h
index 4712bfec..51ed954 100644
--- a/chromeos/ash/services/orca/public/cpp/orca_entry.h
+++ b/chromeos/ash/services/orca/public/cpp/orca_entry.h
@@ -40,6 +40,12 @@
                 uint32_t receiver_handle,
                 OrcaLogger* logger);
 
+// Returns whether the receiver was successfully bound.
+OrcaBindServiceStatus __attribute__((visibility("default")))
+OrcaBindServiceV2(const MojoSystemThunks2* mojo_thunks,
+                  uintptr_t receiver_handle,
+                  OrcaLogger* logger);
+
 // Resets the OrcaService.
 // If `OrcaBindService` was called, this function must be called to clean up
 // resources before calling OrcaBindService again or unloading the shared
diff --git a/chromeos/assistant/internal b/chromeos/assistant/internal
index 4a629f0..366dc48 160000
--- a/chromeos/assistant/internal
+++ b/chromeos/assistant/internal
@@ -1 +1 @@
-Subproject commit 4a629f07bb5192d38397131cbbec303d81ac1179
+Subproject commit 366dc486f8f18d097f22acb469b8eab41b14c9ad
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index 4c09f4c..d447d4cd 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -3546,6 +3546,12 @@
         <message name="IDS_SEA_PEN_FREEFORM_INTRODUCTION_DIALOG_FIRST_PARAGRAPH" desc="Option to fill in the SEA_PEN_INTRO_FIRST_PARAGRAPH of the IDS_SEA_PEN_INTRODUCTION_DIALOG_CONTENT.">
           When you select “Create with AI,” write a custom prompt. Or you can select “AI wallpapers,” to choose a theme and then select the underlined words to personalize your AI wallpaper.
         </message>
+        <message name="IDS_SEA_PEN_FREEFORM_ARIA_LABEL_SAMPLE_PROMPTS" desc="Aria label for a list of sample text prompts to be used to generate AI images.">
+          Sample prompts
+        </message>
+        <message name="IDS_SEA_PEN_FREEFORM_ARIA_LABEL_SUGGESTIONS" desc="Aria label for a list of suggestions that can be added to an AI text-to-image prompt (e.g. 'realistic photo')">
+          Suggestions
+        </message>
 
         <!-- Sea Pen Templates (AUTOGENERATED - contact assistive-eng@google.com before editing) -->
         <!-- Wallpaper template glowscapes -->
diff --git a/chromeos/chromeos_strings_grd/IDS_SEA_PEN_FREEFORM_ARIA_LABEL_SAMPLE_PROMPTS.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SEA_PEN_FREEFORM_ARIA_LABEL_SAMPLE_PROMPTS.png.sha1
new file mode 100644
index 0000000..132911e
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SEA_PEN_FREEFORM_ARIA_LABEL_SAMPLE_PROMPTS.png.sha1
@@ -0,0 +1 @@
+e1c326a1af66fa0508ab2a4bc40c33df69780216
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SEA_PEN_FREEFORM_ARIA_LABEL_SUGGESTIONS.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SEA_PEN_FREEFORM_ARIA_LABEL_SUGGESTIONS.png.sha1
new file mode 100644
index 0000000..ea3fac27
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SEA_PEN_FREEFORM_ARIA_LABEL_SUGGESTIONS.png.sha1
@@ -0,0 +1 @@
+0c22f392a9f4ebf89771677485ab1990810d09b4
\ No newline at end of file
diff --git a/chromeos/services/assistant/public/shared/BUILD.gn b/chromeos/services/assistant/public/shared/BUILD.gn
index 825caae..b93a480 100644
--- a/chromeos/services/assistant/public/shared/BUILD.gn
+++ b/chromeos/services/assistant/public/shared/BUILD.gn
@@ -24,3 +24,25 @@
 
   deps = [ "//base:base" ]
 }
+
+source_set("new_entry_point_constants") {
+  if (is_chromeos && is_chrome_branded) {
+    deps = [ "//chromeos/assistant/internal:new_entry_point_constants" ]
+  } else {
+    deps = [ ":new_entry_point_constants_placeholder" ]
+  }
+}
+
+source_set("new_entry_point_constants_placeholder") {
+  sources = [ "new_entry_point_constants.cc" ]
+  deps = [
+    ":new_entry_point_constants_interface",
+    "//chrome/app/theme:theme_resources_grit",
+  ]
+}
+
+source_set("new_entry_point_constants_interface") {
+  sources = [ "new_entry_point_constants.h" ]
+
+  deps = [ "//base" ]
+}
diff --git a/chromeos/services/assistant/public/shared/DEPS b/chromeos/services/assistant/public/shared/DEPS
new file mode 100644
index 0000000..5805ad1
--- /dev/null
+++ b/chromeos/services/assistant/public/shared/DEPS
@@ -0,0 +1,5 @@
+specific_include_rules = {
+  "new_entry_point_constants.cc": [
+    "+chrome/grit",
+  ]
+}
diff --git a/chromeos/services/assistant/public/shared/new_entry_point_constants.cc b/chromeos/services/assistant/public/shared/new_entry_point_constants.cc
new file mode 100644
index 0000000..f0dc01e
--- /dev/null
+++ b/chromeos/services/assistant/public/shared/new_entry_point_constants.cc
@@ -0,0 +1,14 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/services/assistant/public/shared/new_entry_point_constants.h"
+
+#include "chrome/grit/theme_resources.h"
+
+namespace chromeos::assistant {
+
+// Use `IDR_PRODUCT_LOGO_32` as a placeholder.
+const int kIconResourceId = IDR_PRODUCT_LOGO_32;
+
+}  // namespace chromeos::assistant
diff --git a/chromeos/services/assistant/public/shared/new_entry_point_constants.h b/chromeos/services/assistant/public/shared/new_entry_point_constants.h
new file mode 100644
index 0000000..38ca977
--- /dev/null
+++ b/chromeos/services/assistant/public/shared/new_entry_point_constants.h
@@ -0,0 +1,16 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_SERVICES_ASSISTANT_PUBLIC_SHARED_NEW_ENTRY_POINT_CONSTANTS_H_
+#define CHROMEOS_SERVICES_ASSISTANT_PUBLIC_SHARED_NEW_ENTRY_POINT_CONSTANTS_H_
+
+#include "base/component_export.h"
+
+namespace chromeos::assistant {
+
+COMPONENT_EXPORT(ASSISTANT_SERVICE_SHARED) extern const int kIconResourceId;
+
+}
+
+#endif  // CHROMEOS_SERVICES_ASSISTANT_PUBLIC_SHARED_NEW_ENTRY_POINT_CONSTANTS_H_
diff --git a/clank b/clank
index 5c28d3d..94e9a17 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 5c28d3db4b56fc58531352e6cb59a7c8db2db9e3
+Subproject commit 94e9a17ca9d53b1cd11478b59a5185931ca5d547
diff --git a/components/autofill/core/browser/data_manager/payments/payments_data_manager.cc b/components/autofill/core/browser/data_manager/payments/payments_data_manager.cc
index 4e62fb5..b5598b3 100644
--- a/components/autofill/core/browser/data_manager/payments/payments_data_manager.cc
+++ b/components/autofill/core/browser/data_manager/payments/payments_data_manager.cc
@@ -842,16 +842,15 @@
   return result;
 }
 
-std::vector<AutofillOfferData*> PaymentsDataManager::GetAutofillOffers() const {
+std::vector<const AutofillOfferData*> PaymentsDataManager::GetAutofillOffers()
+    const {
   if (!IsAutofillWalletImportEnabled() || !IsAutofillPaymentMethodsEnabled()) {
     return {};
   }
-  std::vector<AutofillOfferData*> result;
-  result.reserve(autofill_offer_data_.size());
-  for (const auto& data : autofill_offer_data_) {
-    result.push_back(data.get());
-  }
-  return result;
+  return base::ToVector(
+      autofill_offer_data_,
+      [](const std::unique_ptr<AutofillOfferData>& offer)
+          -> const AutofillOfferData* { return offer.get(); });
 }
 
 std::vector<const AutofillOfferData*>
diff --git a/components/autofill/core/browser/data_manager/payments/payments_data_manager.h b/components/autofill/core/browser/data_manager/payments/payments_data_manager.h
index 71859d57..336d8466 100644
--- a/components/autofill/core/browser/data_manager/payments/payments_data_manager.h
+++ b/components/autofill/core/browser/data_manager/payments/payments_data_manager.h
@@ -226,7 +226,7 @@
       const;
 
   // Returns autofill offer data, including card-linked and promo code offers.
-  virtual std::vector<AutofillOfferData*> GetAutofillOffers() const;
+  std::vector<const AutofillOfferData*> GetAutofillOffers() const;
 
   // Returns autofill offer data, but only promo code offers that are not
   // expired and that are for the given |origin|.
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_test_base.cc b/components/autofill/core/browser/metrics/autofill_metrics_test_base.cc
index 106435024..df987a3 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics_test_base.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics_test_base.cc
@@ -87,7 +87,8 @@
       .set_credit_card_save_manager(
           std::make_unique<TestCreditCardSaveManager>(autofill_client_.get()));
   autofill_client_->GetPaymentsAutofillClient()->set_autofill_offer_manager(
-      std::make_unique<AutofillOfferManager>(&personal_data()));
+      std::make_unique<AutofillOfferManager>(
+          &personal_data().payments_data_manager()));
 
   auto browser_autofill_manager =
       std::make_unique<TestBrowserAutofillManager>(autofill_driver_.get());
diff --git a/components/autofill/core/browser/payments/autofill_offer_manager.cc b/components/autofill/core/browser/payments/autofill_offer_manager.cc
index 602b0d9..0d1174d 100644
--- a/components/autofill/core/browser/payments/autofill_offer_manager.cc
+++ b/components/autofill/core/browser/payments/autofill_offer_manager.cc
@@ -4,6 +4,7 @@
 
 #include "components/autofill/core/browser/payments/autofill_offer_manager.h"
 
+#include "base/check_deref.h"
 #include "base/containers/contains.h"
 #include "base/functional/bind.h"
 #include "base/ranges/ranges.h"
@@ -20,10 +21,10 @@
 #include "ui/base/l10n/l10n_util.h"
 
 namespace autofill {
-AutofillOfferManager::AutofillOfferManager(PersonalDataManager* personal_data)
-    : personal_data_(personal_data) {
-  payments_data_manager_observation.Observe(
-      &personal_data_->payments_data_manager());
+AutofillOfferManager::AutofillOfferManager(
+    PaymentsDataManager* payments_data_manager)
+    : payments_data_manager_(CHECK_DEREF(payments_data_manager)) {
+  payments_data_manager_observation.Observe(payments_data_manager);
   UpdateEligibleMerchantDomains();
 }
 
@@ -48,13 +49,12 @@
     return {};
   }
 
-  const std::vector<AutofillOfferData*> offers =
-      personal_data_->payments_data_manager().GetAutofillOffers();
   const std::vector<const CreditCard*> cards =
-      personal_data_->payments_data_manager().GetCreditCards();
+      payments_data_manager_->GetCreditCards();
   AutofillOfferManager::CardLinkedOffersMap card_linked_offers_map;
 
-  for (AutofillOfferData* offer : offers) {
+  for (const AutofillOfferData* offer :
+       payments_data_manager_->GetAutofillOffers()) {
     // Ensure the offer is valid.
     if (!offer->IsActiveAndEligibleForOrigin(
             last_committed_primary_main_frame_origin)) {
@@ -86,10 +86,10 @@
       last_committed_primary_main_frame_url.DeprecatedGetOriginAsURL());
 }
 
-AutofillOfferData* AutofillOfferManager::GetOfferForUrl(
-    const GURL& last_committed_primary_main_frame_url) {
-  for (AutofillOfferData* offer :
-       personal_data_->payments_data_manager().GetAutofillOffers()) {
+const AutofillOfferData* AutofillOfferManager::GetOfferForUrl(
+    const GURL& last_committed_primary_main_frame_url) const {
+  for (const AutofillOfferData* offer :
+       payments_data_manager_->GetAutofillOffers()) {
     if (offer->IsActiveAndEligibleForOrigin(
             last_committed_primary_main_frame_url.DeprecatedGetOriginAsURL())) {
       return offer;
@@ -101,10 +101,8 @@
 
 void AutofillOfferManager::UpdateEligibleMerchantDomains() {
   eligible_merchant_domains_.clear();
-  std::vector<AutofillOfferData*> offers =
-      personal_data_->payments_data_manager().GetAutofillOffers();
-
-  for (auto* offer : offers) {
+  for (const AutofillOfferData* offer :
+       payments_data_manager_->GetAutofillOffers()) {
     eligible_merchant_domains_.insert(offer->GetMerchantOrigins().begin(),
                                       offer->GetMerchantOrigins().end());
   }
diff --git a/components/autofill/core/browser/payments/autofill_offer_manager.h b/components/autofill/core/browser/payments/autofill_offer_manager.h
index 0d877ba..b34507d 100644
--- a/components/autofill/core/browser/payments/autofill_offer_manager.h
+++ b/components/autofill/core/browser/payments/autofill_offer_manager.h
@@ -25,7 +25,7 @@
 class AutofillClient;
 class AutofillOfferData;
 class OfferNotificationHandler;
-class PersonalDataManager;
+class PaymentsDataManager;
 
 // Manages all Autofill related offers. One per browser context. Owned and
 // created by the AutofillOfferManagerFactory.
@@ -33,9 +33,9 @@
                              public PaymentsDataManager::Observer {
  public:
   // Mapping from credit card guid id to offer data.
-  using CardLinkedOffersMap = std::map<std::string, AutofillOfferData*>;
+  using CardLinkedOffersMap = std::map<std::string, const AutofillOfferData*>;
 
-  AutofillOfferManager(PersonalDataManager* personal_data);
+  explicit AutofillOfferManager(PaymentsDataManager* payments_data_manager);
   ~AutofillOfferManager() override;
   AutofillOfferManager(const AutofillOfferManager&) = delete;
   AutofillOfferManager& operator=(const AutofillOfferManager&) = delete;
@@ -47,18 +47,18 @@
   void OnDidNavigateFrame(AutofillClient& client);
 
   // Gets a mapping between credit card's guid id and eligible card-linked
-  // offers on the |last_committed_primary_main_frame_url|.
+  // offers on the `last_committed_primary_main_frame_url`.
   CardLinkedOffersMap GetCardLinkedOffersMap(
       const GURL& last_committed_primary_main_frame_url) const;
 
-  // Returns true only if the domain of |last_committed_primary_main_frame_url|
+  // Returns true only if the domain of `last_committed_primary_main_frame_url`
   // has an offer.
   bool IsUrlEligible(const GURL& last_committed_primary_main_frame_url);
 
   // Returns the offer that contains the domain of
-  // |last_committed_primary_main_frame_url|.
-  AutofillOfferData* GetOfferForUrl(
-      const GURL& last_committed_primary_main_frame_url);
+  // `last_committed_primary_main_frame_url`.
+  const AutofillOfferData* GetOfferForUrl(
+      const GURL& last_committed_primary_main_frame_url) const;
 
  private:
   FRIEND_TEST_ALL_PREFIXES(
@@ -68,11 +68,11 @@
   friend class OfferNotificationBubbleViewsInteractiveUiTest;
   friend class OfferNotificationControllerAndroidBrowserTest;
 
-  // Queries |personal_data_| to reset the elements of
-  // |eligible_merchant_domains_|
+  // Queries `payments_data_manager_` to reset the elements of
+  // `eligible_merchant_domains_`.
   void UpdateEligibleMerchantDomains();
 
-  raw_ptr<PersonalDataManager> personal_data_;
+  const raw_ref<PaymentsDataManager> payments_data_manager_;
 
   // This set includes all the eligible domains where offers are applicable.
   // This is used as a local cache and will be updated whenever the data in the
diff --git a/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc b/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc
index 9bdca40..13c83c6 100644
--- a/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc
+++ b/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc
@@ -56,8 +56,8 @@
     personal_data_manager_.SetPrefService(autofill_client_.GetPrefs());
     personal_data_manager_.SetSyncServiceForTest(&sync_service_);
     personal_data_manager_.SetPrefService(autofill_client_.GetPrefs());
-    autofill_offer_manager_ =
-        std::make_unique<AutofillOfferManager>(&personal_data_manager_);
+    autofill_offer_manager_ = std::make_unique<AutofillOfferManager>(
+        &personal_data_manager_.payments_data_manager());
   }
 
   CreditCard CreateCreditCard(std::string guid,
@@ -223,7 +223,7 @@
           card1, "5%", /*expired=*/false,
           {GURL("http://www.google.com"), GURL("http://www.youtube.com")}));
 
-  AutofillOfferData* result =
+  const AutofillOfferData* result =
       autofill_offer_manager_->GetOfferForUrl(GURL("http://www.example.com"));
   EXPECT_EQ(nullptr, result);
 }
@@ -247,7 +247,7 @@
   personal_data_manager_.test_payments_data_manager().AddAutofillOfferData(
       offer2);
 
-  AutofillOfferData* result =
+  const AutofillOfferData* result =
       autofill_offer_manager_->GetOfferForUrl(GURL("http://www.example.com"));
   EXPECT_EQ(offer2, *result);
 }
diff --git a/components/autofill/core/browser/payments/offer_notification_handler.cc b/components/autofill/core/browser/payments/offer_notification_handler.cc
index d09c8b1e..f08b0a5 100644
--- a/components/autofill/core/browser/payments/offer_notification_handler.cc
+++ b/components/autofill/core/browser/payments/offer_notification_handler.cc
@@ -16,7 +16,7 @@
 
 namespace {
 
-bool IsOfferValid(AutofillOfferData* offer) {
+bool IsOfferValid(const AutofillOfferData* offer) {
   if (!offer) {
     return false;
   }
@@ -51,7 +51,7 @@
     //   Currently, if a url has both types of offers and the promo code offer
     //   is selected, no bubble will end up being shown (due to not yet being
     //   implemented).
-    AutofillOfferData* offer = offer_manager_->GetOfferForUrl(url);
+    const AutofillOfferData* const offer = offer_manager_->GetOfferForUrl(url);
     CHECK(IsOfferValid(offer));
     int64_t offer_id = offer->GetOfferId();
     bool offer_id_has_shown_before = shown_notification_ids_.contains(offer_id);
diff --git a/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator.cc b/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator.cc
index fb9ebabe..e2a8783 100644
--- a/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator.cc
+++ b/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator.cc
@@ -97,7 +97,7 @@
 
 // Returns the card-linked offers map with credit card guid as the key and the
 // pointer to the linked AutofillOfferData as the value.
-std::map<std::string, AutofillOfferData*> GetCardLinkedOffers(
+std::map<std::string, const AutofillOfferData*> GetCardLinkedOffers(
     const AutofillClient& autofill_client) {
   if (const AutofillOfferManager* offer_manager =
           autofill_client.GetPaymentsAutofillClient()
@@ -739,7 +739,7 @@
           .GetCreditCardsToSuggest(use_legacy_algorithm);
   // If a card has available card linked offers on the last committed url, rank
   // it to the top.
-  if (std::map<std::string, AutofillOfferData*> card_linked_offers_map =
+  if (std::map<std::string, const AutofillOfferData*> card_linked_offers_map =
           GetCardLinkedOffers(client);
       !card_linked_offers_map.empty()) {
     base::ranges::stable_sort(
@@ -950,7 +950,7 @@
           features::kAutofillEnablePaymentsFieldSwapping) &&
       trigger_field.is_autofilled();
 
-  std::map<std::string, AutofillOfferData*> card_linked_offers_map =
+  std::map<std::string, const AutofillOfferData*> card_linked_offers_map =
       GetCardLinkedOffers(client);
   summary.with_offer = !card_linked_offers_map.empty();
   bool suppress_disused_cards =
diff --git a/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_unittest.cc b/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_unittest.cc
index 28ec77bb..8a980d1 100644
--- a/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_unittest.cc
+++ b/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_unittest.cc
@@ -211,7 +211,8 @@
     payments_data().SetSyncServiceForTest(&sync_service_);
     autofill_client_.GetPaymentsAutofillClient()->set_autofill_offer_manager(
         std::make_unique<AutofillOfferManager>(
-            &autofill_client_.GetPersonalDataManager()));
+            &autofill_client_.GetPersonalDataManager()
+                 .payments_data_manager()));
     credit_card_form_event_logger_ =
         std::make_unique<NiceMock<MockCreditCardFormEventLogger>>(
             &autofill_manager_);
diff --git a/components/bookmarks/browser/bookmark_model_unittest.cc b/components/bookmarks/browser/bookmark_model_unittest.cc
index f1fa9a6..c154dee 100644
--- a/components/bookmarks/browser/bookmark_model_unittest.cc
+++ b/components/bookmarks/browser/bookmark_model_unittest.cc
@@ -1483,17 +1483,16 @@
 
   // Make sure folder is in the most recently modified.
   std::vector<const BookmarkNode*> most_recent_folders =
-      GetMostRecentlyModifiedUserFolders(model_.get(), 1);
-  ASSERT_EQ(1U, most_recent_folders.size());
-  ASSERT_EQ(folder, most_recent_folders[0]);
+      GetMostRecentlyModifiedUserFolders(model_.get());
+  ASSERT_FALSE(most_recent_folders.empty());
+  EXPECT_EQ(folder, most_recent_folders[0]);
 
   // Nuke the folder and do another fetch, making sure folder isn't in the
   // returned list.
   model_->Remove(folder->parent()->children().front().get(),
                  bookmarks::metrics::BookmarkEditSource::kOther, FROM_HERE);
-  most_recent_folders = GetMostRecentlyModifiedUserFolders(model_.get(), 1);
-  ASSERT_EQ(1U, most_recent_folders.size());
-  ASSERT_NE(most_recent_folders[0], folder);
+  most_recent_folders = GetMostRecentlyModifiedUserFolders(model_.get());
+  EXPECT_FALSE(base::Contains(most_recent_folders, folder));
 }
 
 // Make sure MostRecentlyAddedEntries stays in sync.
diff --git a/components/bookmarks/browser/bookmark_utils.cc b/components/bookmarks/browser/bookmark_utils.cc
index a2f349e..ae4baa3 100644
--- a/components/bookmarks/browser/bookmark_utils.cc
+++ b/components/bookmarks/browser/bookmark_utils.cc
@@ -222,51 +222,120 @@
 }
 
 std::vector<const BookmarkNode*> GetMostRecentlyModifiedUserFolders(
-    BookmarkModel* model,
-    size_t max_count) {
+    BookmarkModel* model) {
   std::vector<const BookmarkNode*> nodes;
   ui::TreeNodeIterator<const BookmarkNode> iterator(
       model->root_node(), base::BindRepeating(&PruneInvisibleFolders));
 
   while (iterator.has_next()) {
-    const BookmarkNode* parent = iterator.Next();
-    if (model->client()->IsNodeManaged(parent)) {
+    const BookmarkNode* const node = iterator.Next();
+    // Filter out managed nodes and non-folders.
+    if (model->client()->IsNodeManaged(node) || !node->is_folder()) {
       continue;
     }
-    if (parent->is_folder() && parent->date_folder_modified() > Time()) {
-      if (max_count == 0) {
-        nodes.push_back(parent);
-      } else {
-        auto i = std::upper_bound(nodes.begin(), nodes.end(), parent,
-                                  &MoreRecentlyModified);
-        if (nodes.size() < max_count || i != nodes.end()) {
-          nodes.insert(i, parent);
-          while (nodes.size() > max_count)
-            nodes.pop_back();
-        }
-      }
-    }  // else case, the root node, which we don't care about or imported nodes
-       // (which have a time of 0).
+    nodes.push_back(node);
   }
 
-  if (nodes.size() < max_count) {
-    // Add the permanent nodes if there is space. The permanent nodes are the
-    // only children of the root_node.
-    const BookmarkNode* root_node = model->root_node();
+  // TODO(crbug.com/354892429): Filter local permanent nodes if they shouldn't
+  // visible (user has permanent account nodes but no local bookmarks).
 
-    for (const auto& node : root_node->children()) {
-      if (node->IsVisible() && !model->client()->IsNodeManaged(node.get()) &&
-          !base::Contains(nodes, node.get())) {
-        nodes.push_back(node.get());
+  std::ranges::stable_sort(nodes, &MoreRecentlyModified);
 
-        if (nodes.size() == max_count)
-          break;
-      }
-    }
-  }
   return nodes;
 }
 
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
+RecentlyUsedFolders::RecentlyUsedFolders() = default;
+RecentlyUsedFolders::RecentlyUsedFolders(const RecentlyUsedFolders&) = default;
+RecentlyUsedFolders& RecentlyUsedFolders::operator=(
+    const RecentlyUsedFolders&) = default;
+RecentlyUsedFolders::~RecentlyUsedFolders() = default;
+
+RecentlyUsedFolders GetMostRecentlyUsedFoldersForDisplay(
+    BookmarkModel* model,
+    const BookmarkNode* displayed_node) {
+  // `displayed_node` is meant to be a bookmark. Code below is not tested for
+  // folders.
+  CHECK(!displayed_node->is_folder());
+
+  // Max number of most recently used non-permanent-node folders.
+  static constexpr size_t kMaxMRUFolders = 5;
+
+  std::vector<const BookmarkNode*> mru_nodes =
+      bookmarks::GetMostRecentlyModifiedUserFolders(model);
+  const BookmarkNode* const most_recent_node =
+      mru_nodes.empty() ? nullptr : mru_nodes[0];
+
+  // Special case the parent item, it'll either remain first or filtered out as
+  // a permanent node and added back later.
+  std::erase(mru_nodes, displayed_node->parent());  // No-op if not present.
+  mru_nodes.insert(mru_nodes.begin(), displayed_node->parent());
+
+  // Remove permanent nodes, they'll be re-added at the end if used later.
+  std::erase_if(mru_nodes, [](const BookmarkNode* mru_node) {
+    return mru_node->is_permanent_node();
+  });
+
+  // Figure out which permanent nodes to add.
+  const bool account_nodes_exist =
+      model->account_bookmark_bar_node() != nullptr;
+  const std::vector<const BookmarkNode*> account_permanent_nodes(
+      {model->account_bookmark_bar_node(), model->account_other_node(),
+       model->account_mobile_node()});
+  const std::vector<const BookmarkNode*> local_permanent_nodes(
+      {model->bookmark_bar_node(), model->other_node(), model->mobile_node()});
+
+  std::vector<const BookmarkNode*> permanent_nodes_included;
+  for (const BookmarkNode* permanent_node :
+       account_nodes_exist ? account_permanent_nodes : local_permanent_nodes) {
+    if (!permanent_node->IsVisible()) {
+      continue;
+    }
+    permanent_nodes_included.push_back(permanent_node);
+  }
+
+  if (account_nodes_exist) {
+    // Add back the most recent node and the parent node if either of them are
+    // local permanent nodes. Permanent account nodes are preferred.
+    auto append_if_permanent_local_node = [model, &permanent_nodes_included](
+                                              const BookmarkNode* mru_node) {
+      if (mru_node->is_permanent_node() && model->IsLocalOnlyNode(*mru_node)) {
+        permanent_nodes_included.push_back(mru_node);
+      }
+    };
+    if (most_recent_node) {
+      append_if_permanent_local_node(most_recent_node);
+    }
+    if (displayed_node->parent() != most_recent_node) {
+      append_if_permanent_local_node(displayed_node->parent());
+    }
+  }
+
+  // Cap total number of non-permanent nodes to kMaxMRUFolders.
+  mru_nodes.resize(std::min(mru_nodes.size(), kMaxMRUFolders));
+
+  // Add permanent nodes at the end (note that these lists are both sorted and
+  // will remain sorted (permanent last) when split them up below.
+  mru_nodes.insert(mru_nodes.end(), permanent_nodes_included.begin(),
+                   permanent_nodes_included.end());
+
+  // Split between account and local nodes if there are account nodes.
+  RecentlyUsedFolders result;
+  if (account_nodes_exist) {
+    std::vector<const BookmarkNode*> account_nodes;
+    std::vector<const BookmarkNode*> local_nodes;
+    for (const BookmarkNode* mru_node : mru_nodes) {
+      (model->IsLocalOnlyNode(*mru_node) ? result.local_nodes
+                                         : result.account_nodes)
+          .push_back(mru_node);
+    }
+  } else {
+    result.local_nodes = std::move(mru_nodes);
+  }
+  return result;
+}
+#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
+
 void GetMostRecentlyAddedEntries(BookmarkModel* model,
                                  size_t count,
                                  std::vector<const BookmarkNode*>* nodes) {
@@ -484,8 +553,8 @@
   }
 
   std::vector<const BookmarkNode*> nodes =
-      GetMostRecentlyModifiedUserFolders(model, 1);
-  DCHECK(!nodes.empty());  // This list is always padded with default folders.
+      GetMostRecentlyModifiedUserFolders(model);
+  CHECK(!nodes.empty());
   return nodes[0];
 }
 
diff --git a/components/bookmarks/browser/bookmark_utils.h b/components/bookmarks/browser/bookmark_utils.h
index d65dcf4..7cabdcb 100644
--- a/components/bookmarks/browser/bookmark_utils.h
+++ b/components/bookmarks/browser/bookmark_utils.h
@@ -14,6 +14,7 @@
 #include "base/location.h"
 #include "base/memory/raw_ptr.h"
 #include "base/strings/utf_offset_string_conversions.h"
+#include "build/build_config.h"
 #include "components/bookmarks/browser/bookmark_node_data.h"
 #include "components/bookmarks/common/bookmark_metrics.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -79,10 +80,53 @@
     metrics::BookmarkEditSource source,
     bool is_off_the_record);
 
-// Returns a vector containing up to `max_count` of the most recently modified
-// user folders. This never returns an empty vector.
+// Returns a vector containing of the most recently modified user folders. This
+// never returns an empty vector.
 std::vector<const BookmarkNode*> GetMostRecentlyModifiedUserFolders(
-    BookmarkModel* model, size_t max_count);
+    BookmarkModel* model);
+
+// If this should be used on mobile we need to reevaluate if this implementation
+// makes sense. See tests in bookmark_utils_unittest.cc which currently fail
+// outside of desktop. Enable and update those if this is to be used on mobile.
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
+// Fields to use, split by account/local bookmarks. Used by
+// RecentlyUsedFoldersComboModel.
+struct RecentlyUsedFolders final {
+  RecentlyUsedFolders();
+  RecentlyUsedFolders(const RecentlyUsedFolders&);
+  RecentlyUsedFolders& operator=(const RecentlyUsedFolders&);
+  ~RecentlyUsedFolders();
+
+  std::vector<const BookmarkNode*> account_nodes;
+  std::vector<const BookmarkNode*> local_nodes;
+};
+
+// Get recently-used-folders, including permanent nodes for display split up by
+// "account" and "local" nodes. If there are no "account" bookmarks all entries
+// are returned as local nodes even if sync'd, to be displayed as a single list
+// without any headers/labels.
+//
+// In case of a mixed account and local bookmarks in the MRU nodes, this would
+// display:
+//   - Account Bookmark Heading
+//     - Most recently used custom account bookmarks
+//     - Account permanent folders if visible
+//   - Local Bookmark Heading
+//     - Most recently used custom local bookmarks
+//     - Local permanent folder if it is the most recently used folder
+//
+// If MRU nodes are only local or account, this would display:
+//   - Most recently used custom
+//   - Account/Local and syncable permanent nodes
+//
+// Note: The parent of `display_node` is pushed on top of its corresponding list
+// if it is a non-permanent folder or at the end if it is a permanent folder
+// that is not already included.
+RecentlyUsedFolders GetMostRecentlyUsedFoldersForDisplay(
+    BookmarkModel* model,
+    const BookmarkNode* displayed_node);
+
+#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 
 // Returns the most recently added bookmarks. This does not return folders,
 // only nodes of type url.
diff --git a/components/bookmarks/browser/bookmark_utils_unittest.cc b/components/bookmarks/browser/bookmark_utils_unittest.cc
index 7fe121d7..d48870c 100644
--- a/components/bookmarks/browser/bookmark_utils_unittest.cc
+++ b/components/bookmarks/browser/bookmark_utils_unittest.cc
@@ -13,8 +13,8 @@
 
 #include "base/memory/raw_ptr.h"
 #include "base/scoped_observation.h"
-#include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "build/build_config.h"
 #include "components/bookmarks/browser/base_bookmark_model_observer.h"
@@ -24,6 +24,7 @@
 #include "components/bookmarks/browser/bookmark_node_data.h"
 #include "components/bookmarks/common/bookmark_metrics.h"
 #include "components/bookmarks/test/test_bookmark_client.h"
+#include "components/sync/base/features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/clipboard/clipboard.h"
@@ -83,6 +84,10 @@
     ++grouped_changes_ended_count_;
   }
 
+  // Some of these tests exercise account bookmarks.
+  base::test::ScopedFeatureList features_override_{
+      syncer::kSyncEnableBookmarksInTransportMode};
+
   // Clipboard requires a full TaskEnvironment.
   base::test::TaskEnvironment task_environment_;
 
@@ -336,5 +341,154 @@
                                                       /*adjustments=*/nullptr));
 }
 
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
+// TODO(crbug.com/380820764): Break this up into smaller parts that:
+// * Add more than 5 custom folders and make sure that permanent nodes still
+//   show.
+// * Add 6 custom folders, make sure that only 5 show and that the folder past
+//   the cutoff starts showing if it's the parent of the currently showing
+//   bookmark.
+// * Permanent nodes don't show up first even if they are the parents of the
+//   currently displaying bookmarks.
+TEST_F(BookmarkUtilsTest, GetRecentlyUsedFoldersWithOnlyLocalBookmarks) {
+  std::unique_ptr<BookmarkModel> model(TestBookmarkClient::CreateModel());
+
+  const std::u16string title = u"Title";
+  const GURL url("http://google.com");
+  // Note that because `other_bookmark` is a child of a permanent node its use
+  // in GetMostRecentlyUsedFoldersForDisplay will not cause other_node() to be
+  // displayed before more recently modified folders.
+  const BookmarkNode* const other_bookmark =
+      model->AddURL(model->other_node(), 0, title, url);
+
+  const bookmarks::RecentlyUsedFolders mru_bookmarks =
+      bookmarks::GetMostRecentlyUsedFoldersForDisplay(model.get(),
+                                                      other_bookmark);
+
+  EXPECT_TRUE(mru_bookmarks.account_nodes.empty());
+  ASSERT_EQ(mru_bookmarks.local_nodes.size(), 2u);
+  // Permanent nodes display in a fixed order even if a bookmark in other_node()
+  // is currently displayed.
+  EXPECT_EQ(mru_bookmarks.local_nodes[0], model->bookmark_bar_node());
+  EXPECT_EQ(mru_bookmarks.local_nodes[1], model->other_node());
+
+  const BookmarkNode* const folder1 =
+      model->AddFolder(model->other_node(), 0, u"Folder");
+  const BookmarkNode* const folder2 =
+      model->AddFolder(model->other_node(), 0, u"Folder2");
+
+  model->SetDateFolderModified(folder1,
+                               base::Time::FromMillisecondsSinceUnixEpoch(1));
+  model->SetDateFolderModified(folder2,
+                               base::Time::FromMillisecondsSinceUnixEpoch(2));
+
+  // folder2 is most recent
+  EXPECT_EQ(folder2, bookmarks::GetMostRecentlyUsedFoldersForDisplay(
+                         model.get(), other_bookmark)
+                         .local_nodes[0]);
+
+  model->SetDateFolderModified(folder1,
+                               base::Time::FromMillisecondsSinceUnixEpoch(3));
+  // folder1 is most recent
+  EXPECT_EQ(folder1, bookmarks::GetMostRecentlyUsedFoldersForDisplay(
+                         model.get(), other_bookmark)
+                         .local_nodes[0]);
+
+  const BookmarkNode* const bookmark = model->AddURL(folder2, 0, title, url);
+
+  // folder2 as a parent to `bookmark` displays first even though not most
+  // recent.
+  EXPECT_EQ(folder2, bookmarks::GetMostRecentlyUsedFoldersForDisplay(
+                         model.get(), bookmark)
+                         .local_nodes[0]);
+}
+
+// TODO(crbug.com/380820764): Break this up into smaller parts and make sure we
+// have full coverage for:
+// * Add more than 5 custom folders and make sure that account permanent nodes
+//   still show.
+// * Add 6 custom folders, make sure that the oldest one is cut off (regardless
+//   of local or account). Make sure that the oldest one starts showing if it's
+//   the parent of a currently-showing bookmarl (and the second-oldest one is
+//   gone instead).
+// * Make sure that local permanent nodes show up if most recently used and if
+//   the displayed bookmark is a child of that local node it's only added once
+//   (no duplicates).
+// * Make sure local permanent nodes show up even if the displayed bookmark is
+//   another permanent node (both local permanent nodes can show).
+// * Make sure that local permanent nodes show up last among local nodes even if
+//   they are the most recent ones or parents of the current currently-displayed
+//   bookmark.
+// * Make sure local nodes are empty if there's >5 more recently used folders
+//   under account bookmarks.
+TEST_F(BookmarkUtilsTest, GetRecentlyUsedFoldersWithAccountBookmarks) {
+  std::unique_ptr<BookmarkModel> model(TestBookmarkClient::CreateModel());
+  model->CreateAccountPermanentFolders();
+
+  const std::u16string title = u"Title";
+  const GURL url("http://google.com");
+  // Note that because `bookmark_in_account_other_node` is a child of a
+  // permanent node its use in GetMostRecentlyUsedFoldersForDisplay will not
+  // cause account_other_node() to be displayed before more recently modified
+  // folders.
+  const BookmarkNode* const bookmark_in_account_other_node =
+      model->AddURL(model->account_other_node(), 0, title, url);
+
+  bookmarks::RecentlyUsedFolders mru_bookmarks =
+      bookmarks::GetMostRecentlyUsedFoldersForDisplay(
+          model.get(), bookmark_in_account_other_node);
+
+  // Permanent nodes are only added to account nodes by default.
+  ASSERT_EQ(mru_bookmarks.account_nodes.size(), 2u);
+  // No local nodes display by default.
+  EXPECT_TRUE(mru_bookmarks.local_nodes.empty());
+
+  // Permanent nodes display in a fixed order even if a bookmark in
+  // account_other_node() is currently displayed.
+  EXPECT_EQ(mru_bookmarks.account_nodes[0], model->account_bookmark_bar_node());
+  EXPECT_EQ(mru_bookmarks.account_nodes[1], model->account_other_node());
+
+  const BookmarkNode* const local_other_bookmark =
+      model->AddURL(model->other_node(), 0, title, url);
+
+  // Make sure local permanent nodes are not the most recently modified ones.
+  model->SetDateFolderModified(model->other_node(),
+                               base::Time::FromMillisecondsSinceUnixEpoch(1));
+  model->SetDateFolderModified(model->account_other_node(),
+                               base::Time::FromMillisecondsSinceUnixEpoch(2));
+
+  mru_bookmarks = bookmarks::GetMostRecentlyUsedFoldersForDisplay(
+      model.get(), local_other_bookmark);
+
+  // Local permanent node included when its children are being displayed.
+  ASSERT_EQ(mru_bookmarks.local_nodes.size(), 1u);
+  EXPECT_EQ(model->other_node(), mru_bookmarks.local_nodes[0]);
+
+  // But not otherwise.
+  EXPECT_TRUE(bookmarks::GetMostRecentlyUsedFoldersForDisplay(
+                  model.get(), bookmark_in_account_other_node)
+                  .local_nodes.empty());
+
+  // The most recent folders under account and local are split up as the topmost
+  // entries.
+  const BookmarkNode* const account_folder =
+      model->AddFolder(model->account_other_node(), 0, u"Folder");
+  const BookmarkNode* const local_folder =
+      model->AddFolder(model->other_node(), 0, u"Folder2");
+
+  model->SetDateFolderModified(account_folder,
+                               base::Time::FromMillisecondsSinceUnixEpoch(20));
+  // Older than `account_folder` but not filtered out (not permanent node).
+  model->SetDateFolderModified(local_folder,
+                               base::Time::FromMillisecondsSinceUnixEpoch(10));
+
+  mru_bookmarks = bookmarks::GetMostRecentlyUsedFoldersForDisplay(
+      model.get(), bookmark_in_account_other_node);
+  EXPECT_EQ(account_folder, mru_bookmarks.account_nodes[0]);
+  EXPECT_EQ(local_folder, mru_bookmarks.local_nodes[0]);
+}
+
+#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
+
 }  // namespace
 }  // namespace bookmarks
diff --git a/components/collaboration/internal/messaging/messaging_backend_service_impl.cc b/components/collaboration/internal/messaging/messaging_backend_service_impl.cc
index ddded50..2fa2a4e 100644
--- a/components/collaboration/internal/messaging/messaging_backend_service_impl.cc
+++ b/components/collaboration/internal/messaging/messaging_backend_service_impl.cc
@@ -205,6 +205,85 @@
   return tab_metadata;
 }
 
+TabMessageMetadata CreateTabMessageMetadataFromMessageOrTab(
+    const collaboration_pb::Message& message,
+    std::optional<tab_groups::SavedTabGroupTab> tab) {
+  if (tab) {
+    return CreateTabMessageMetadata(*tab);
+  }
+
+  // Tab no longer available, so fill in what we can.
+  TabMessageMetadata tab_metadata = TabMessageMetadata();
+  tab_metadata.last_known_url = message.tab_data().last_url();
+  tab_metadata.sync_tab_id =
+      base::Uuid::ParseLowercase(message.tab_data().sync_tab_id());
+  return tab_metadata;
+}
+
+std::optional<tab_groups::SavedTabGroupTab> GetTabFromGroup(
+    const collaboration_pb::Message& message,
+    std::optional<tab_groups::SavedTabGroup> tab_group) {
+  if (!tab_group) {
+    return std::nullopt;
+  }
+
+  const tab_groups::SavedTabGroupTab* tab = tab_group->GetTab(
+      base::Uuid::ParseCaseInsensitive(message.tab_data().sync_tab_id()));
+  if (tab) {
+    return std::make_optional(*tab);
+  }
+  return std::nullopt;
+}
+
+DirtyType GetDirtyTypeFromPersistentNotificationTypeForQuery(
+    std::optional<PersistentNotificationType> type) {
+  if (!type) {
+    // Ask for all dirty messages.
+    return DirtyType::kAll;
+  }
+  if (*type == PersistentNotificationType::DIRTY_TAB) {
+    return DirtyType::kDot;
+  } else if (*type == PersistentNotificationType::CHIP) {
+    return DirtyType::kChip;
+  } else {
+    // Ask for all dirty messages.
+    return DirtyType::kAll;
+  }
+}
+
+std::vector<PersistentMessage> RemoveDuplicateDirtyTabGroupMessages(
+    const std::vector<PersistentMessage>& messages) {
+  std::unordered_set<data_sharing::GroupId> dirty_tab_groups;
+  std::vector<PersistentMessage> result;
+  for (const auto& message : messages) {
+    if (message.type == PersistentNotificationType::DIRTY_TAB_GROUP) {
+      // We only want one DIRTY_TAB_GROUP per collaboration.
+      if (dirty_tab_groups.find(message.attribution.collaboration_id) ==
+          dirty_tab_groups.end()) {
+        // This is the first one, so we add it.
+        dirty_tab_groups.emplace(message.attribution.collaboration_id);
+        result.emplace_back(message);
+      }
+    } else {
+      // If this is not a dirty tab group, add it to the result
+      result.emplace_back(message);
+    }
+  }
+  return result;
+}
+
+std::vector<PersistentMessage> CreatePersistentMessagesForTypes(
+    PersistentMessage base_message,
+    const std::vector<PersistentNotificationType>& types) {
+  std::vector<PersistentMessage> messages;
+  for (const PersistentNotificationType& type : types) {
+    PersistentMessage message = base_message;
+    message.type = type;
+    messages.emplace_back(message);
+  }
+  return messages;
+}
+
 }  // namespace
 
 MessagingBackendServiceImpl::MessagingBackendServiceImpl(
@@ -233,8 +312,15 @@
 void MessagingBackendServiceImpl::AddPersistentMessageObserver(
     PersistentMessageObserver* observer) {
   persistent_message_observers_.AddObserver(observer);
-  // TODO(345856704): Implement this and inform the observer if we have already
-  // initialized.
+  if (IsInitialized()) {
+    // We invoke the observer here in a re-entrant manner (documented in the
+    // public API), because at any time after adding the observer, new messages
+    // can come in, and they could arrive before the posted task with the
+    // callback executes, which means they could get calls to Display/Hide of
+    // PersistentMessages before they get the call to
+    // OnMessagingBackendServiceInitialized().
+    observer->OnMessagingBackendServiceInitialized();
+  }
 }
 
 void MessagingBackendServiceImpl::RemovePersistentMessageObserver(
@@ -249,24 +335,67 @@
 std::vector<PersistentMessage> MessagingBackendServiceImpl::GetMessagesForTab(
     tab_groups::EitherTabID tab_id,
     std::optional<PersistentNotificationType> type) {
-  // TODO(345856704): Implement this and DCHECK(IsInitialized()) and update
-  // interface description.
-  return {};
+  std::optional<tab_groups::SavedTabGroupTab> tab = GetTabFromTabId(tab_id);
+  if (!tab) {
+    // Unable to find tab.
+    return {};
+  }
+
+  std::optional<tab_groups::SavedTabGroup> tab_group =
+      tab_group_sync_service_->GetGroup(tab->saved_group_guid());
+  if (!tab_group) {
+    // Unable to find group.
+    return {};
+  }
+
+  std::optional<data_sharing::GroupId> collaboration_group_id =
+      GroupIdForTabGroup(*tab_group);
+  if (!collaboration_group_id) {
+    // Unable to find collaboration ID.
+    return {};
+  }
+
+  DirtyType dirty_type =
+      GetDirtyTypeFromPersistentNotificationTypeForQuery(type);
+
+  std::optional<collaboration_pb::Message> message =
+      store_->GetDirtyMessageForTab(*collaboration_group_id,
+                                    tab->saved_tab_guid(), dirty_type);
+  if (!message) {
+    return {};
+  }
+  return ConvertMessageToPersistentMessages(
+      *message, dirty_type, type, /*allow_dirty_tab_group_message=*/false);
 }
 
 std::vector<PersistentMessage> MessagingBackendServiceImpl::GetMessagesForGroup(
     tab_groups::EitherGroupID group_id,
     std::optional<PersistentNotificationType> type) {
-  // TODO(345856704): Implement this and DCHECK(IsInitialized()) and update
-  // interface description.
-  return {};
+  std::optional<data_sharing::GroupId> collaboration_group_id =
+      GetCollaborationGroupId(group_id);
+  if (!collaboration_group_id) {
+    // Unable to find collaboration.
+    return {};
+  }
+
+  DirtyType dirty_type =
+      GetDirtyTypeFromPersistentNotificationTypeForQuery(type);
+
+  std::vector<collaboration_pb::Message> messages =
+      store_->GetDirtyMessagesForGroup(*collaboration_group_id, dirty_type);
+  return RemoveDuplicateDirtyTabGroupMessages(
+      ConvertMessagesToPersistentMessages(messages, dirty_type, type));
 }
 
 std::vector<PersistentMessage> MessagingBackendServiceImpl::GetMessages(
     std::optional<PersistentNotificationType> type) {
-  // TODO(345856704): Implement this and DCHECK(IsInitialized()) and update
-  // interface description.
-  return {};
+  DirtyType dirty_type =
+      GetDirtyTypeFromPersistentNotificationTypeForQuery(type);
+
+  std::vector<collaboration_pb::Message> messages =
+      store_->GetDirtyMessages(dirty_type);
+  return RemoveDuplicateDirtyTabGroupMessages(
+      ConvertMessagesToPersistentMessages(messages, dirty_type, type));
 }
 
 std::vector<ActivityLogItem> MessagingBackendServiceImpl::GetActivityLog(
@@ -389,6 +518,16 @@
       CreateTabMessage(*collaboration_group_id, added_tab,
                        collaboration_pb::TAB_ADDED, DirtyType::kDotAndChip);
   store_->AddMessage(message);
+
+  PersistentMessage persistent_message =
+      CreatePersistentMessage(message, std::nullopt, added_tab, std::nullopt);
+
+  NotifyDisplayPersistentMessagesForTypes(
+      persistent_message, {PersistentNotificationType::CHIP,
+                           PersistentNotificationType::DIRTY_TAB});
+
+  DisplayOrHideTabGroupDirtyDotForTabGroup(*collaboration_group_id,
+                                           added_tab.saved_group_guid());
 }
 
 void MessagingBackendServiceImpl::OnTabRemoved(
@@ -404,6 +543,21 @@
       CreateTabMessage(*collaboration_group_id, removed_tab,
                        collaboration_pb::TAB_REMOVED, DirtyType::kNone);
   store_->AddMessage(message);
+
+  // Tab no longer available, so should not contribute to any dirty tab groups.
+  store_->ClearDirtyMessageForTab(*collaboration_group_id,
+                                  removed_tab.saved_tab_guid(),
+                                  DirtyType::kDotAndChip);
+
+  PersistentMessage persistent_message =
+      CreatePersistentMessage(message, std::nullopt, removed_tab, std::nullopt);
+
+  NotifyHidePersistentMessagesForTypes(persistent_message,
+                                       {PersistentNotificationType::CHIP,
+                                        PersistentNotificationType::DIRTY_TAB});
+
+  DisplayOrHideTabGroupDirtyDotForTabGroup(*collaboration_group_id,
+                                           removed_tab.saved_group_guid());
 }
 
 void MessagingBackendServiceImpl::OnTabUpdated(
@@ -419,10 +573,62 @@
       CreateTabMessage(*collaboration_group_id, updated_tab,
                        collaboration_pb::TAB_UPDATED, DirtyType::kDotAndChip);
   store_->AddMessage(message);
+
+  PersistentMessage persistent_message =
+      CreatePersistentMessage(message, std::nullopt, updated_tab, std::nullopt);
+
+  NotifyDisplayPersistentMessagesForTypes(
+      persistent_message, {PersistentNotificationType::CHIP,
+                           PersistentNotificationType::DIRTY_TAB});
+
+  DisplayOrHideTabGroupDirtyDotForTabGroup(*collaboration_group_id,
+                                           updated_tab.saved_group_guid());
 }
 
 void MessagingBackendServiceImpl::OnTabSelected(
-    std::optional<tab_groups::SavedTabGroupTab> selected_tab) {}
+    std::optional<tab_groups::SavedTabGroupTab> selected_tab) {
+  last_selected_tab_ = selected_tab;
+  if (!selected_tab) {
+    // A tab outside shared tab groups was selected.
+    // TODO(crbug.com/378422466): Maybe clear chip on desktop here.
+    return;
+  }
+
+  std::optional<data_sharing::GroupId> collaboration_group_id =
+      GetCollaborationGroupIdForTab(selected_tab.value());
+
+  if (!collaboration_group_id) {
+    // Unable to find the collaboration, so nothing to clear.
+    return;
+  }
+
+  // TODO(crbug.com/378422466): Do not clear chip on desktop, until the user
+  // goes away from the tab.
+  store_->ClearDirtyMessageForTab(*collaboration_group_id,
+                                  selected_tab->saved_tab_guid(),
+                                  DirtyType::kDotAndChip);
+
+  std::optional<tab_groups::SavedTabGroup> tab_group =
+      tab_group_sync_service_->GetGroup(selected_tab->saved_group_guid());
+
+  // Specialized handling of creating a PersistentMessage, since we do not have
+  // a stored collaboration_pb::Message available.
+  PersistentMessage persistent_message;
+  persistent_message.collaboration_event = CollaborationEvent::UNDEFINED;
+  persistent_message.attribution = MessageAttribution();
+  persistent_message.attribution.collaboration_id = *collaboration_group_id;
+  persistent_message.attribution.tab_group_metadata =
+      CreateTabGroupMessageMetadata(*tab_group);
+  persistent_message.attribution.tab_metadata =
+      CreateTabMessageMetadata(*selected_tab);
+
+  NotifyHidePersistentMessagesForTypes(persistent_message,
+                                       {PersistentNotificationType::CHIP,
+                                        PersistentNotificationType::DIRTY_TAB});
+
+  DisplayOrHideTabGroupDirtyDotForTabGroup(*collaboration_group_id,
+                                           selected_tab->saved_group_guid());
+}
 
 void MessagingBackendServiceImpl::OnGroupAdded(
     const data_sharing::GroupId& group_id,
@@ -553,7 +759,8 @@
   data_sharing::GroupId collaboration_group_id(message.collaboration_id());
 
   std::optional<GaiaId> gaia_id = GetGaiaIdFromMessage(message);
-  std::optional<data_sharing::GroupMember> group_member;
+  std::optional<data_sharing::GroupMember> group_member =
+      GetGroupMemberFromGaiaId(collaboration_group_id, gaia_id);
   if (gaia_id) {
     std::optional<std::string> user_name_for_display =
         GetDisplayNameForUserInGroup(collaboration_group_id, *gaia_id,
@@ -561,15 +768,10 @@
     if (user_name_for_display) {
       item.user_display_name = *user_name_for_display;
     }
-    std::optional<data_sharing::GroupMemberPartialData> group_member_data =
-        data_sharing_service_->GetPossiblyRemovedGroupMember(
-            collaboration_group_id, *gaia_id);
-    if (group_member_data) {
-      group_member = group_member_data->ToGroupMember();
-    }
   }
 
-  // TODO(nyquist): Compare GaiaId with current user in this profile.
+  // TODO(crbug.com/380517719): Compare GaiaId with current user in this
+  // profile.
   item.user_is_self = false;
 
   // By default, we use an empty description. This is special cased below.
@@ -589,28 +791,15 @@
       item.show_favicon = true;
 
       std::optional<tab_groups::SavedTabGroup> tab_group =
-          tab_group_sync_service_->GetGroup(base::Uuid::ParseCaseInsensitive(
-              message.tab_data().sync_tab_group_id()));
-      if (!tab_group) {
-        break;
-      }
+          GetTabGroupFromMessage(message);
       item.activity_metadata.tab_group_metadata =
-          CreateTabGroupMessageMetadata(*tab_group);
-      tab_groups::SavedTabGroupTab* tab = tab_group->GetTab(
-          base::Uuid::ParseCaseInsensitive(message.tab_data().sync_tab_id()));
-      GURL url;
-      if (tab) {
-        item.activity_metadata.tab_metadata = CreateTabMessageMetadata(*tab);
-        url = tab->url();
-      } else {
-        // Tab no longer available, so fill in what we can.
-        item.activity_metadata.tab_metadata = TabMessageMetadata();
-        item.activity_metadata.tab_metadata->last_known_url =
-            message.tab_data().last_url();
-        item.activity_metadata.tab_metadata->sync_tab_id =
-            base::Uuid::ParseLowercase(message.tab_data().sync_tab_id());
-        url = GURL(message.tab_data().last_url());
-      }
+          CreateTabGroupMessageMetadataFromMessageOrTabGroup(message,
+                                                             tab_group);
+      item.activity_metadata.tab_metadata =
+          CreateTabMessageMetadataFromMessageOrTab(
+              message, GetTabFromGroup(message, tab_group));
+      // We are guaranteed to have a value for `last_known_url`.
+      GURL url = GURL(*item.activity_metadata.tab_metadata->last_known_url);
       item.activity_metadata.triggering_user = group_member;
 
       item.description =
@@ -621,26 +810,9 @@
     }
     case MessageCategory::kTabGroup: {
       item.activity_metadata.triggering_user = group_member;
-      std::optional<tab_groups::SavedTabGroup> tab_group;
-      if (!message.tab_group_data().sync_tab_group_id().empty()) {
-        tab_group =
-            tab_group_sync_service_->GetGroup(base::Uuid::ParseLowercase(
-                message.tab_group_data().sync_tab_group_id()));
-      }
-      if (tab_group) {
-        item.activity_metadata.tab_group_metadata =
-            CreateTabGroupMessageMetadata(*tab_group);
-      } else {
-        item.activity_metadata.tab_group_metadata = TabGroupMessageMetadata();
-        std::optional<std::u16string> previous_title =
-            tab_group_sync_service_
-                ->GetTitleForPreviouslyExistingSharedTabGroup(
-                    ToCollaborationId(collaboration_group_id));
-        if (previous_title) {
-          item.activity_metadata.tab_group_metadata->last_known_title =
-              base::UTF16ToUTF8(*previous_title);
-        }
-      }
+      item.activity_metadata.tab_group_metadata =
+          CreateTabGroupMessageMetadataFromMessageOrTabGroup(message,
+                                                             std::nullopt);
 
       // Only tab group name changes have specialized description.
       if (message.event_type() == collaboration_pb::TAB_GROUP_NAME_UPDATED) {
@@ -676,4 +848,277 @@
   return GroupIdForTabGroup(*tab_group);
 }
 
+TabGroupMessageMetadata
+MessagingBackendServiceImpl::CreateTabGroupMessageMetadataFromCollaborationId(
+    std::optional<tab_groups::SavedTabGroup> tab_group,
+    std::optional<data_sharing::GroupId> collaboration_group_id) {
+  if (tab_group) {
+    return CreateTabGroupMessageMetadata(*tab_group);
+  }
+
+  TabGroupMessageMetadata tab_group_metadata = TabGroupMessageMetadata();
+  if (!collaboration_group_id) {
+    return tab_group_metadata;
+  }
+  std::optional<std::u16string> previous_title =
+      tab_group_sync_service_->GetTitleForPreviouslyExistingSharedTabGroup(
+          ToCollaborationId(data_sharing::GroupId(*collaboration_group_id)));
+  if (previous_title) {
+    tab_group_metadata.last_known_title = base::UTF16ToUTF8(*previous_title);
+  }
+  return tab_group_metadata;
+}
+
+TabGroupMessageMetadata
+MessagingBackendServiceImpl::CreateTabGroupMessageMetadataFromMessageOrTabGroup(
+    const collaboration_pb::Message& message,
+    const std::optional<tab_groups::SavedTabGroup>& tab_group) {
+  if (tab_group) {
+    return CreateTabGroupMessageMetadata(*tab_group);
+  }
+
+  return CreateTabGroupMessageMetadataFromCollaborationId(
+      GetTabGroupFromMessage(message),
+      data_sharing::GroupId(message.collaboration_id()));
+}
+
+std::optional<tab_groups::SavedTabGroup>
+MessagingBackendServiceImpl::GetTabGroupFromMessage(
+    const collaboration_pb::Message& message) {
+  std::string sync_tab_group_id = message.tab_group_data().sync_tab_group_id();
+  if (sync_tab_group_id.empty()) {
+    // Try from tab data next.
+    sync_tab_group_id = message.tab_data().sync_tab_group_id();
+  }
+
+  if (sync_tab_group_id.empty()) {
+    return std::nullopt;
+  }
+
+  return tab_group_sync_service_->GetGroup(
+      base::Uuid::ParseLowercase(sync_tab_group_id));
+}
+
+std::optional<data_sharing::GroupMember>
+MessagingBackendServiceImpl::GetGroupMemberFromGaiaId(
+    const data_sharing::GroupId& collaboration_group_id,
+    std::optional<GaiaId> gaia_id) {
+  if (!gaia_id) {
+    return std::nullopt;
+  }
+
+  std::optional<data_sharing::GroupMemberPartialData> group_member_data =
+      data_sharing_service_->GetPossiblyRemovedGroupMember(
+          collaboration_group_id, *gaia_id);
+  if (group_member_data) {
+    return group_member_data->ToGroupMember();
+  }
+  return std::nullopt;
+}
+
+std::optional<data_sharing::GroupId>
+MessagingBackendServiceImpl::GetCollaborationGroupId(
+    tab_groups::EitherGroupID group_id) {
+  std::optional<tab_groups::SavedTabGroup> tab_group =
+      tab_group_sync_service_->GetGroup(group_id);
+  if (!tab_group) {
+    return std::nullopt;
+  }
+  return GroupIdForTabGroup(*tab_group);
+}
+
+std::optional<tab_groups::SavedTabGroupTab>
+MessagingBackendServiceImpl::GetTabFromTabId(tab_groups::EitherTabID tab_id) {
+  if (std::holds_alternative<base::Uuid>(tab_id)) {
+    base::Uuid sync_tab_id = std::get<base::Uuid>(tab_id);
+    for (const auto& group : tab_group_sync_service_->GetAllGroups()) {
+      if (group.ContainsTab(sync_tab_id)) {
+        return std::make_optional(*group.GetTab(sync_tab_id));
+      }
+    }
+  }
+  if (std::holds_alternative<tab_groups::LocalTabID>(tab_id)) {
+    tab_groups::LocalTabID local_tab_id =
+        std::get<tab_groups::LocalTabID>(tab_id);
+    for (const auto& group : tab_group_sync_service_->GetAllGroups()) {
+      if (group.ContainsTab(local_tab_id)) {
+        return std::make_optional(*group.GetTab(local_tab_id));
+      }
+    }
+  }
+  return std::nullopt;
+}
+
+std::vector<PersistentMessage>
+MessagingBackendServiceImpl::ConvertMessagesToPersistentMessages(
+    const std::vector<collaboration_pb::Message>& messages,
+    DirtyType lookup_dirty_type,
+    const std::optional<PersistentNotificationType>& type) {
+  std::vector<PersistentMessage> result;
+  for (const auto& message : messages) {
+    // Each DB message might result in multiple individual PersistentMessages.
+    std::vector<PersistentMessage> converted_messages =
+        ConvertMessageToPersistentMessages(
+            message, lookup_dirty_type, type,
+            /*allow_dirty_tab_group_message=*/true);
+    result.insert(result.end(), converted_messages.begin(),
+                  converted_messages.end());
+  }
+  return result;
+}
+
+std::vector<PersistentMessage>
+MessagingBackendServiceImpl::ConvertMessageToPersistentMessages(
+    const collaboration_pb::Message& message,
+    DirtyType lookup_dirty_type,
+    const std::optional<PersistentNotificationType>& type,
+    bool allow_dirty_tab_group_message) {
+  std::vector<PersistentMessage> persistent_messages;
+  if (GetMessageCategory(message) != MessageCategory::kTab) {
+    return persistent_messages;
+  }
+
+  // Helper local variables to increase readability of code below.
+  bool has_dirty_chip = message.dirty() & static_cast<int>(DirtyType::kChip);
+  bool looking_for_dirty_chip = lookup_dirty_type == DirtyType::kAll ||
+                                lookup_dirty_type == DirtyType::kChip;
+  bool has_dirty_dot = message.dirty() & static_cast<int>(DirtyType::kDot);
+  bool looking_for_dirty_dot = lookup_dirty_type == DirtyType::kAll ||
+                               lookup_dirty_type == DirtyType::kDot;
+  bool add_dirty_tab_messages =
+      !type || *type == PersistentNotificationType::DIRTY_TAB;
+  bool add_dirty_tab_group_messages =
+      allow_dirty_tab_group_message &&
+      (!type || *type == PersistentNotificationType::DIRTY_TAB_GROUP);
+  bool has_dirty_tab_messages_in_group =
+      !store_
+           ->GetDirtyMessagesForGroup(
+               data_sharing::GroupId(message.collaboration_id()),
+               DirtyType::kDot)
+           .empty();
+
+  std::optional<tab_groups::SavedTabGroup> tab_group =
+      GetTabGroupFromMessage(message);
+
+  if (has_dirty_chip && looking_for_dirty_chip) {
+    persistent_messages.push_back(CreatePersistentMessage(
+        message, tab_group, std::nullopt, PersistentNotificationType::CHIP));
+  }
+
+  if (has_dirty_dot && looking_for_dirty_dot) {
+    if (add_dirty_tab_messages) {
+      persistent_messages.push_back(
+          CreatePersistentMessage(message, tab_group, std::nullopt,
+                                  PersistentNotificationType::DIRTY_TAB));
+    }
+
+    if (add_dirty_tab_group_messages && has_dirty_tab_messages_in_group) {
+      PersistentMessage persistent_message =
+          CreatePersistentMessage(message, tab_group, std::nullopt,
+                                  PersistentNotificationType::DIRTY_TAB_GROUP);
+      // Override collaboration event and tab metadata since this is about
+      // a group.
+      persistent_message.collaboration_event = CollaborationEvent::UNDEFINED;
+      persistent_message.attribution.tab_metadata = TabMessageMetadata();
+      persistent_messages.push_back(persistent_message);
+    }
+  }
+  return persistent_messages;
+}
+
+PersistentMessage MessagingBackendServiceImpl::CreatePersistentMessage(
+    const collaboration_pb::Message& message,
+    const std::optional<tab_groups::SavedTabGroup>& tab_group,
+    const std::optional<tab_groups::SavedTabGroupTab>& tab,
+    const std::optional<PersistentNotificationType>& type) {
+  PersistentMessage persistent_message;
+  persistent_message.collaboration_event =
+      ToCollaborationEvent(message.event_type());
+  persistent_message.attribution = MessageAttribution();
+  persistent_message.attribution.collaboration_id =
+      data_sharing::GroupId(message.collaboration_id());
+  std::optional<tab_groups::SavedTabGroup> stack_tab_group = tab_group;
+  if (!tab_group && tab) {
+    stack_tab_group =
+        tab_group_sync_service_->GetGroup(tab->saved_group_guid());
+  }
+  persistent_message.attribution.tab_group_metadata =
+      CreateTabGroupMessageMetadataFromMessageOrTabGroup(message, tab_group);
+  persistent_message.attribution.tab_metadata =
+      CreateTabMessageMetadataFromMessageOrTab(
+          message, tab.has_value() ? tab : GetTabFromGroup(message, tab_group));
+  persistent_message.attribution.triggering_user = GetGroupMemberFromGaiaId(
+      data_sharing::GroupId(message.collaboration_id()),
+      GaiaId(message.triggering_user_gaia_id()));
+  if (type) {
+    persistent_message.type = *type;
+  }
+  return persistent_message;
+}
+
+void MessagingBackendServiceImpl::NotifyDisplayPersistentMessagesForTypes(
+    const PersistentMessage& base_message,
+    const std::vector<PersistentNotificationType>& types) {
+  for (const PersistentMessage& message :
+       CreatePersistentMessagesForTypes(base_message, types)) {
+    persistent_message_observers_.Notify(
+        &PersistentMessageObserver::DisplayPersistentMessage, message);
+  }
+}
+
+void MessagingBackendServiceImpl::NotifyHidePersistentMessagesForTypes(
+    const PersistentMessage& base_message,
+    const std::vector<PersistentNotificationType>& types) {
+  for (const PersistentMessage& message :
+       CreatePersistentMessagesForTypes(base_message, types)) {
+    persistent_message_observers_.Notify(
+        &PersistentMessageObserver::HidePersistentMessage, message);
+  }
+}
+
+void MessagingBackendServiceImpl::DisplayOrHideTabGroupDirtyDotForTabGroup(
+    const data_sharing::GroupId& collaboration_group_id,
+    base::Uuid shared_tab_group_id) {
+  bool hasDirtyDotMessagesForGroup =
+      !store_->GetDirtyMessagesForGroup(collaboration_group_id, DirtyType::kDot)
+           .empty();
+
+  std::optional<tab_groups::SavedTabGroup> tab_group =
+      tab_group_sync_service_->GetGroup(shared_tab_group_id);
+  PersistentMessage persistent_message;
+
+  persistent_message.attribution = MessageAttribution();
+  persistent_message.attribution.collaboration_id = collaboration_group_id;
+
+  if (tab_group) {
+    persistent_message.attribution.tab_group_metadata =
+        CreateTabGroupMessageMetadata(*tab_group);
+  } else {
+    // Unable to find the group, so we fill in what we known.
+    persistent_message.attribution.tab_group_metadata =
+        TabGroupMessageMetadata();
+    persistent_message.attribution.tab_group_metadata->sync_tab_group_id =
+        shared_tab_group_id;
+    std::optional<std::u16string> previous_title =
+        tab_group_sync_service_->GetTitleForPreviouslyExistingSharedTabGroup(
+            ToCollaborationId(collaboration_group_id));
+    if (previous_title) {
+      persistent_message.attribution.tab_group_metadata->last_known_title =
+          base::UTF16ToUTF8(*previous_title);
+    }
+  }
+
+  persistent_message.collaboration_event = CollaborationEvent::UNDEFINED;
+  // We do not fill in triggering user or affeted user, because any action
+  // related to dirty tabs could have been relevant here.
+
+  if (hasDirtyDotMessagesForGroup) {
+    NotifyDisplayPersistentMessagesForTypes(
+        persistent_message, {PersistentNotificationType::DIRTY_TAB_GROUP});
+  } else {
+    NotifyHidePersistentMessagesForTypes(
+        persistent_message, {PersistentNotificationType::DIRTY_TAB_GROUP});
+  }
+}
+
 }  // namespace collaboration::messaging
diff --git a/components/collaboration/internal/messaging/messaging_backend_service_impl.h b/components/collaboration/internal/messaging/messaging_backend_service_impl.h
index 33ed750..276326e 100644
--- a/components/collaboration/internal/messaging/messaging_backend_service_impl.h
+++ b/components/collaboration/internal/messaging/messaging_backend_service_impl.h
@@ -12,6 +12,7 @@
 #include "base/observer_list.h"
 #include "base/scoped_observation.h"
 #include "components/collaboration/internal/messaging/data_sharing_change_notifier.h"
+#include "components/collaboration/internal/messaging/storage/messaging_backend_store.h"
 #include "components/collaboration/internal/messaging/tab_group_change_notifier.h"
 #include "components/collaboration/public/messaging/message.h"
 #include "components/collaboration/public/messaging/messaging_backend_service.h"
@@ -116,6 +117,72 @@
   std::optional<data_sharing::GroupId> GetCollaborationGroupIdForTab(
       const tab_groups::SavedTabGroupTab& tab);
 
+  // Uses the provided data to create TabGroupMessageMetadata.
+  TabGroupMessageMetadata CreateTabGroupMessageMetadataFromCollaborationId(
+      std::optional<tab_groups::SavedTabGroup> tab_group,
+      std::optional<data_sharing::GroupId> collaboration_group_id);
+
+  // Creates a TabGroupMessageMetadata based on the sources given as input.
+  TabGroupMessageMetadata CreateTabGroupMessageMetadataFromMessageOrTabGroup(
+      const collaboration_pb::Message& message,
+      const std::optional<tab_groups::SavedTabGroup>& tab_group);
+
+  // Tries to retrieve the correct tab group based on data in the Message.
+  std::optional<tab_groups::SavedTabGroup> GetTabGroupFromMessage(
+      const collaboration_pb::Message& message);
+
+  // Uses the available data to look up a GroupMember.
+  std::optional<data_sharing::GroupMember> GetGroupMemberFromGaiaId(
+      const data_sharing::GroupId& collaboration_group_id,
+      std::optional<GaiaId> gaia_id);
+
+  // Retrieves the relevant tab group from the TabGroupSyncService and looks up
+  // its collaboration group id.
+  std::optional<data_sharing::GroupId> GetCollaborationGroupId(
+      tab_groups::EitherGroupID group_id);
+
+  // Looks up the tab from tab group sync service.
+  std::optional<tab_groups::SavedTabGroupTab> GetTabFromTabId(
+      tab_groups::EitherTabID tab_id);
+
+  // Convert all the provided stored Messages to PersistentMessages.
+  std::vector<PersistentMessage> ConvertMessagesToPersistentMessages(
+      const std::vector<collaboration_pb::Message>& messages,
+      DirtyType lookup_dirty_type,
+      const std::optional<PersistentNotificationType>& type);
+
+  // Convert a single stored Message to PersistentMessages. Each stored message
+  // may result in multiple PersistentMessages, e.g. both CHIP and DIRTY_TAB.
+  std::vector<PersistentMessage> ConvertMessageToPersistentMessages(
+      const collaboration_pb::Message& message,
+      DirtyType lookup_dirty_type,
+      const std::optional<PersistentNotificationType>& type,
+      bool allow_dirty_tab_group_message);
+
+  // Creates a PersistentMessage based on the provided information.
+  PersistentMessage CreatePersistentMessage(
+      const collaboration_pb::Message& message,
+      const std::optional<tab_groups::SavedTabGroup>& tab_group,
+      const std::optional<tab_groups::SavedTabGroupTab>& tab,
+      const std::optional<PersistentNotificationType>& type);
+
+  // Creates individual messages based on `base_message` per type, and notifies
+  // oservers to display the messages.
+  void NotifyDisplayPersistentMessagesForTypes(
+      const PersistentMessage& base_message,
+      const std::vector<PersistentNotificationType>& types);
+
+  // Creates individual messages based on `base_message` per type, and notifies
+  // oservers to hide the messages.
+  void NotifyHidePersistentMessagesForTypes(
+      const PersistentMessage& base_message,
+      const std::vector<PersistentNotificationType>& types);
+
+  // Notifies observers to display or hide the dirty dot for a tab group.
+  void DisplayOrHideTabGroupDirtyDotForTabGroup(
+      const data_sharing::GroupId& collaboration_group_id,
+      base::Uuid shared_tab_group_id);
+
   // Provides functionality to go from observing the TabGroupSyncService to
   // a delta based observer API.
   std::unique_ptr<TabGroupChangeNotifier> tab_group_change_notifier_;
@@ -142,6 +209,10 @@
   // data sharing service.
   DataSharingChangeNotifier::FlushCallback data_sharing_flush_callback_;
 
+  // The last tab the user selected, or `std::nullopt` if it was outside a
+  // shared tab group.
+  std::optional<tab_groups::SavedTabGroupTab> last_selected_tab_;
+
   // Service providing information about tabs and tab groups.
   raw_ptr<tab_groups::TabGroupSyncService> tab_group_sync_service_;
 
diff --git a/components/collaboration/internal/messaging/messaging_backend_service_impl_unittest.cc b/components/collaboration/internal/messaging/messaging_backend_service_impl_unittest.cc
index dfd52e9..c701b73 100644
--- a/components/collaboration/internal/messaging/messaging_backend_service_impl_unittest.cc
+++ b/components/collaboration/internal/messaging/messaging_backend_service_impl_unittest.cc
@@ -20,6 +20,7 @@
 #include "components/data_sharing/test_support/mock_data_sharing_service.h"
 #include "components/saved_tab_groups/public/saved_tab_group_tab.h"
 #include "components/saved_tab_groups/public/tab_group_sync_service.h"
+#include "components/saved_tab_groups/public/types.h"
 #include "components/saved_tab_groups/test_support/mock_tab_group_sync_service.h"
 #include "components/tab_groups/tab_group_color.h"
 #include "google_apis/gaia/gaia_id.h"
@@ -861,4 +862,202 @@
             activity_log[2].activity_metadata.triggering_user->email);
 }
 
+TEST_F(MessagingBackendServiceImplTest, TestGetMessagesNoMessages) {
+  CreateAndInitializeService();
+
+  std::vector<collaboration_pb::Message> db_messages;
+
+  EXPECT_CALL(*unowned_messaging_backend_store_,
+              GetDirtyMessages(DirtyType::kAll))
+      .WillOnce(Return(db_messages));
+  std::vector<PersistentMessage> messages = service_->GetMessages(std::nullopt);
+  EXPECT_EQ(0u, messages.size());
+}
+
+TEST_F(MessagingBackendServiceImplTest, TestGetMessagesOneMessage) {
+  CreateAndInitializeService();
+
+  data_sharing::GroupId collaboration_group_id =
+      data_sharing::GroupId("my group id");
+  base::Time now = base::Time::Now();
+
+  std::vector<collaboration_pb::Message> db_messages;
+
+  EXPECT_CALL(*unowned_messaging_backend_store_,
+              GetDirtyMessages(DirtyType::kAll))
+      .WillOnce(Return(db_messages));
+  std::vector<PersistentMessage> messages = service_->GetMessages(std::nullopt);
+  EXPECT_EQ(0u, messages.size());
+
+  collaboration_pb::Message message = CreateStoredMessage(
+      collaboration_group_id, collaboration_pb::EventType::TAB_ADDED,
+      DirtyType::kDotAndChip, now);
+  db_messages.emplace_back(message);
+
+  EXPECT_CALL(*unowned_messaging_backend_store_,
+              GetDirtyMessages(DirtyType::kAll))
+      .WillOnce(Return(db_messages));
+  // Our service will need to also query for dirty dot messages for a group.
+  EXPECT_CALL(*unowned_messaging_backend_store_,
+              GetDirtyMessagesForGroup(collaboration_group_id, DirtyType::kDot))
+      .WillOnce(Return(db_messages));
+  messages = service_->GetMessages(std::nullopt);
+  // Should become two PersistentMessages for the tab, and one for the tab
+  // group.
+  ASSERT_EQ(3u, messages.size());
+  EXPECT_EQ(CollaborationEvent::TAB_ADDED, messages.at(0).collaboration_event);
+  EXPECT_EQ(PersistentNotificationType::CHIP, messages.at(0).type);
+  EXPECT_EQ(CollaborationEvent::TAB_ADDED, messages.at(1).collaboration_event);
+  EXPECT_EQ(PersistentNotificationType::DIRTY_TAB, messages.at(1).type);
+  EXPECT_EQ(CollaborationEvent::UNDEFINED, messages.at(2).collaboration_event);
+  EXPECT_EQ(PersistentNotificationType::DIRTY_TAB_GROUP, messages.at(2).type);
+}
+
+TEST_F(MessagingBackendServiceImplTest, TestGetMessagesTwoMessages) {
+  CreateAndInitializeService();
+
+  data_sharing::GroupId collaboration_group_id =
+      data_sharing::GroupId("my group id");
+  base::Time now = base::Time::Now();
+
+  std::vector<collaboration_pb::Message> db_messages;
+
+  EXPECT_CALL(*unowned_messaging_backend_store_,
+              GetDirtyMessages(DirtyType::kAll))
+      .WillOnce(Return(db_messages));
+  std::vector<PersistentMessage> messages = service_->GetMessages(std::nullopt);
+  EXPECT_EQ(0u, messages.size());
+
+  collaboration_pb::Message message1 = CreateStoredMessage(
+      collaboration_group_id, collaboration_pb::EventType::TAB_ADDED,
+      DirtyType::kDotAndChip, now);
+  collaboration_pb::Message message2 = CreateStoredMessage(
+      collaboration_group_id, collaboration_pb::EventType::TAB_UPDATED,
+      DirtyType::kDotAndChip, now);
+  db_messages.emplace_back(message1);
+  db_messages.emplace_back(message2);
+
+  EXPECT_CALL(*unowned_messaging_backend_store_,
+              GetDirtyMessages(DirtyType::kAll))
+      .WillRepeatedly(Return(db_messages));
+  // Our service will need to also query for dirty dot messages for a group.
+  EXPECT_CALL(*unowned_messaging_backend_store_,
+              GetDirtyMessagesForGroup(collaboration_group_id, DirtyType::kDot))
+      .WillRepeatedly(Return(db_messages));
+  messages = service_->GetMessages(std::nullopt);
+  // Should become two PersistentMessages for each tab, and one for the tab
+  // group.
+  ASSERT_EQ(5u, messages.size());
+  EXPECT_EQ(CollaborationEvent::TAB_ADDED, messages.at(0).collaboration_event);
+  EXPECT_EQ(PersistentNotificationType::CHIP, messages.at(0).type);
+  EXPECT_EQ(CollaborationEvent::TAB_ADDED, messages.at(1).collaboration_event);
+  EXPECT_EQ(PersistentNotificationType::DIRTY_TAB, messages.at(1).type);
+  EXPECT_EQ(CollaborationEvent::UNDEFINED, messages.at(2).collaboration_event);
+  EXPECT_EQ(PersistentNotificationType::DIRTY_TAB_GROUP, messages.at(2).type);
+  EXPECT_EQ(CollaborationEvent::TAB_UPDATED,
+            messages.at(3).collaboration_event);
+  EXPECT_EQ(PersistentNotificationType::CHIP, messages.at(3).type);
+  EXPECT_EQ(CollaborationEvent::TAB_UPDATED,
+            messages.at(4).collaboration_event);
+  EXPECT_EQ(PersistentNotificationType::DIRTY_TAB, messages.at(4).type);
+}
+
+TEST_F(MessagingBackendServiceImplTest, TestGetMessagesForGroup) {
+  CreateAndInitializeService();
+
+  data_sharing::GroupId collaboration_group_id =
+      data_sharing::GroupId("my group id");
+  base::Time now = base::Time::Now();
+
+  std::vector<collaboration_pb::Message> db_messages;
+
+  EXPECT_CALL(*unowned_messaging_backend_store_,
+              GetDirtyMessages(DirtyType::kAll))
+      .WillOnce(Return(db_messages));
+  std::vector<PersistentMessage> messages = service_->GetMessages(std::nullopt);
+  EXPECT_EQ(0u, messages.size());
+
+  collaboration_pb::Message message = CreateStoredMessage(
+      collaboration_group_id, collaboration_pb::EventType::TAB_ADDED,
+      DirtyType::kDotAndChip, now);
+  db_messages.emplace_back(message);
+
+  EXPECT_CALL(*unowned_messaging_backend_store_,
+              GetDirtyMessagesForGroup(collaboration_group_id, DirtyType::kAll))
+      .WillOnce(Return(db_messages));
+  // Our service will need to query for dirty dot messages for a group.
+  EXPECT_CALL(*unowned_messaging_backend_store_,
+              GetDirtyMessagesForGroup(collaboration_group_id, DirtyType::kDot))
+      .WillOnce(Return(db_messages));
+
+  // The query should come for the given tab group.
+  tab_groups::SavedTabGroup tab_group =
+      CreateSharedTabGroup(collaboration_group_id);
+  EXPECT_CALL(*mock_tab_group_sync_service_,
+              GetGroup(tab_groups::EitherGroupID(tab_group.saved_guid())))
+      .WillOnce(Return(tab_group));
+
+  messages = service_->GetMessagesForGroup(
+      tab_groups::EitherGroupID(tab_group.saved_guid()), std::nullopt);
+  // Should become two PersistentMessages for the tab, and one for the tab
+  // group.
+  ASSERT_EQ(3u, messages.size());
+  EXPECT_EQ(CollaborationEvent::TAB_ADDED, messages.at(0).collaboration_event);
+  EXPECT_EQ(PersistentNotificationType::CHIP, messages.at(0).type);
+  EXPECT_EQ(CollaborationEvent::TAB_ADDED, messages.at(1).collaboration_event);
+  EXPECT_EQ(PersistentNotificationType::DIRTY_TAB, messages.at(1).type);
+  EXPECT_EQ(CollaborationEvent::UNDEFINED, messages.at(2).collaboration_event);
+  EXPECT_EQ(PersistentNotificationType::DIRTY_TAB_GROUP, messages.at(2).type);
+}
+
+TEST_F(MessagingBackendServiceImplTest, TestGetMessagesForTab) {
+  CreateAndInitializeService();
+
+  data_sharing::GroupId collaboration_group_id =
+      data_sharing::GroupId("my group id");
+  base::Time now = base::Time::Now();
+
+  std::vector<collaboration_pb::Message> db_messages;
+
+  EXPECT_CALL(*unowned_messaging_backend_store_,
+              GetDirtyMessages(DirtyType::kAll))
+      .WillOnce(Return(db_messages));
+  std::vector<PersistentMessage> messages = service_->GetMessages(std::nullopt);
+  EXPECT_EQ(0u, messages.size());
+
+  collaboration_pb::Message message = CreateStoredMessage(
+      collaboration_group_id, collaboration_pb::EventType::TAB_ADDED,
+      DirtyType::kDotAndChip, now);
+  db_messages.emplace_back(message);
+
+  // The query should come for the given tab's tab group.
+  tab_groups::SavedTabGroup tab_group =
+      CreateSharedTabGroup(collaboration_group_id);
+  std::vector<tab_groups::SavedTabGroup> all_groups = {tab_group};
+  EXPECT_CALL(*mock_tab_group_sync_service_, GetAllGroups())
+      .WillRepeatedly(Return(all_groups));
+  EXPECT_CALL(*mock_tab_group_sync_service_, GetGroup(tab_group.saved_guid()))
+      .WillRepeatedly(Return(tab_group));
+  base::Uuid tab1_sync_id = tab_group.saved_tabs().at(0).saved_tab_guid();
+
+  EXPECT_CALL(*unowned_messaging_backend_store_,
+              GetDirtyMessageForTab(collaboration_group_id, tab1_sync_id,
+                                    DirtyType::kAll))
+      .WillRepeatedly(Return(db_messages.at(0)));
+  // Our service will need to query for dirty dot messages for a group.
+  EXPECT_CALL(*unowned_messaging_backend_store_,
+              GetDirtyMessagesForGroup(collaboration_group_id, DirtyType::kDot))
+      .WillRepeatedly(Return(db_messages));
+
+  messages = service_->GetMessagesForTab(tab_groups::EitherTabID(tab1_sync_id),
+                                         std::nullopt);
+  // Should become two PersistentMessages for the tab, but nothing from the
+  // group.
+  ASSERT_EQ(2u, messages.size());
+  EXPECT_EQ(CollaborationEvent::TAB_ADDED, messages.at(0).collaboration_event);
+  EXPECT_EQ(PersistentNotificationType::CHIP, messages.at(0).type);
+  EXPECT_EQ(CollaborationEvent::TAB_ADDED, messages.at(1).collaboration_event);
+  EXPECT_EQ(PersistentNotificationType::DIRTY_TAB, messages.at(1).type);
+}
+
 }  // namespace collaboration::messaging
diff --git a/components/collaboration/internal/messaging/tab_group_change_notifier_impl.cc b/components/collaboration/internal/messaging/tab_group_change_notifier_impl.cc
index a0a0d2f..2f94ae08 100644
--- a/components/collaboration/internal/messaging/tab_group_change_notifier_impl.cc
+++ b/components/collaboration/internal/messaging/tab_group_change_notifier_impl.cc
@@ -336,6 +336,19 @@
     return std::nullopt;
   }
 
+  // Try to look up live data first, since we are not always updated, e.g. if a
+  // local tab ID changes for a particular tab.
+  std::optional<tab_groups::SavedTabGroup> tab_group;
+  if (sync_tab_group_id) {
+    tab_group = tab_group_sync_service_->GetGroup(*sync_tab_group_id);
+  }
+  if (tab_group) {
+    const tab_groups::SavedTabGroupTab* tab = tab_group->GetTab(*sync_tab_id);
+    if (tab) {
+      return *tab;
+    }
+  }
+
   // The tab is in a shared tab group.
   const tab_groups::SavedTabGroup& group = group_it->second;
   const tab_groups::SavedTabGroupTab* tab = group.GetTab(*sync_tab_id);
diff --git a/components/collaboration/internal/messaging/tab_group_change_notifier_impl_unittest.cc b/components/collaboration/internal/messaging/tab_group_change_notifier_impl_unittest.cc
index 1f85e11..76b32113 100644
--- a/components/collaboration/internal/messaging/tab_group_change_notifier_impl_unittest.cc
+++ b/components/collaboration/internal/messaging/tab_group_change_notifier_impl_unittest.cc
@@ -786,4 +786,36 @@
                                 tab1.saved_tab_guid());
 }
 
+TEST_F(TabGroupChangeNotifierImplTest, TestTabSelectionReadsLiveData) {
+  InitializeNotifier(
+      /*startup_tab_groups=*/std::vector<tab_groups::SavedTabGroup>(),
+      /*init_tab_groups=*/std::vector<tab_groups::SavedTabGroup>());
+
+  tab_groups::SavedTabGroup tab_group = CreateTestSharedTabGroupWithNoTabs();
+  tab_groups::SavedTabGroupTab tab = tab_groups::test::CreateSavedTabGroupTab(
+      "url", u"title", tab_group.saved_guid());
+  // The local tab ID is not set yet.
+  tab_group.AddTabFromSync(tab);
+
+  // Set up notifier with initial tab group data.
+  EXPECT_CALL(*notifier_observer_, OnTabGroupAdded(TabGroupGuidEq(tab_group)));
+  tgss_observer_->OnTabGroupAdded(tab_group, tab_groups::TriggerSource::REMOTE);
+
+  // Now, set the local tab ID, but do not inform our observers.
+  tab_groups::SavedTabGroupTab* tab_for_update =
+      tab_group.GetTab(tab.saved_tab_guid());
+  tab_for_update->SetLocalTabID(42);
+
+  // We expect the notifier to use live data to get the updated local tab id.
+  EXPECT_CALL(*tab_group_sync_service_, GetGroup(tab_group.saved_guid()))
+      .WillOnce(Return(tab_group));
+
+  std::optional<tab_groups::SavedTabGroupTab> tab_selection_received;
+  // Select the tab: This should lead to our notifier reading the live data.
+  EXPECT_CALL(*notifier_observer_, OnTabSelected(TabGuidEq(tab)))
+      .WillOnce(SaveArg<0>(&tab_selection_received));
+  tgss_observer_->OnTabSelected(tab_group.saved_guid(), tab.saved_tab_guid());
+  EXPECT_EQ(42, tab_selection_received->local_tab_id());
+}
+
 }  // namespace collaboration::messaging
diff --git a/components/collaboration/public/BUILD.gn b/components/collaboration/public/BUILD.gn
index 0f3fb32a8..130007b 100644
--- a/components/collaboration/public/BUILD.gn
+++ b/components/collaboration/public/BUILD.gn
@@ -20,6 +20,8 @@
   sources = [
     "collaboration_controller_delegate.h",
     "collaboration_service.h",
+    "features.cc",
+    "features.h",
     "service_status.cc",
     "service_status.h",
   ]
diff --git a/components/collaboration/public/features.cc b/components/collaboration/public/features.cc
new file mode 100644
index 0000000..63b98944
--- /dev/null
+++ b/components/collaboration/public/features.cc
@@ -0,0 +1,15 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/collaboration/public/features.h"
+
+#include "base/feature_list.h"
+
+namespace collaboration::messaging {
+
+BASE_FEATURE(kCollaborationMessaging,
+             "CollaborationMessaging",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+}  // namespace collaboration::messaging
diff --git a/components/collaboration/public/features.h b/components/collaboration/public/features.h
new file mode 100644
index 0000000..ead7a10e
--- /dev/null
+++ b/components/collaboration/public/features.h
@@ -0,0 +1,16 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_COLLABORATION_PUBLIC_FEATURES_H_
+#define COMPONENTS_COLLABORATION_PUBLIC_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace collaboration::messaging {
+
+BASE_DECLARE_FEATURE(kCollaborationMessaging);
+
+}  // namespace collaboration::messaging
+
+#endif  // COMPONENTS_COLLABORATION_PUBLIC_FEATURES_H_
diff --git a/components/collaboration/public/messaging/messaging_backend_service.h b/components/collaboration/public/messaging/messaging_backend_service.h
index 506fcd0..1d2cebf 100644
--- a/components/collaboration/public/messaging/messaging_backend_service.h
+++ b/components/collaboration/public/messaging/messaging_backend_service.h
@@ -23,9 +23,9 @@
   class PersistentMessageObserver : public base::CheckedObserver {
    public:
     // Invoked once when the service is initialized. This is invoked only once
-    // and is immediately invoked if the service was initialized before the
-    // observer was added. The initialization state can also be inspected using
-    // IsInitialized().
+    // and is immediately invoked (re-entrant) if the service was initialized
+    // before the observer was added. You can invoke `IsInitialized()` if you
+    // want to know the state and whether this is going to happen or not.
     virtual void OnMessagingBackendServiceInitialized() = 0;
 
     // Invoked when the frontend needs to display a specific persistent message.
diff --git a/components/commerce/core/commerce_feature_list.cc b/components/commerce/core/commerce_feature_list.cc
index a0c687ed..2d19e92 100644
--- a/components/commerce/core/commerce_feature_list.cc
+++ b/components/commerce/core/commerce_feature_list.cc
@@ -198,11 +198,6 @@
     &commerce::kProductSpecificationsMultiSpecifics,
     kProductSpecsMigrateToMultiSpecificsParam, false};
 
-// Tonal colors for the expanded state of the price tracking chip on desktop.
-BASE_FEATURE(kPriceTrackingIconColors,
-             "PriceTrackingIconColors",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 // Promotion in Magic Stack for Price Tracking users from other platforms.
 BASE_FEATURE(kPriceTrackingPromo,
              "PriceTrackingPromo",
@@ -243,10 +238,6 @@
              "CompareManagementInterface",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kShoppingIconColorVariant,
-             "ShoppingIconColorVariant",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 // Discount on navigation
 BASE_FEATURE(kEnableDiscountInfoApi,
              "EnableDiscountInfoApi",
diff --git a/components/commerce/core/commerce_feature_list.h b/components/commerce/core/commerce_feature_list.h
index 2880ab09..ca4e256c 100644
--- a/components/commerce/core/commerce_feature_list.h
+++ b/components/commerce/core/commerce_feature_list.h
@@ -46,7 +46,6 @@
 extern const base::FeatureParam<bool> kPriceInsightsUseCache;
 extern const char kProductSpecsMigrateToMultiSpecificsParam[];
 extern const base::FeatureParam<bool> kProductSpecsMigrateToMultiSpecifics;
-BASE_DECLARE_FEATURE(kPriceTrackingIconColors);
 BASE_DECLARE_FEATURE(kPriceTrackingPromo);
 
 BASE_DECLARE_FEATURE(kProductSpecifications);
@@ -57,7 +56,6 @@
 BASE_DECLARE_FEATURE(kProductSpecificationsCache);
 BASE_DECLARE_FEATURE(kCompareManagementInterface);
 
-BASE_DECLARE_FEATURE(kShoppingIconColorVariant);
 BASE_DECLARE_FEATURE(kShoppingList);
 BASE_DECLARE_FEATURE(kShoppingListRegionLaunched);
 BASE_DECLARE_FEATURE(kPriceTrackingSubscriptionServiceLocaleKey);
diff --git a/components/commerce/core/flag_descriptions.cc b/components/commerce/core/flag_descriptions.cc
index 9e74913..a788514 100644
--- a/components/commerce/core/flag_descriptions.cc
+++ b/components/commerce/core/flag_descriptions.cc
@@ -11,12 +11,6 @@
     "Allow Chrome to attempt to detect product pages on the client, without "
     "server support.";
 
-const char kPriceTrackingIconColorsName[] =
-    "Price Tracking Icon Tonal UI Colors";
-const char kPriceTrackingIconColorsDescription[] =
-    "Tonal colors for the expanded state of the price tracking chip on "
-    "desktop.";
-
 const char kProductSpecificationsName[] = "Product Specifications";
 const char kProductSpecificationsDescription[] =
     "Enable the Product Specifications feature.";
@@ -37,12 +31,6 @@
     "Enable showing the comparison tables list in the Compare UI and enable "
     "the new \"Comparison tables\" context menu under \"Bookmarks and Lists\".";
 
-const char kShoppingIconColorVariantName[] =
-    "Enable color variant for shopping icons";
-const char kShoppingIconColorVariantDescription[] =
-    "Enables a color variant for shopping page action icons (Price Insights & "
-    "Price Tracking)";
-
 const char kShoppingListName[] = "Shopping List";
 const char kShoppingListDescription[] = "Enable shopping list in bookmarks.";
 
diff --git a/components/commerce/core/flag_descriptions.h b/components/commerce/core/flag_descriptions.h
index 9691ab7..4d1ec9f 100644
--- a/components/commerce/core/flag_descriptions.h
+++ b/components/commerce/core/flag_descriptions.h
@@ -12,9 +12,6 @@
 extern const char kCommerceLocalPDPDetectionName[];
 extern const char kCommerceLocalPDPDetectionDescription[];
 
-extern const char kPriceTrackingIconColorsName[];
-extern const char kPriceTrackingIconColorsDescription[];
-
 extern const char kProductSpecificationsName[];
 extern const char kProductSpecificationsDescription[];
 
@@ -27,9 +24,6 @@
 extern const char kCompareManagementInterfaceName[];
 extern const char kCompareManagementInterfaceDescription[];
 
-extern const char kShoppingIconColorVariantName[];
-extern const char kShoppingIconColorVariantDescription[];
-
 extern const char kShoppingListName[];
 extern const char kShoppingListDescription[];
 
diff --git a/components/component_updater/installer_policies/trust_token_key_commitments_component_installer_policy_unittest.cc b/components/component_updater/installer_policies/trust_token_key_commitments_component_installer_policy_unittest.cc
index e4fc5d1..b8609ff 100644
--- a/components/component_updater/installer_policies/trust_token_key_commitments_component_installer_policy_unittest.cc
+++ b/components/component_updater/installer_policies/trust_token_key_commitments_component_installer_policy_unittest.cc
@@ -13,12 +13,10 @@
 #include "base/sequence_checker.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_command_line.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/values.h"
 #include "base/version.h"
 #include "components/component_updater/component_updater_switches.h"
-#include "services/network/public/cpp/features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -42,9 +40,6 @@
 
 TEST_F(TrustTokenKeyCommitmentsComponentInstallerTest,
        LoadsCommitmentsFromOverriddenPath) {
-  base::test::ScopedFeatureList scoped_list;
-  scoped_list.InitAndEnableFeature(network::features::kPrivateStateTokens);
-
   base::SequenceCheckerImpl checker;
 
   std::string expectation = "some trust token keys";
@@ -79,9 +74,6 @@
 }
 
 TEST_F(TrustTokenKeyCommitmentsComponentInstallerTest, LoadsCommitments) {
-  base::test::ScopedFeatureList scoped_list;
-  scoped_list.InitAndEnableFeature(network::features::kPrivateStateTokens);
-
   base::SequenceCheckerImpl checker;
 
   std::string expectation = "some trust token keys";
diff --git a/components/embedder_support/user_agent_utils.cc b/components/embedder_support/user_agent_utils.cc
index a8cb8f5d..279a6ae 100644
--- a/components/embedder_support/user_agent_utils.cc
+++ b/components/embedder_support/user_agent_utils.cc
@@ -193,26 +193,16 @@
 #if !BUILDFLAG(CHROMIUM_BRANDING)
   brand = version_info::GetProductName();
 #endif
-  std::optional<std::string> maybe_brand_override =
-      base::GetFieldTrialParamValueByFeature(features::kGreaseUACH,
-                                             "brand_override");
-  std::optional<std::string> maybe_version_override =
-      base::GetFieldTrialParamValueByFeature(features::kGreaseUACH,
-                                             "version_override");
-  if (maybe_brand_override->empty())
-    maybe_brand_override = std::nullopt;
-  if (maybe_version_override->empty())
-    maybe_version_override = std::nullopt;
 
   std::string brand_version =
       output_version_type == blink::UserAgentBrandVersionType::kFullVersion
           ? full_version
           : major_version;
 
-  return GenerateBrandVersionList(
-      major_version_number, brand, brand_version, maybe_brand_override,
-      maybe_version_override, enable_updated_grease_by_policy,
-      output_version_type, additional_brand_version);
+  return GenerateBrandVersionList(major_version_number, brand, brand_version,
+                                  enable_updated_grease_by_policy,
+                                  output_version_type,
+                                  additional_brand_version);
 }
 
 // Return UserAgentBrandList with the major version populated in the brand
@@ -383,16 +373,13 @@
     int seed,
     std::optional<std::string> brand,
     const std::string& version,
-    std::optional<std::string> maybe_greasey_brand,
-    std::optional<std::string> maybe_greasey_version,
     bool enable_updated_grease_by_policy,
     blink::UserAgentBrandVersionType output_version_type,
     std::optional<blink::UserAgentBrandVersion> additional_brand_version) {
   DCHECK_GE(seed, 0);
 
   blink::UserAgentBrandVersion greasey_bv = GetGreasedUserAgentBrandVersion(
-      seed, maybe_greasey_brand, maybe_greasey_version,
-      enable_updated_grease_by_policy, output_version_type);
+      seed, enable_updated_grease_by_policy, output_version_type);
   blink::UserAgentBrandVersion chromium_bv = {"Chromium", version};
 
   blink::UserAgentBrandList brand_version_list = {std::move(greasey_bv),
@@ -443,8 +430,6 @@
 
 blink::UserAgentBrandVersion GetGreasedUserAgentBrandVersion(
     int seed,
-    std::optional<std::string> maybe_greasey_brand,
-    std::optional<std::string> maybe_greasey_version,
     bool enable_updated_grease_by_policy,
     blink::UserAgentBrandVersionType output_version_type) {
   std::string greasey_brand;
@@ -452,9 +437,7 @@
   // The updated algorithm is enabled by default, but we maintain the ability
   // to opt out of it either via Finch (setting updated_algorithm to false) or
   // via an enterprise policy escape hatch.
-  if (enable_updated_grease_by_policy &&
-      base::GetFieldTrialParamByFeatureAsBool(features::kGreaseUACH,
-                                              "updated_algorithm", true)) {
+  if (enable_updated_grease_by_policy) {
     const std::vector<std::string> greasey_chars = {
         " ", "(", ":", "-", ".", "/", ")", ";", "=", "?", "_"};
     const std::vector<std::string> greased_versions = {"8", "99", "24"};
@@ -465,9 +448,8 @@
          greasey_chars[(seed + 1) % greasey_chars.size()], "Brand"});
     greasey_version = greased_versions[seed % greased_versions.size()];
 
-    return GetProcessedGreasedBrandVersion(
-        maybe_greasey_brand.value_or(greasey_brand),
-        maybe_greasey_version.value_or(greasey_version), output_version_type);
+    return GetProcessedGreasedBrandVersion(greasey_brand, greasey_version,
+                                           output_version_type);
   } else {
     const std::vector<std::string> greasey_chars = {" ", " ", ";"};
     const std::vector<size_t> permuted_order =
diff --git a/components/embedder_support/user_agent_utils.h b/components/embedder_support/user_agent_utils.h
index e6a4843..3adb28fb 100644
--- a/components/embedder_support/user_agent_utils.h
+++ b/components/embedder_support/user_agent_utils.h
@@ -69,8 +69,6 @@
     int seed,
     std::optional<std::string> brand,
     const std::string& version,
-    std::optional<std::string> maybe_greasey_brand,
-    std::optional<std::string> maybe_greasey_version,
     bool enable_updated_grease_by_policy,
     blink::UserAgentBrandVersionType output_version_type,
     std::optional<blink::UserAgentBrandVersion> additional_brand_version =
@@ -107,8 +105,6 @@
 // https://wicg.github.io/ua-client-hints/#create-arbitrary-brands-section.
 blink::UserAgentBrandVersion GetGreasedUserAgentBrandVersion(
     int seed,
-    std::optional<std::string> maybe_greasey_brand,
-    std::optional<std::string> maybe_greasey_version,
     bool enable_updated_grease_by_policy,
     blink::UserAgentBrandVersionType output_version_type);
 
diff --git a/components/embedder_support/user_agent_utils_unittest.cc b/components/embedder_support/user_agent_utils_unittest.cc
index 8912eb3..b9779c4 100644
--- a/components/embedder_support/user_agent_utils_unittest.cc
+++ b/components/embedder_support/user_agent_utils_unittest.cc
@@ -771,12 +771,12 @@
 
 TEST_F(UserAgentUtilsTest, GenerateBrandVersionListUnbranded) {
   blink::UserAgentMetadata metadata;
-  metadata.brand_version_list = GenerateBrandVersionList(
-      84, std::nullopt, "84", std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
-  metadata.brand_full_version_list = GenerateBrandVersionList(
-      84, std::nullopt, "84.0.0.0", std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kFullVersion);
+  metadata.brand_version_list =
+      GenerateBrandVersionList(84, std::nullopt, "84", true,
+                               blink::UserAgentBrandVersionType::kMajorVersion);
+  metadata.brand_full_version_list =
+      GenerateBrandVersionList(84, std::nullopt, "84.0.0.0", true,
+                               blink::UserAgentBrandVersionType::kFullVersion);
   // 1. verify major version
   std::string brand_list = metadata.SerializeBrandMajorVersionList();
   EXPECT_EQ(R"("Not;A=Brand";v="8", "Chromium";v="84")", brand_list);
@@ -789,19 +789,19 @@
 TEST_F(UserAgentUtilsTest, GenerateBrandVersionListUnbrandedVerifySeedChanges) {
   blink::UserAgentMetadata metadata;
 
-  metadata.brand_version_list = GenerateBrandVersionList(
-      84, std::nullopt, "84", std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
+  metadata.brand_version_list =
+      GenerateBrandVersionList(84, std::nullopt, "84", true,
+                               blink::UserAgentBrandVersionType::kMajorVersion);
   // Capture the serialized brand lists with version 84 as the seed.
   std::string brand_list = metadata.SerializeBrandMajorVersionList();
   std::string brand_list_w_fv = metadata.SerializeBrandFullVersionList();
 
-  metadata.brand_version_list = GenerateBrandVersionList(
-      85, std::nullopt, "85", std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
-  metadata.brand_full_version_list = GenerateBrandVersionList(
-      85, std::nullopt, "85.0.0.0", std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kFullVersion);
+  metadata.brand_version_list =
+      GenerateBrandVersionList(85, std::nullopt, "85", true,
+                               blink::UserAgentBrandVersionType::kMajorVersion);
+  metadata.brand_full_version_list =
+      GenerateBrandVersionList(85, std::nullopt, "85.0.0.0", true,
+                               blink::UserAgentBrandVersionType::kFullVersion);
 
   // Make sure the lists are different for different seeds (84 vs 85).
   // 1. verify major version
@@ -815,27 +815,6 @@
   EXPECT_NE(brand_list_w_fv, brand_list_diff_w_fv);
 }
 
-TEST_F(UserAgentUtilsTest, GenerateBrandVersionListWithGreaseBrandOverride) {
-  blink::UserAgentMetadata metadata;
-  // The GREASE generation algorithm should respond to experiment overrides.
-  metadata.brand_version_list = GenerateBrandVersionList(
-      84, std::nullopt, "84", "Clean GREASE", std::nullopt, true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
-  metadata.brand_full_version_list = GenerateBrandVersionList(
-      84, std::nullopt, "84.0.0.0", "Clean GREASE", std::nullopt, true,
-      blink::UserAgentBrandVersionType::kFullVersion);
-  // 1. verify major version
-  std::string brand_list_grease_override =
-      metadata.SerializeBrandMajorVersionList();
-  EXPECT_EQ(R"("Clean GREASE";v="8", "Chromium";v="84")",
-            brand_list_grease_override);
-  // 2. verify full version
-  std::string brand_list_grease_override_fv =
-      metadata.SerializeBrandFullVersionList();
-  EXPECT_EQ(R"("Clean GREASE";v="8.0.0.0", "Chromium";v="84.0.0.0")",
-            brand_list_grease_override_fv);
-}
-
 TEST_F(UserAgentUtilsTest, GenerateBrandVersionListAdditionalBrandVersions) {
   blink::UserAgentMetadata metadata;
   // The GREASE generation algorithm should respond to experiment overrides.
@@ -844,15 +823,15 @@
   blink::UserAgentBrandVersion additional_brand_full_versions = {"Add Brand",
                                                                  "1.0.0.0"};
 
-  // 1. Without greasey brand and product brand.
-  metadata.brand_version_list = GenerateBrandVersionList(
-      84, std::nullopt, "84", std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kMajorVersion,
-      additional_brand_major_versions);
-  metadata.brand_full_version_list = GenerateBrandVersionList(
-      84, std::nullopt, "84.0.0.0", std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kFullVersion,
-      additional_brand_full_versions);
+  // 1. Without product brand.
+  metadata.brand_version_list =
+      GenerateBrandVersionList(84, std::nullopt, "84", true,
+                               blink::UserAgentBrandVersionType::kMajorVersion,
+                               additional_brand_major_versions);
+  metadata.brand_full_version_list =
+      GenerateBrandVersionList(84, std::nullopt, "84.0.0.0", true,
+                               blink::UserAgentBrandVersionType::kFullVersion,
+                               additional_brand_full_versions);
   // Verify major version and full version.
   EXPECT_EQ(base::StrCat({"\"Not;A=Brand\";v=\"8\", ",
                           "\"Chromium\";v=\"84\", ", "\"Add Brand\";v=\"1\""}),
@@ -862,33 +841,15 @@
                           "\"Add Brand\";v=\"1.0.0.0\""}),
             metadata.SerializeBrandFullVersionList());
 
-  // 2. With greasey brand
-  metadata.brand_version_list = GenerateBrandVersionList(
-      84, std::nullopt, "84", "Clean GREASE", std::nullopt, true,
-      blink::UserAgentBrandVersionType::kMajorVersion,
-      additional_brand_major_versions);
-  metadata.brand_full_version_list = GenerateBrandVersionList(
-      84, std::nullopt, "84.0.0.0", "Clean GREASE", std::nullopt, true,
-      blink::UserAgentBrandVersionType::kFullVersion,
-      additional_brand_full_versions);
-  // Verify major version and full version.
-  EXPECT_EQ(base::StrCat({"\"Clean GREASE\";v=\"8\", ",
-                          "\"Chromium\";v=\"84\", ", "\"Add Brand\";v=\"1\""}),
-            metadata.SerializeBrandMajorVersionList());
-  EXPECT_EQ(base::StrCat({"\"Clean GREASE\";v=\"8.0.0.0\", ",
-                          "\"Chromium\";v=\"84.0.0.0\", ",
-                          "\"Add Brand\";v=\"1.0.0.0\""}),
-            metadata.SerializeBrandFullVersionList());
-
-  // 3. With product brand
-  metadata.brand_version_list = GenerateBrandVersionList(
-      84, "Product Brand", "84", std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kMajorVersion,
-      additional_brand_major_versions);
-  metadata.brand_full_version_list = GenerateBrandVersionList(
-      84, "Product Brand", "84.0.0.0", std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kFullVersion,
-      additional_brand_full_versions);
+  // 2. With product brand
+  metadata.brand_version_list =
+      GenerateBrandVersionList(84, "Product Brand", "84", true,
+                               blink::UserAgentBrandVersionType::kMajorVersion,
+                               additional_brand_major_versions);
+  metadata.brand_full_version_list =
+      GenerateBrandVersionList(84, "Product Brand", "84.0.0.0", true,
+                               blink::UserAgentBrandVersionType::kFullVersion,
+                               additional_brand_full_versions);
   // Verify major version and full version.
   EXPECT_EQ(
       base::StrCat({"\"Chromium\";v=\"84\", ", "\"Product Brand\";v=\"84\", ",
@@ -900,43 +861,23 @@
                           "\"Add Brand\";v=\"1.0.0.0\""}),
             metadata.SerializeBrandFullVersionList());
 
-  // 4. With product brand and greasey brand
-  metadata.brand_version_list = GenerateBrandVersionList(
-      84, "Product Brand", "84", "Clean GREASE", std::nullopt, true,
-      blink::UserAgentBrandVersionType::kMajorVersion,
-      additional_brand_major_versions);
-  metadata.brand_full_version_list = GenerateBrandVersionList(
-      84, "Product Brand", "84.0.0.0", "Clean GREASE", std::nullopt, true,
-      blink::UserAgentBrandVersionType::kFullVersion,
-      additional_brand_full_versions);
-  // Verify major version and full version.
-  EXPECT_EQ(
-      base::StrCat({"\"Chromium\";v=\"84\", ", "\"Product Brand\";v=\"84\", ",
-                    "\"Clean GREASE\";v=\"8\", ", "\"Add Brand\";v=\"1\""}),
-      metadata.SerializeBrandMajorVersionList());
-  EXPECT_EQ(base::StrCat({"\"Chromium\";v=\"84.0.0.0\", ",
-                          "\"Product Brand\";v=\"84.0.0.0\", ",
-                          "\"Clean GREASE\";v=\"8.0.0.0\", ",
-                          "\"Add Brand\";v=\"1.0.0.0\""}),
-            metadata.SerializeBrandFullVersionList());
-
-  // 5. With product brand, greasey brand and different seed.
-  metadata.brand_version_list = GenerateBrandVersionList(
-      86, "Product Brand", "84", "Clean GREASE", std::nullopt, true,
-      blink::UserAgentBrandVersionType::kMajorVersion,
-      additional_brand_major_versions);
-  metadata.brand_full_version_list = GenerateBrandVersionList(
-      86, "Product Brand", "84.0.0.0", "Clean GREASE", std::nullopt, true,
-      blink::UserAgentBrandVersionType::kFullVersion,
-      additional_brand_full_versions);
+  // 3. With product brand and different seed.
+  metadata.brand_version_list =
+      GenerateBrandVersionList(86, "Product Brand", "84", true,
+                               blink::UserAgentBrandVersionType::kMajorVersion,
+                               additional_brand_major_versions);
+  metadata.brand_full_version_list =
+      GenerateBrandVersionList(86, "Product Brand", "84.0.0.0", true,
+                               blink::UserAgentBrandVersionType::kFullVersion,
+                               additional_brand_full_versions);
   // Verify major version and full version.
   EXPECT_EQ(
       base::StrCat({"\"Product Brand\";v=\"84\", ", "\"Chromium\";v=\"84\", ",
-                    "\"Clean GREASE\";v=\"24\", ", "\"Add Brand\";v=\"1\""}),
+                    "\"Not?A_Brand\";v=\"24\", ", "\"Add Brand\";v=\"1\""}),
       metadata.SerializeBrandMajorVersionList());
   EXPECT_EQ(base::StrCat({"\"Product Brand\";v=\"84.0.0.0\", ",
                           "\"Chromium\";v=\"84.0.0.0\", ",
-                          "\"Clean GREASE\";v=\"24.0.0.0\", ",
+                          "\"Not?A_Brand\";v=\"24.0.0.0\", ",
                           "\"Add Brand\";v=\"1.0.0.0\""}),
             metadata.SerializeBrandFullVersionList());
 
@@ -955,53 +896,53 @@
        GenerateBrandVersionListWithGreaseBrandAndVersionOverride) {
   blink::UserAgentMetadata metadata;
 
-  metadata.brand_version_list = GenerateBrandVersionList(
-      84, std::nullopt, "84", "Clean GREASE", "1024", true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
-  metadata.brand_full_version_list = GenerateBrandVersionList(
-      84, std::nullopt, "84.0.0.0", "Clean GREASE", "1024", true,
-      blink::UserAgentBrandVersionType::kFullVersion);
+  metadata.brand_version_list =
+      GenerateBrandVersionList(84, std::nullopt, "84", true,
+                               blink::UserAgentBrandVersionType::kMajorVersion);
+  metadata.brand_full_version_list =
+      GenerateBrandVersionList(84, std::nullopt, "84.0.0.0", true,
+                               blink::UserAgentBrandVersionType::kFullVersion);
   // 1. verify major version
   std::string brand_list_and_version_grease_override =
       metadata.SerializeBrandMajorVersionList();
-  EXPECT_EQ(R"("Clean GREASE";v="1024", "Chromium";v="84")",
+  EXPECT_EQ(R"("Not;A=Brand";v="8", "Chromium";v="84")",
             brand_list_and_version_grease_override);
   // 2. verify full version
   std::string brand_list_and_version_grease_override_fv =
       metadata.SerializeBrandFullVersionList();
-  EXPECT_EQ(R"("Clean GREASE";v="1024.0.0.0", "Chromium";v="84.0.0.0")",
+  EXPECT_EQ(R"("Not;A=Brand";v="8.0.0.0", "Chromium";v="84.0.0.0")",
             brand_list_and_version_grease_override_fv);
 }
 
 TEST_F(UserAgentUtilsTest, GenerateBrandVersionListWithGreaseVersionOverride) {
   blink::UserAgentMetadata metadata;
 
-  metadata.brand_version_list = GenerateBrandVersionList(
-      84, std::nullopt, "84", std::nullopt, "1024", true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
-  metadata.brand_full_version_list = GenerateBrandVersionList(
-      84, std::nullopt, "84.0.0.0", std::nullopt, "1024", true,
-      blink::UserAgentBrandVersionType::kFullVersion);
+  metadata.brand_version_list =
+      GenerateBrandVersionList(84, std::nullopt, "84", true,
+                               blink::UserAgentBrandVersionType::kMajorVersion);
+  metadata.brand_full_version_list =
+      GenerateBrandVersionList(84, std::nullopt, "84.0.0.0", true,
+                               blink::UserAgentBrandVersionType::kFullVersion);
   // 1. verify major version
   std::string brand_version_grease_override =
       metadata.SerializeBrandMajorVersionList();
-  EXPECT_EQ(R"("Not;A=Brand";v="1024", "Chromium";v="84")",
+  EXPECT_EQ(R"("Not;A=Brand";v="8", "Chromium";v="84")",
             brand_version_grease_override);
   // 2. verify full version
   std::string brand_version_grease_override_fv =
       metadata.SerializeBrandFullVersionList();
-  EXPECT_EQ(R"("Not;A=Brand";v="1024.0.0.0", "Chromium";v="84.0.0.0")",
+  EXPECT_EQ(R"("Not;A=Brand";v="8.0.0.0", "Chromium";v="84.0.0.0")",
             brand_version_grease_override_fv);
 }
 
 TEST_F(UserAgentUtilsTest, GenerateBrandVersionListWithBrand) {
   blink::UserAgentMetadata metadata;
-  metadata.brand_version_list = GenerateBrandVersionList(
-      84, "Totally A Brand", "84", std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
-  metadata.brand_full_version_list = GenerateBrandVersionList(
-      84, "Totally A Brand", "84.0.0.0", std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kFullVersion);
+  metadata.brand_version_list =
+      GenerateBrandVersionList(84, "Totally A Brand", "84", true,
+                               blink::UserAgentBrandVersionType::kMajorVersion);
+  metadata.brand_full_version_list =
+      GenerateBrandVersionList(84, "Totally A Brand", "84.0.0.0", true,
+                               blink::UserAgentBrandVersionType::kFullVersion);
   // 1. verify major version
   std::string brand_list_w_brand = metadata.SerializeBrandMajorVersionList();
   EXPECT_EQ(
@@ -1018,92 +959,21 @@
 TEST_F(UserAgentUtilsTest, GenerateBrandVersionListInvalidSeed) {
   // Should DCHECK on negative numbers
   EXPECT_DCHECK_DEATH(GenerateBrandVersionList(
-      -1, std::nullopt, "99", std::nullopt, std::nullopt, true,
+      -1, std::nullopt, "99", true,
       blink::UserAgentBrandVersionType::kMajorVersion));
-  EXPECT_DCHECK_DEATH(GenerateBrandVersionList(
-      -1, std::nullopt, "99.0.0.0", std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kFullVersion));
+  EXPECT_DCHECK_DEATH(
+      GenerateBrandVersionList(-1, std::nullopt, "99.0.0.0", true,
+                               blink::UserAgentBrandVersionType::kFullVersion));
 }
 
 TEST_F(UserAgentUtilsTest, GetGreasedUserAgentBrandVersionOldAlgorithm) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  // Test to ensure the old algorithm is respected when opted into.
-  scoped_feature_list.InitAndEnableFeatureWithParameters(
-      features::kGreaseUACH, {{"updated_algorithm", "false"}});
-
   blink::UserAgentBrandVersion greased_bv = GetGreasedUserAgentBrandVersion(
-      84, std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
+      84, false, blink::UserAgentBrandVersionType::kMajorVersion);
   EXPECT_EQ(greased_bv.brand, " Not A;Brand");
   EXPECT_EQ(greased_bv.version, "99");
 
   greased_bv = GetGreasedUserAgentBrandVersion(
-      84, std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kFullVersion);
-  EXPECT_EQ(greased_bv.brand, " Not A;Brand");
-  EXPECT_EQ(greased_bv.version, "99.0.0.0");
-}
-
-TEST_F(UserAgentUtilsTest,
-       GetGreasedUserAgentBrandVersionOldAlgorithmIgnoresBrandOverrides) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  // Test to ensure the old algorithm is respected when the flag is not set.
-  scoped_feature_list.InitAndEnableFeatureWithParameters(
-      features::kGreaseUACH, {{"updated_algorithm", "false"}});
-  // With the new algorithm disabled, we want to avoid experiment params
-  // ("WhatIsGrease", 1024) from taking an effect.
-  blink::UserAgentBrandVersion greased_bv = GetGreasedUserAgentBrandVersion(
-      84, "WhatIsGrease", std::nullopt, true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
-  EXPECT_EQ(greased_bv.brand, " Not A;Brand");
-  EXPECT_EQ(greased_bv.version, "99");
-
-  greased_bv = GetGreasedUserAgentBrandVersion(
-      84, "WhatIsGrease", std::nullopt, true,
-      blink::UserAgentBrandVersionType::kFullVersion);
-  EXPECT_EQ(greased_bv.brand, " Not A;Brand");
-  EXPECT_EQ(greased_bv.version, "99.0.0.0");
-}
-
-TEST_F(UserAgentUtilsTest,
-       GetGreasedUserAgentBrandVersionOldAlgorithmIgnoresVersionOverrides) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  // Test to ensure the old algorithm is respected when the flag is not set.
-  scoped_feature_list.InitAndEnableFeatureWithParameters(
-      features::kGreaseUACH, {{"updated_algorithm", "false"}});
-  // With the new algorithm disabled, we want to avoid experiment params
-  // ("WhatIsGrease", 1024) from taking an effect.
-  blink::UserAgentBrandVersion greased_bv = GetGreasedUserAgentBrandVersion(
-      84, std::nullopt, "1024", true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
-  EXPECT_EQ(greased_bv.brand, " Not A;Brand");
-  EXPECT_EQ(greased_bv.version, "99");
-
-  greased_bv = GetGreasedUserAgentBrandVersion(
-      84, std::nullopt, "1024", true,
-      blink::UserAgentBrandVersionType::kFullVersion);
-  EXPECT_EQ(greased_bv.brand, " Not A;Brand");
-  EXPECT_EQ(greased_bv.version, "99.0.0.0");
-}
-
-TEST_F(
-    UserAgentUtilsTest,
-    GetGreasedUserAgentBrandVersionOldAlgorithmIgnoresBrandAndVersionOverrides) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  // Test to ensure the old algorithm is respected when the flag is not set.
-  scoped_feature_list.InitAndEnableFeatureWithParameters(
-      features::kGreaseUACH, {{"updated_algorithm", "false"}});
-  // With the new algorithm disabled, we want to avoid experiment params
-  // ("WhatIsGrease", 1024) from taking an effect.
-  blink::UserAgentBrandVersion greased_bv = GetGreasedUserAgentBrandVersion(
-      84, "WhatIsGrease", "1024", true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
-  EXPECT_EQ(greased_bv.brand, " Not A;Brand");
-  EXPECT_EQ(greased_bv.version, "99");
-
-  greased_bv = GetGreasedUserAgentBrandVersion(
-      84, "WhatIsGrease", "1024", true,
-      blink::UserAgentBrandVersionType::kFullVersion);
+      84, false, blink::UserAgentBrandVersionType::kFullVersion);
   EXPECT_EQ(greased_bv.brand, " Not A;Brand");
   EXPECT_EQ(greased_bv.version, "99.0.0.0");
 }
@@ -1112,103 +982,38 @@
 TEST_F(UserAgentUtilsTest, GetGreasedUserAgentBrandVersionNewAlgorithm) {
   std::vector<int> permuted_order{0, 1, 2};
   blink::UserAgentBrandVersion greased_bv = GetGreasedUserAgentBrandVersion(
-      84, std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
+      84, true, blink::UserAgentBrandVersionType::kMajorVersion);
   EXPECT_EQ(greased_bv.brand, "Not;A=Brand");
   EXPECT_EQ(greased_bv.version, "8");
 
   greased_bv = GetGreasedUserAgentBrandVersion(
-      84, std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kFullVersion);
+      84, true, blink::UserAgentBrandVersionType::kFullVersion);
   EXPECT_EQ(greased_bv.brand, "Not;A=Brand");
   EXPECT_EQ(greased_bv.version, "8.0.0.0");
 }
 
-TEST_F(UserAgentUtilsTest,
-       GetGreasedUserAgentBrandVersionNewAlgorithmBrandOverride) {
-  blink::UserAgentBrandVersion greased_bv = GetGreasedUserAgentBrandVersion(
-      84, "WhatIsGrease", std::nullopt, true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
-  EXPECT_EQ(greased_bv.brand, "WhatIsGrease");
-  EXPECT_EQ(greased_bv.version, "8");
-
-  greased_bv = GetGreasedUserAgentBrandVersion(
-      84, "WhatIsGrease", std::nullopt, true,
-      blink::UserAgentBrandVersionType::kFullVersion);
-  EXPECT_EQ(greased_bv.brand, "WhatIsGrease");
-  EXPECT_EQ(greased_bv.version, "8.0.0.0");
-}
-
-TEST_F(UserAgentUtilsTest,
-       GetGreasedUserAgentBrandVersionNewAlgorithmVersionOverride) {
-  std::vector<int> permuted_order{0, 1, 2};
-  blink::UserAgentBrandVersion greased_bv = GetGreasedUserAgentBrandVersion(
-      84, std::nullopt, "1024", true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
-  EXPECT_EQ(greased_bv.brand, "Not;A=Brand");
-  EXPECT_EQ(greased_bv.version, "1024");
-
-  greased_bv = GetGreasedUserAgentBrandVersion(
-      84, std::nullopt, "1024", true,
-      blink::UserAgentBrandVersionType::kFullVersion);
-  EXPECT_EQ(greased_bv.brand, "Not;A=Brand");
-  EXPECT_EQ(greased_bv.version, "1024.0.0.0");
-}
-
-TEST_F(UserAgentUtilsTest,
-       GetGreasedUserAgentBrandVersionNewAlgorithmBrandAndVersionOverride) {
-  blink::UserAgentBrandVersion greased_bv = GetGreasedUserAgentBrandVersion(
-      84, "WhatIsGrease", "1024", true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
-  EXPECT_EQ(greased_bv.brand, "WhatIsGrease");
-  EXPECT_EQ(greased_bv.version, "1024");
-
-  greased_bv = GetGreasedUserAgentBrandVersion(
-      84, "WhatIsGrease", "1024", true,
-      blink::UserAgentBrandVersionType::kFullVersion);
-  EXPECT_EQ(greased_bv.brand, "WhatIsGrease");
-  EXPECT_EQ(greased_bv.version, "1024.0.0.0");
-}
-
 TEST_F(UserAgentUtilsTest, GetGreasedUserAgentBrandVersionFullVersions) {
   blink::UserAgentBrandVersion greased_bv = GetGreasedUserAgentBrandVersion(
-      86, std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
+      86, true, blink::UserAgentBrandVersionType::kMajorVersion);
   EXPECT_EQ(greased_bv.brand, "Not?A_Brand");
   EXPECT_EQ(greased_bv.version, "24");
 
   greased_bv = GetGreasedUserAgentBrandVersion(
-      86, std::nullopt, std::nullopt, true,
-      blink::UserAgentBrandVersionType::kFullVersion);
+      86, true, blink::UserAgentBrandVersionType::kFullVersion);
   EXPECT_EQ(greased_bv.brand, "Not?A_Brand");
   EXPECT_EQ(greased_bv.version, "24.0.0.0");
-
-  // Test the greasy input with full version
-  greased_bv = GetGreasedUserAgentBrandVersion(
-      84, std::nullopt, "1024.0.0.0", true,
-      blink::UserAgentBrandVersionType::kMajorVersion);
-  EXPECT_EQ(greased_bv.brand, "Not;A=Brand");
-  EXPECT_EQ(greased_bv.version, "1024");
-
-  greased_bv = GetGreasedUserAgentBrandVersion(
-      84, std::nullopt, "1024.0.0.0", true,
-      blink::UserAgentBrandVersionType::kFullVersion);
-  EXPECT_EQ(greased_bv.brand, "Not;A=Brand");
-  EXPECT_EQ(greased_bv.version, "1024.0.0.0");
 }
 
 TEST_F(UserAgentUtilsTest, GetGreasedUserAgentBrandVersionEnterpriseOverride) {
   // Ensure the enterprise override bool can force the old GREASE algorithm to
   // be used.
   blink::UserAgentBrandVersion greased_bv = GetGreasedUserAgentBrandVersion(
-      84, std::nullopt, std::nullopt, false,
-      blink::UserAgentBrandVersionType::kMajorVersion);
+      84, false, blink::UserAgentBrandVersionType::kMajorVersion);
   EXPECT_EQ(greased_bv.brand, " Not A;Brand");
   EXPECT_EQ(greased_bv.version, "99");
 
   greased_bv = GetGreasedUserAgentBrandVersion(
-      84, std::nullopt, std::nullopt, false,
-      blink::UserAgentBrandVersionType::kFullVersion);
+      84, false, blink::UserAgentBrandVersionType::kFullVersion);
   EXPECT_EQ(greased_bv.brand, " Not A;Brand");
   EXPECT_EQ(greased_bv.version, "99.0.0.0");
 }
@@ -1219,14 +1024,12 @@
   // Ensure the enterprise override bool can force the old GREASE algorithm to
   // be used and supersedes passed-in brand/version overrides.
   blink::UserAgentBrandVersion greased_bv = GetGreasedUserAgentBrandVersion(
-      84, "helloWorld", "100000", false,
-      blink::UserAgentBrandVersionType::kMajorVersion);
+      84, false, blink::UserAgentBrandVersionType::kMajorVersion);
   EXPECT_EQ(greased_bv.brand, " Not A;Brand");
   EXPECT_EQ(greased_bv.version, "99");
 
   greased_bv = GetGreasedUserAgentBrandVersion(
-      84, "helloWorld", "100000", false,
-      blink::UserAgentBrandVersionType::kFullVersion);
+      84, false, blink::UserAgentBrandVersionType::kFullVersion);
   EXPECT_EQ(greased_bv.brand, " Not A;Brand");
   EXPECT_EQ(greased_bv.version, "99.0.0.0");
 }
@@ -1238,13 +1041,11 @@
     // Regardless of the major version seed, the spec calls for no leading
     // whitespace in the brand.
     greased_bv = GetGreasedUserAgentBrandVersion(
-        i, std::nullopt, std::nullopt, true,
-        blink::UserAgentBrandVersionType::kMajorVersion);
+        i, true, blink::UserAgentBrandVersionType::kMajorVersion);
     EXPECT_NE(greased_bv.brand[0], ' ');
 
     greased_bv = GetGreasedUserAgentBrandVersion(
-        i, std::nullopt, std::nullopt, true,
-        blink::UserAgentBrandVersionType::kFullVersion);
+        i, true, blink::UserAgentBrandVersionType::kFullVersion);
     EXPECT_NE(greased_bv.brand[0], ' ');
   }
 }
diff --git a/components/facilitated_payments/core/browser/ewallet_manager.cc b/components/facilitated_payments/core/browser/ewallet_manager.cc
index 4cfca7b7..935604be0 100644
--- a/components/facilitated_payments/core/browser/ewallet_manager.cc
+++ b/components/facilitated_payments/core/browser/ewallet_manager.cc
@@ -168,11 +168,16 @@
 
   initiate_payment_request_details_->risk_data_ = risk_data;
 
-  GetApiClient()->GetClientToken(base::BindOnce(
-      &EwalletManager::OnGetClientToken, weak_ptr_factory_.GetWeakPtr()));
+  GetApiClient()->GetClientToken(
+      base::BindOnce(&EwalletManager::OnGetClientToken,
+                     weak_ptr_factory_.GetWeakPtr(), base::TimeTicks::Now()));
 }
 
-void EwalletManager::OnGetClientToken(std::vector<uint8_t> client_token) {
+void EwalletManager::OnGetClientToken(base::TimeTicks start_time,
+                                      std::vector<uint8_t> client_token) {
+  LogGetClientTokenResultAndLatency(kPaymentsType, !client_token.empty(),
+                                    (base::TimeTicks::Now() - start_time),
+                                    scheme_);
   if (client_token.empty()) {
     client_->ShowErrorScreen();
     return;
diff --git a/components/facilitated_payments/core/browser/ewallet_manager.h b/components/facilitated_payments/core/browser/ewallet_manager.h
index 45da4f60..0a508c6 100644
--- a/components/facilitated_payments/core/browser/ewallet_manager.h
+++ b/components/facilitated_payments/core/browser/ewallet_manager.h
@@ -87,7 +87,9 @@
 
   // Called after retrieving the client token from the facilitated payment API.
   // If not empty, the client token can be used for initiating payment.
-  void OnGetClientToken(std::vector<uint8_t> client_token);
+  // The call was made at `start_time`.
+  void OnGetClientToken(base::TimeTicks start_time,
+                        std::vector<uint8_t> client_token);
 
   // Makes a payment request to the Payments server after the user has selected
   // the eWallet for making the payment.
diff --git a/components/facilitated_payments/core/browser/ewallet_manager_test_api.h b/components/facilitated_payments/core/browser/ewallet_manager_test_api.h
index 7127f4e..755cd1a 100644
--- a/components/facilitated_payments/core/browser/ewallet_manager_test_api.h
+++ b/components/facilitated_payments/core/browser/ewallet_manager_test_api.h
@@ -54,8 +54,9 @@
     ewallet_manager_->OnRiskDataLoaded(start_time, risk_data);
   }
 
-  void OnGetClientToken(std::vector<uint8_t> client_token) {
-    ewallet_manager_->OnGetClientToken(client_token);
+  void OnGetClientToken(base::TimeTicks start_time,
+                        std::vector<uint8_t> client_token) {
+    ewallet_manager_->OnGetClientToken(start_time, client_token);
   }
 
   FacilitatedPaymentsInitiatePaymentRequestDetails*
diff --git a/components/facilitated_payments/core/browser/ewallet_manager_unittest.cc b/components/facilitated_payments/core/browser/ewallet_manager_unittest.cc
index d53e2d99..3f1794a 100644
--- a/components/facilitated_payments/core/browser/ewallet_manager_unittest.cc
+++ b/components/facilitated_payments/core/browser/ewallet_manager_unittest.cc
@@ -357,7 +357,35 @@
 TEST_F(EwalletManagerTest, OnGetClientToken_ClientTokenEmpty_ErrorScreenShown) {
   EXPECT_CALL(client_, ShowErrorScreen);
 
-  test_api(*ewallet_manager_).OnGetClientToken(std::vector<uint8_t>{});
+  test_api(*ewallet_manager_)
+      .OnGetClientToken(base::TimeTicks::Now() - base::Seconds(2),
+                        std::vector<uint8_t>{});
+}
+
+// Test that GetClientToken related metrics are logged correctly.
+TEST_F(EwalletManagerTest, LogGetClientTokenResultAndLatency) {
+  for (bool get_client_token_result : {true, false}) {
+    base::HistogramTester histogram_tester;
+
+    test_api(*ewallet_manager_)
+        .OnGetClientToken(base::TimeTicks::Now() - base::Seconds(2),
+                          get_client_token_result
+                              ? std::vector<uint8_t>{'t', 'o', 'k', 'e', 'n'}
+                              : std::vector<uint8_t>{});
+
+    std::string result = get_client_token_result ? "Success" : "Failure";
+
+    histogram_tester.ExpectUniqueSample(
+        base::StrCat({"FacilitatedPayments.Ewallet.GetClientToken.", result,
+                      ".Latency"}),
+        /*sample=*/2000,
+        /*expected_bucket_count=*/1);
+    histogram_tester.ExpectUniqueSample(
+        base::StrCat({"FacilitatedPayments.Ewallet.GetClientToken.", result,
+                      ".Latency.ShopeePay"}),
+        /*sample=*/2000,
+        /*expected_bucket_count=*/1);
+  }
 }
 
 // Test that SendInitiatePaymentRequest doesn't initiates payment when
diff --git a/components/facilitated_payments/core/browser/facilitated_payments_manager.cc b/components/facilitated_payments/core/browser/facilitated_payments_manager.cc
index 11c97461..90c54f417 100644
--- a/components/facilitated_payments/core/browser/facilitated_payments_manager.cc
+++ b/components/facilitated_payments/core/browser/facilitated_payments_manager.cc
@@ -231,7 +231,7 @@
 void FacilitatedPaymentsManager::OnGetClientToken(
     std::vector<uint8_t> client_token) {
   LogGetClientTokenResultAndLatency(
-      !client_token.empty(),
+      kPaymentsType, !client_token.empty(),
       (base::TimeTicks::Now() - get_client_token_loading_start_time_));
   if (client_token.empty()) {
     ShowErrorScreen();
diff --git a/components/facilitated_payments/core/metrics/facilitated_payments_metrics.cc b/components/facilitated_payments/core/metrics/facilitated_payments_metrics.cc
index 926a447..a886242d 100644
--- a/components/facilitated_payments/core/metrics/facilitated_payments_metrics.cc
+++ b/components/facilitated_payments/core/metrics/facilitated_payments_metrics.cc
@@ -144,11 +144,24 @@
   }
 }
 
-void LogGetClientTokenResultAndLatency(bool result, base::TimeDelta duration) {
+void LogGetClientTokenResultAndLatency(
+    FacilitatedPaymentsType payment_type,
+    bool result,
+    base::TimeDelta duration,
+    std::optional<PaymentLinkValidator::Scheme> scheme) {
   base::UmaHistogramLongTimes(
-      base::StrCat({"FacilitatedPayments.Pix.GetClientToken.",
-                    result ? "Success" : "Failure", ".Latency"}),
+      base::StrCat({"FacilitatedPayments.", PaymentTypeToString(payment_type),
+                    ".GetClientToken.", ResultToString(result), ".Latency"}),
       duration);
+  if (payment_type == FacilitatedPaymentsType::kEwallet) {
+    CHECK(scheme.has_value());
+    CHECK_NE(PaymentLinkValidator::Scheme::kInvalid, *scheme);
+    base::UmaHistogramLongTimes(
+        base::StrCat({"FacilitatedPayments.Ewallet.GetClientToken.",
+                      ResultToString(result), ".Latency.",
+                      SchemeToString(*scheme)}),
+        duration);
+  }
 }
 
 void LogPayflowExitedReason(PayflowExitedReason reason) {
diff --git a/components/facilitated_payments/core/metrics/facilitated_payments_metrics.h b/components/facilitated_payments/core/metrics/facilitated_payments_metrics.h
index d6cf4367..c3a8377 100644
--- a/components/facilitated_payments/core/metrics/facilitated_payments_metrics.h
+++ b/components/facilitated_payments/core/metrics/facilitated_payments_metrics.h
@@ -113,7 +113,14 @@
     std::optional<PaymentLinkValidator::Scheme> scheme = std::nullopt);
 
 // Log the result and the latency of the GetClientToken call made to api client.
-void LogGetClientTokenResultAndLatency(bool result, base::TimeDelta duration);
+// `payment_type` must be either `kEwallet` or `kPix`.
+// The `scheme` parameter is required for the 'kEwallet' payment type and should
+// not be `kInvalid`.
+void LogGetClientTokenResultAndLatency(
+    FacilitatedPaymentsType payment_type,
+    bool result,
+    base::TimeDelta duration,
+    std::optional<PaymentLinkValidator::Scheme> scheme = std::nullopt);
 
 // Log the reason for the payflow was exited early. This includes all the
 // reasons after receiving a signal from the renderer process that a valid code
diff --git a/components/facilitated_payments/core/metrics/facilitated_payments_metrics_unittest.cc b/components/facilitated_payments/core/metrics/facilitated_payments_metrics_unittest.cc
index 1ea7c76..19ae4b8 100644
--- a/components/facilitated_payments/core/metrics/facilitated_payments_metrics_unittest.cc
+++ b/components/facilitated_payments/core/metrics/facilitated_payments_metrics_unittest.cc
@@ -77,17 +77,6 @@
       /*expected_bucket_count=*/1);
 }
 
-TEST(FacilitatedPaymentsMetricsTest, LogGetClientTokenResultAndLatency) {
-  base::HistogramTester histogram_tester;
-
-  LogGetClientTokenResultAndLatency(/*result=*/true, base::Milliseconds(10));
-
-  histogram_tester.ExpectUniqueSample(
-      "FacilitatedPayments.Pix.GetClientToken.Success.Latency",
-      /*sample=*/10,
-      /*expected_bucket_count=*/1);
-}
-
 TEST(FacilitatedPaymentsMetricsTest, LogInitiatePaymentAttempt) {
   base::HistogramTester histogram_tester;
 
@@ -335,6 +324,52 @@
 }
 
 TEST_P(FacilitatedPaymentsMetricsParameterizedTest,
+       LogGetClientTokenResultAndLatency_Success) {
+  base::HistogramTester histogram_tester;
+
+  LogGetClientTokenResultAndLatency(payment_type(), /*result=*/true,
+                                    base::Milliseconds(10), scheme());
+
+  histogram_tester.ExpectUniqueSample(
+      base::StrCat({"FacilitatedPayments.", GetFacilitatedPaymentsTypeString(),
+                    ".GetClientToken.Success.Latency"}),
+      /*sample=*/10,
+      /*expected_bucket_count=*/1);
+  histogram_tester.ExpectUniqueSample(
+      base::StrCat(
+          {"FacilitatedPayments.Ewallet.GetClientToken.Success.Latency.",
+           GetSchemeString()}),
+      /*sample=*/10,
+      /*expected_bucket_count=*/payment_type() ==
+              FacilitatedPaymentsType::kEwallet
+          ? 1
+          : 0);
+}
+
+TEST_P(FacilitatedPaymentsMetricsParameterizedTest,
+       LogGetClientTokenResultAndLatency_Failure) {
+  base::HistogramTester histogram_tester;
+
+  LogGetClientTokenResultAndLatency(payment_type(), /*result=*/false,
+                                    base::Milliseconds(10), scheme());
+
+  histogram_tester.ExpectUniqueSample(
+      base::StrCat({"FacilitatedPayments.", GetFacilitatedPaymentsTypeString(),
+                    ".GetClientToken.Failure.Latency"}),
+      /*sample=*/10,
+      /*expected_bucket_count=*/1);
+  histogram_tester.ExpectUniqueSample(
+      base::StrCat(
+          {"FacilitatedPayments.Ewallet.GetClientToken.Failure.Latency.",
+           GetSchemeString()}),
+      /*sample=*/10,
+      /*expected_bucket_count=*/payment_type() ==
+              FacilitatedPaymentsType::kEwallet
+          ? 1
+          : 0);
+}
+
+TEST_P(FacilitatedPaymentsMetricsParameterizedTest,
        LogLoadRiskDataResult_Success) {
   base::HistogramTester histogram_tester;
 
diff --git a/components/leveldb_proto/internal/proto_leveldb_wrapper.h b/components/leveldb_proto/internal/proto_leveldb_wrapper.h
index 81345ef..8826c2f 100644
--- a/components/leveldb_proto/internal/proto_leveldb_wrapper.h
+++ b/components/leveldb_proto/internal/proto_leveldb_wrapper.h
@@ -151,7 +151,7 @@
   // Used to run blocking tasks in-order, must be the TaskRunner that |db_|
   // relies on.
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
-  raw_ptr<LevelDB, AcrossTasksDanglingUntriaged> db_ = nullptr;
+  raw_ptr<LevelDB> db_ = nullptr;
 
   // The identifier used when recording metrics to determine the source of the
   // LevelDB calls, likely the database client name.
diff --git a/components/leveldb_proto/internal/unique_proto_database_unittest.cc b/components/leveldb_proto/internal/unique_proto_database_unittest.cc
index 0afe16c..240bd27 100644
--- a/components/leveldb_proto/internal/unique_proto_database_unittest.cc
+++ b/components/leveldb_proto/internal/unique_proto_database_unittest.cc
@@ -224,24 +224,33 @@
   }
 }
 
-class UniqueProtoDatabaseTest : public testing::Test {
+// RAII wrapper around `ProtoDatabaseImpl<TestProto>` that waits for posted
+// tasks to complete when destroyed.
+class ScopedProtoDatabase {
  public:
-  UniqueProtoDatabaseTest()
-      : options_(MakeMatcher(new OptionsEqMatcher(CreateSimpleOptions()))) {}
-  void SetUp() override {
-    db_ = std::make_unique<ProtoDatabaseImpl<TestProto>>(
-        ProtoDbType::TEST_DATABASE0, base::FilePath(),
-        base::SingleThreadTaskRunner::GetCurrentDefault());
-  }
-
-  void TearDown() override {
+  ScopedProtoDatabase()
+      : db_(std::make_unique<ProtoDatabaseImpl<TestProto>>(
+            ProtoDbType::TEST_DATABASE0,
+            base::FilePath(),
+            base::SingleThreadTaskRunner::GetCurrentDefault())) {}
+  ~ScopedProtoDatabase() {
     db_.reset();
     base::RunLoop().RunUntilIdle();
   }
 
+  ProtoDatabaseImpl<TestProto>* operator->() { return db_.get(); }
+
+ private:
+  std::unique_ptr<ProtoDatabaseImpl<TestProto>> db_;
+};
+
+class UniqueProtoDatabaseTest : public testing::Test {
+ public:
+  UniqueProtoDatabaseTest()
+      : options_(MakeMatcher(new OptionsEqMatcher(CreateSimpleOptions()))) {}
+
   const Matcher<const Options&> options_;
   TaskEnvironment task_environment_;
-  std::unique_ptr<ProtoDatabaseImpl<TestProto>> db_;
 };
 
 // Test that UniqueProtoDatabase calls Init on the underlying database and that
@@ -256,9 +265,10 @@
   MockDatabaseCaller caller;
   EXPECT_CALL(caller, InitStatusCallback(Enums::InitStatus::kOK));
 
-  db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
-                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
-                                       base::Unretained(&caller)));
+  ScopedProtoDatabase db;
+  db->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
+                       base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                                      base::Unretained(&caller)));
 
   base::RunLoop().RunUntilIdle();
 }
@@ -276,9 +286,10 @@
   MockDatabaseCaller caller;
   EXPECT_CALL(caller, InitStatusCallback(Enums::InitStatus::kError));
 
-  db_->InitWithDatabase(mock_db.get(), path, options,
-                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
-                                       base::Unretained(&caller)));
+  ScopedProtoDatabase db;
+  db->InitWithDatabase(mock_db.get(), path, options,
+                       base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                                      base::Unretained(&caller)));
 
   base::RunLoop().RunUntilIdle();
 }
@@ -293,13 +304,14 @@
   MockDatabaseCaller caller;
   EXPECT_CALL(caller, InitStatusCallback(Enums::InitStatus::kOK));
 
-  db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
-                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
-                                       base::Unretained(&caller)));
+  ScopedProtoDatabase db;
+  db->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
+                       base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                                      base::Unretained(&caller)));
 
   EXPECT_CALL(caller, DestroyCallback(true));
-  db_->Destroy(base::BindOnce(&MockDatabaseCaller::DestroyCallback,
-                              base::Unretained(&caller)));
+  db->Destroy(base::BindOnce(&MockDatabaseCaller::DestroyCallback,
+                             base::Unretained(&caller)));
   EXPECT_CALL(*mock_db, Destroy()).WillOnce(Return(leveldb::Status()));
 
   base::RunLoop().RunUntilIdle();
@@ -315,13 +327,14 @@
   MockDatabaseCaller caller;
   EXPECT_CALL(caller, InitStatusCallback(Enums::InitStatus::kOK));
 
-  db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
-                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
-                                       base::Unretained(&caller)));
+  ScopedProtoDatabase db;
+  db->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
+                       base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                                      base::Unretained(&caller)));
 
   EXPECT_CALL(caller, DestroyCallback(false));
-  db_->Destroy(base::BindOnce(&MockDatabaseCaller::DestroyCallback,
-                              base::Unretained(&caller)));
+  db->Destroy(base::BindOnce(&MockDatabaseCaller::DestroyCallback,
+                             base::Unretained(&caller)));
   EXPECT_CALL(*mock_db, Destroy())
       .WillOnce(
           Return(leveldb::Status::IOError(leveldb::Slice(), leveldb::Slice())));
@@ -371,15 +384,16 @@
 
   EXPECT_CALL(*mock_db, Init(_, options_, _));
   EXPECT_CALL(caller, InitStatusCallback(_));
-  db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
-                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
-                                       base::Unretained(&caller)));
+  ScopedProtoDatabase db;
+  db->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
+                       base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                                      base::Unretained(&caller)));
 
   EXPECT_CALL(*mock_db, LoadKeysAndEntriesWhile(_, _, _, _))
       .WillOnce(AppendLoadKeysAndEntries(model));
   EXPECT_CALL(caller, LoadKeysAndEntriesCallback1(true, _))
       .WillOnce(VerifyLoadKeysAndEntries(testing::ByRef(model)));
-  db_->LoadKeysAndEntries(
+  db->LoadKeysAndEntries(
       base::BindOnce(&MockDatabaseCaller::LoadKeysAndEntriesCallback,
                      base::Unretained(&caller)));
 
@@ -394,14 +408,15 @@
 
   EXPECT_CALL(*mock_db, Init(_, options_, _));
   EXPECT_CALL(caller, InitStatusCallback(_));
-  db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
-                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
-                                       base::Unretained(&caller)));
+  ScopedProtoDatabase db;
+  db->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
+                       base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                                      base::Unretained(&caller)));
 
   EXPECT_CALL(*mock_db, LoadWithFilter(_, _, _, _)).WillOnce(Return(false));
   EXPECT_CALL(caller, LoadCallback1(false, _));
-  db_->LoadEntries(base::BindOnce(&MockDatabaseCaller::LoadCallback,
-                                  base::Unretained(&caller)));
+  db->LoadEntries(base::BindOnce(&MockDatabaseCaller::LoadCallback,
+                                 base::Unretained(&caller)));
 
   base::RunLoop().RunUntilIdle();
 }
@@ -419,9 +434,11 @@
   expected["d"] = model["d"];
 
   EXPECT_CALL(caller, InitStatusCallback(_));
-  db_->InitWithDatabase(db.get(), temp_dir.GetPath(), CreateSimpleOptions(),
-                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
-                                       base::Unretained(&caller)));
+  ScopedProtoDatabase proto_db;
+  proto_db->InitWithDatabase(
+      db.get(), temp_dir.GetPath(), CreateSimpleOptions(),
+      base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                     base::Unretained(&caller)));
 
   auto save_entries =
       std::make_unique<ProtoDatabase<TestProto>::KeyEntryVector>();
@@ -433,14 +450,14 @@
 
   leveldb::Status status;
   EXPECT_CALL(caller, SaveCallback(true));
-  db_->UpdateEntries(std::move(save_entries), std::move(remove_keys),
-                     base::BindOnce(&MockDatabaseCaller::SaveCallback,
-                                    base::Unretained(&caller)));
+  proto_db->UpdateEntries(std::move(save_entries), std::move(remove_keys),
+                          base::BindOnce(&MockDatabaseCaller::SaveCallback,
+                                         base::Unretained(&caller)));
   base::RunLoop().RunUntilIdle();
 
   EXPECT_CALL(caller, LoadKeysAndEntriesCallback1(true, _))
       .WillOnce(VerifyLoadKeysAndEntries(testing::ByRef(expected)));
-  db_->LoadKeysAndEntriesInRange(
+  proto_db->LoadKeysAndEntriesInRange(
       "b", "d",
       base::BindOnce(&MockDatabaseCaller::LoadKeysAndEntriesCallback,
                      base::Unretained(&caller)));
@@ -460,9 +477,11 @@
   expected["d"] = model["d"];
 
   EXPECT_CALL(caller, InitStatusCallback(_));
-  db_->InitWithDatabase(db.get(), temp_dir.GetPath(), CreateSimpleOptions(),
-                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
-                                       base::Unretained(&caller)));
+  ScopedProtoDatabase proto_db;
+  proto_db->InitWithDatabase(
+      db.get(), temp_dir.GetPath(), CreateSimpleOptions(),
+      base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                     base::Unretained(&caller)));
 
   auto save_entries =
       std::make_unique<ProtoDatabase<TestProto>::KeyEntryVector>();
@@ -475,14 +494,14 @@
 
   leveldb::Status status;
   EXPECT_CALL(caller, SaveCallback(true));
-  db_->UpdateEntries(std::move(save_entries), std::move(remove_keys),
-                     base::BindOnce(&MockDatabaseCaller::SaveCallback,
-                                    base::Unretained(&caller)));
+  proto_db->UpdateEntries(std::move(save_entries), std::move(remove_keys),
+                          base::BindOnce(&MockDatabaseCaller::SaveCallback,
+                                         base::Unretained(&caller)));
   base::RunLoop().RunUntilIdle();
 
   EXPECT_CALL(caller, LoadKeysAndEntriesCallback1(true, _))
       .WillOnce(VerifyLoadKeysAndEntries(testing::ByRef(expected)));
-  db_->LoadKeysAndEntriesInRange(
+  proto_db->LoadKeysAndEntriesInRange(
       "d", "d",
       base::BindOnce(&MockDatabaseCaller::LoadKeysAndEntriesCallback,
                      base::Unretained(&caller)));
@@ -518,17 +537,18 @@
 
   EXPECT_CALL(*mock_db, Init(_, options_, _));
   EXPECT_CALL(caller, InitStatusCallback(_));
-  db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
-                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
-                                       base::Unretained(&caller)));
+  ScopedProtoDatabase db;
+  db->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
+                       base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                                      base::Unretained(&caller)));
 
   std::string key("1");
   ASSERT_TRUE(model.count(key));
   EXPECT_CALL(*mock_db, Get(key, _, _, _)).WillOnce(SetGetEntry(model));
   EXPECT_CALL(caller, GetCallback1(true, _))
       .WillOnce(VerifyGetEntry(model[key]));
-  db_->GetEntry(key, base::BindOnce(&MockDatabaseCaller::GetCallback,
-                                    base::Unretained(&caller)));
+  db->GetEntry(key, base::BindOnce(&MockDatabaseCaller::GetCallback,
+                                   base::Unretained(&caller)));
 
   base::RunLoop().RunUntilIdle();
 }
@@ -544,9 +564,10 @@
   EXPECT_CALL(*mock_db, UpdateWithRemoveFilter(_, _, kTestPrefix, _))
       .WillOnce(Return(true));
   EXPECT_CALL(caller, InitStatusCallback(_));
-  db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
-                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
-                                       base::Unretained(&caller)));
+  ScopedProtoDatabase db;
+  db->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
+                       base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                                      base::Unretained(&caller)));
 
   base::RunLoop().RunUntilIdle();
 
@@ -557,7 +578,7 @@
         std::move(signal).Run();
       },
       run_update_entries.QuitClosure());
-  db_->RemoveKeysForTesting(
+  db->RemoveKeysForTesting(
       base::BindRepeating([](const std::string& str) { return true; }),
       kTestPrefix, std::move(expect_update_success));
   run_update_entries.Run();
@@ -632,16 +653,17 @@
 
   EXPECT_CALL(*mock_db, Init(_, options_, _));
   EXPECT_CALL(caller, InitStatusCallback(_));
-  db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
-                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
-                                       base::Unretained(&caller)));
+  ScopedProtoDatabase db;
+  db->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
+                       base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                                      base::Unretained(&caller)));
 
   std::string key("does_not_exist");
   ASSERT_FALSE(model.count(key));
   EXPECT_CALL(*mock_db, Get(key, _, _, _)).WillOnce(SetGetEntry(model));
   EXPECT_CALL(caller, GetCallback1(true, nullptr));
-  db_->GetEntry(key, base::BindOnce(&MockDatabaseCaller::GetCallback,
-                                    base::Unretained(&caller)));
+  db->GetEntry(key, base::BindOnce(&MockDatabaseCaller::GetCallback,
+                                   base::Unretained(&caller)));
 
   base::RunLoop().RunUntilIdle();
 }
@@ -655,16 +677,17 @@
 
   EXPECT_CALL(*mock_db, Init(_, options_, _));
   EXPECT_CALL(caller, InitStatusCallback(_));
-  db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
-                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
-                                       base::Unretained(&caller)));
+  ScopedProtoDatabase db;
+  db->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
+                       base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                                      base::Unretained(&caller)));
 
   std::string key("does_not_exist");
   ASSERT_FALSE(model.count(key));
   EXPECT_CALL(*mock_db, Get(key, _, _, _)).WillOnce(Return(false));
   EXPECT_CALL(caller, GetCallback1(false, nullptr));
-  db_->GetEntry(key, base::BindOnce(&MockDatabaseCaller::GetCallback,
-                                    base::Unretained(&caller)));
+  db->GetEntry(key, base::BindOnce(&MockDatabaseCaller::GetCallback,
+                                   base::Unretained(&caller)));
 
   base::RunLoop().RunUntilIdle();
 }
@@ -700,9 +723,10 @@
 
   EXPECT_CALL(*mock_db, Init(_, options_, _));
   EXPECT_CALL(caller, InitStatusCallback(_));
-  db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
-                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
-                                       base::Unretained(&caller)));
+  ScopedProtoDatabase db;
+  db->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
+                       base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                                      base::Unretained(&caller)));
 
   std::unique_ptr<ProtoDatabase<TestProto>::KeyEntryVector> entries(
       new ProtoDatabase<TestProto>::KeyEntryVector());
@@ -713,9 +737,9 @@
 
   EXPECT_CALL(*mock_db, Save(_, _, _)).WillOnce(VerifyUpdateEntries(model));
   EXPECT_CALL(caller, SaveCallback(true));
-  db_->UpdateEntries(std::move(entries), std::move(keys_to_remove),
-                     base::BindOnce(&MockDatabaseCaller::SaveCallback,
-                                    base::Unretained(&caller)));
+  db->UpdateEntries(std::move(entries), std::move(keys_to_remove),
+                    base::BindOnce(&MockDatabaseCaller::SaveCallback,
+                                   base::Unretained(&caller)));
 
   base::RunLoop().RunUntilIdle();
 }
@@ -731,15 +755,16 @@
 
   EXPECT_CALL(*mock_db, Init(_, options_, _));
   EXPECT_CALL(caller, InitStatusCallback(_));
-  db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
-                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
-                                       base::Unretained(&caller)));
+  ScopedProtoDatabase db;
+  db->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
+                       base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                                      base::Unretained(&caller)));
 
   EXPECT_CALL(*mock_db, Save(_, _, _)).WillOnce(Return(false));
   EXPECT_CALL(caller, SaveCallback(false));
-  db_->UpdateEntries(std::move(entries), std::move(keys_to_remove),
-                     base::BindOnce(&MockDatabaseCaller::SaveCallback,
-                                    base::Unretained(&caller)));
+  db->UpdateEntries(std::move(entries), std::move(keys_to_remove),
+                    base::BindOnce(&MockDatabaseCaller::SaveCallback,
+                                   base::Unretained(&caller)));
 
   base::RunLoop().RunUntilIdle();
 }
@@ -756,9 +781,10 @@
 
   EXPECT_CALL(*mock_db, Init(_, options_, _));
   EXPECT_CALL(caller, InitStatusCallback(_));
-  db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
-                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
-                                       base::Unretained(&caller)));
+  ScopedProtoDatabase db;
+  db->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
+                       base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                                      base::Unretained(&caller)));
 
   std::unique_ptr<ProtoDatabase<TestProto>::KeyEntryVector> entries(
       new ProtoDatabase<TestProto>::KeyEntryVector());
@@ -769,9 +795,9 @@
   KeyVector keys_copy(*keys_to_remove.get());
   EXPECT_CALL(*mock_db, Save(_, keys_copy, _)).WillOnce(Return(true));
   EXPECT_CALL(caller, SaveCallback(true));
-  db_->UpdateEntries(std::move(entries), std::move(keys_to_remove),
-                     base::BindOnce(&MockDatabaseCaller::SaveCallback,
-                                    base::Unretained(&caller)));
+  db->UpdateEntries(std::move(entries), std::move(keys_to_remove),
+                    base::BindOnce(&MockDatabaseCaller::SaveCallback,
+                                   base::Unretained(&caller)));
 
   base::RunLoop().RunUntilIdle();
 }
@@ -787,15 +813,16 @@
 
   EXPECT_CALL(*mock_db, Init(_, options_, _));
   EXPECT_CALL(caller, InitStatusCallback(_));
-  db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
-                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
-                                       base::Unretained(&caller)));
+  ScopedProtoDatabase db;
+  db->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(),
+                       base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                                      base::Unretained(&caller)));
 
   EXPECT_CALL(*mock_db, Save(_, _, _)).WillOnce(Return(false));
   EXPECT_CALL(caller, SaveCallback(false));
-  db_->UpdateEntries(std::move(entries), std::move(keys_to_remove),
-                     base::BindOnce(&MockDatabaseCaller::SaveCallback,
-                                    base::Unretained(&caller)));
+  db->UpdateEntries(std::move(entries), std::move(keys_to_remove),
+                    base::BindOnce(&MockDatabaseCaller::SaveCallback,
+                                   base::Unretained(&caller)));
 
   base::RunLoop().RunUntilIdle();
 }
diff --git a/components/live_caption/BUILD.gn b/components/live_caption/BUILD.gn
index e43d34d..770625c 100644
--- a/components/live_caption/BUILD.gn
+++ b/components/live_caption/BUILD.gn
@@ -12,6 +12,8 @@
       "caption_bubble_context_remote.h",
       "caption_bubble_controller.h",
       "caption_bubble_session_observer.h",
+      "live_caption_controller.cc",
+      "live_caption_controller.h",
     ]
 
     deps = [
@@ -57,20 +59,6 @@
         "//ui/views",
       ]
     }  # toolkit_views
-
-    if (is_chromeos_ash) {
-      sources += [
-        "live_caption_ui_remote_driver.cc",
-        "live_caption_ui_remote_driver.h",
-      ]
-    }  # is_chromeos_ash
-
-    if (!is_chromeos_lacros) {
-      sources += [
-        "live_caption_controller.cc",
-        "live_caption_controller.h",
-      ]
-    }
   }
 
   static_library("live_translate") {
@@ -122,7 +110,7 @@
       "//ui/gfx/geometry:geometry",
     ]
 
-    if (is_chromeos_ash) {
+    if (is_chromeos) {
       sources += [
         "caption_bubble_context_remote_unittest.cc",
 
diff --git a/components/live_caption/caption_util.cc b/components/live_caption/caption_util.cc
index 6c1797a..51856708 100644
--- a/components/live_caption/caption_util.cc
+++ b/components/live_caption/caption_util.cc
@@ -13,7 +13,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/live_caption/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "ui/base/ui_base_switches.h"
diff --git a/components/live_caption/live_caption_controller.cc b/components/live_caption/live_caption_controller.cc
index bea19ca4..b5f34a9f 100644
--- a/components/live_caption/live_caption_controller.cc
+++ b/components/live_caption/live_caption_controller.cc
@@ -118,7 +118,7 @@
       prefs::kLiveCaptionMediaFoundationRendererErrorSilenced,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   // Flags for User Microphone Captioning are only available on ash.
   registry->RegisterBooleanPref(prefs::kLiveCaptionUserMicrophoneEnabled,
                                 false);
@@ -156,7 +156,7 @@
 }
 
 bool LiveCaptionController::IsLiveCaptionEnabled() {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   return enabled_for_babel_orca_ ||
          profile_prefs_->GetBoolean(prefs::kLiveCaptionEnabled);
 #else
@@ -194,7 +194,7 @@
   bool is_language_code_for_live_caption =
       prefs::IsLanguageCodeForLiveCaption(language_code, profile_prefs_);
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   bool is_language_code_for_babel_orca =
       prefs::IsLanguageCodeForMicrophoneCaption(language_code, profile_prefs_);
 
@@ -286,7 +286,7 @@
 }
 
 const std::string LiveCaptionController::GetLanguageCode() const {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   if (enabled_for_babel_orca_) {
     return prefs::GetUserMicrophoneCaptionLanguage(profile_prefs_);
   }
@@ -350,7 +350,7 @@
 }
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 void LiveCaptionController::ToggleLiveCaptionForBabelOrca(bool enabled) {
   enabled_for_babel_orca_ = enabled;
   OnLiveCaptionEnabledChanged();
diff --git a/components/live_caption/live_caption_controller.h b/components/live_caption/live_caption_controller.h
index 70af1fb2..bb5e119 100644
--- a/components/live_caption/live_caption_controller.h
+++ b/components/live_caption/live_caption_controller.h
@@ -87,9 +87,9 @@
   void OnToggleFullscreen(CaptionBubbleContext* caption_bubble_context);
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   void ToggleLiveCaptionForBabelOrca(bool enabled);
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
   CaptionBubbleController* caption_bubble_controller_for_testing() {
     return caption_bubble_controller_.get();
@@ -127,7 +127,7 @@
 
   const std::string application_locale_;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   // Tracks whether or not Live Caption has been enabled for babel orca.
   bool enabled_for_babel_orca_ = false;
 #endif
diff --git a/components/live_caption/live_caption_controller_unittest.cc b/components/live_caption/live_caption_controller_unittest.cc
index a31d1d6..42944f2 100644
--- a/components/live_caption/live_caption_controller_unittest.cc
+++ b/components/live_caption/live_caption_controller_unittest.cc
@@ -110,7 +110,7 @@
             speech::kUsEnglishLocale);
 
   // Babel Orca flags are only registered on ash.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   EXPECT_FALSE(testing_pref_service_.GetBoolean(
       prefs::kLiveCaptionUserMicrophoneEnabled));
   EXPECT_EQ(testing_pref_service_.GetString(
diff --git a/components/live_caption/live_caption_ui_remote_driver.cc b/components/live_caption/live_caption_ui_remote_driver.cc
deleted file mode 100644
index f0b4df1..0000000
--- a/components/live_caption/live_caption_ui_remote_driver.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/live_caption/live_caption_ui_remote_driver.h"
-
-#include <string>
-#include <utility>
-
-#include "base/functional/callback_forward.h"
-#include "components/live_caption/caption_bubble_context_remote.h"
-#include "components/live_caption/live_caption_controller.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-
-namespace captions {
-
-LiveCaptionUiRemoteDriver::LiveCaptionUiRemoteDriver(
-    LiveCaptionController* controller,
-    mojo::PendingReceiver<media::mojom::SpeechRecognitionSurfaceClient>
-        client_receiver,
-    mojo::PendingRemote<media::mojom::SpeechRecognitionSurface> surface_remote,
-    const std::string& session_id)
-    : controller_(controller),
-      client_receiver_(this, std::move(client_receiver)),
-      context_(std::move(surface_remote), session_id) {}
-
-LiveCaptionUiRemoteDriver::~LiveCaptionUiRemoteDriver() {
-  controller_->OnAudioStreamEnd(&context_);
-}
-
-void LiveCaptionUiRemoteDriver::OnSpeechRecognitionRecognitionEvent(
-    const media::SpeechRecognitionResult& result,
-    OnSpeechRecognitionRecognitionEventCallback reply) {
-  std::move(reply).Run(controller_->DispatchTranscription(&context_, result));
-}
-
-void LiveCaptionUiRemoteDriver::OnLanguageIdentificationEvent(
-    media::mojom::LanguageIdentificationEventPtr event) {
-  controller_->OnLanguageIdentificationEvent(&context_, std::move(event));
-}
-
-void LiveCaptionUiRemoteDriver::OnSpeechRecognitionError() {
-  controller_->OnError(&context_, CaptionBubbleErrorType::kGeneric,
-                       base::RepeatingClosure(),
-                       base::BindRepeating([](CaptionBubbleErrorType error_type,
-                                              bool checked) {}));
-}
-
-void LiveCaptionUiRemoteDriver::OnSpeechRecognitionStopped() {
-  controller_->OnAudioStreamEnd(&context_);
-}
-
-void LiveCaptionUiRemoteDriver::OnSessionEnded() {
-  context_.OnSessionEnded();
-}
-
-void LiveCaptionUiRemoteDriver::OnFullscreenToggled() {
-  controller_->OnToggleFullscreen(&context_);
-}
-
-}  // namespace captions
diff --git a/components/live_caption/live_caption_ui_remote_driver.h b/components/live_caption/live_caption_ui_remote_driver.h
deleted file mode 100644
index fd5322f..0000000
--- a/components/live_caption/live_caption_ui_remote_driver.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_LIVE_CAPTION_LIVE_CAPTION_UI_REMOTE_DRIVER_H_
-#define COMPONENTS_LIVE_CAPTION_LIVE_CAPTION_UI_REMOTE_DRIVER_H_
-
-#include <memory>
-
-#include "base/memory/raw_ptr.h"
-#include "components/live_caption/caption_bubble_context_remote.h"
-#include "media/mojo/mojom/speech_recognition.mojom.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-
-namespace captions {
-
-class CaptionBubbleContextRemote;
-class LiveCaptionController;
-
-// Receives both speech recognition events and speech surface events (e.g.
-// fullscreen-ing) from remote lacros processes, passing them to the live
-// caption UI.
-//
-// One driver exists in the Ash browser process for each caption-producing
-// stream of media in a lacros renderer.
-class LiveCaptionUiRemoteDriver
-    : public media::mojom::SpeechRecognitionSurfaceClient,
-      public media::mojom::SpeechRecognitionRecognizerClient {
- public:
-  // The speech surface client implementation is bound at construction time, but
-  // the speech recognition client implementation is bound in the "client
-  // browser interface"'s receiver set.
-  LiveCaptionUiRemoteDriver(
-      LiveCaptionController* controller,
-      mojo::PendingReceiver<media::mojom::SpeechRecognitionSurfaceClient>
-          client_receiver,
-      mojo::PendingRemote<media::mojom::SpeechRecognitionSurface> surface,
-      const std::string& session_id);
-  ~LiveCaptionUiRemoteDriver() override;
-
-  // media::mojom::SpeechOriginRecognizerClient:
-  void OnSpeechRecognitionRecognitionEvent(
-      const media::SpeechRecognitionResult& result,
-      OnSpeechRecognitionRecognitionEventCallback reply) override;
-  void OnLanguageIdentificationEvent(
-      media::mojom::LanguageIdentificationEventPtr event) override;
-  void OnSpeechRecognitionError() override;
-  void OnSpeechRecognitionStopped() override;
-
-  // media::mojom::SpeechRecognitionSurfaceClient:
-  void OnSessionEnded() override;
-  void OnFullscreenToggled() override;
-
- private:
-  // We are owned by the "client browser interface", which is a service that
-  // `DependsOn` the controller. Hence the controller is guaranteed to exist.
-  const raw_ptr<LiveCaptionController> controller_;
-
-  mojo::Receiver<media::mojom::SpeechRecognitionSurfaceClient> client_receiver_;
-
-  CaptionBubbleContextRemote context_;
-};
-
-}  // namespace captions
-
-#endif  // COMPONENTS_LIVE_CAPTION_LIVE_CAPTION_UI_REMOTE_DRIVER_H_
diff --git a/components/live_caption/pref_names.cc b/components/live_caption/pref_names.cc
index 0721042a..8a6328a 100644
--- a/components/live_caption/pref_names.cc
+++ b/components/live_caption/pref_names.cc
@@ -45,7 +45,7 @@
 
 #endif  // !defined(ANDROID)
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 const std::string GetUserMicrophoneCaptionLanguage(PrefService* profile_prefs) {
   return GetCaptionLanguageCodeForPref(
       prefs::kUserMicrophoneCaptionLanguageCode, profile_prefs);
diff --git a/components/live_caption/pref_names.h b/components/live_caption/pref_names.h
index dd4e6d4..0c2ad5c 100644
--- a/components/live_caption/pref_names.h
+++ b/components/live_caption/pref_names.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 
 #if !BUILDFLAG(IS_ANDROID)
 #include "components/soda/constants.h"
@@ -44,7 +43,7 @@
     "silenced";
 
 // This may be removed in the future but for now these preferences are ash only.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 
 // Enables Captioning from microphone input.
 inline constexpr char kLiveCaptionUserMicrophoneEnabled[] =
@@ -59,7 +58,7 @@
 bool IsLanguageCodeForMicrophoneCaption(speech::LanguageCode language_code,
                                         PrefService* profile_prefs);
 
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 const std::string GetLiveCaptionLanguageCode(PrefService* profile_prefs);
 bool IsLanguageCodeForLiveCaption(speech::LanguageCode language_code,
diff --git a/components/live_caption/views/caption_bubble.cc b/components/live_caption/views/caption_bubble.cc
index 6f20593..61f0cf09 100644
--- a/components/live_caption/views/caption_bubble.cc
+++ b/components/live_caption/views/caption_bubble.cc
@@ -231,7 +231,7 @@
 
 namespace captions {
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kIsCaptionBubbleKey, false)
 #endif
 
@@ -913,7 +913,7 @@
   params->z_order = ui::ZOrderLevel::kFloatingWindow;
   params->visible_on_all_workspaces = true;
   params->name = "LiveCaptionWindow";
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   params->init_properties_container.SetProperty(kIsCaptionBubbleKey, true);
 #endif
 }
diff --git a/components/live_caption/views/caption_bubble.h b/components/live_caption/views/caption_bubble.h
index 08a1330..f74064b 100644
--- a/components/live_caption/views/caption_bubble.h
+++ b/components/live_caption/views/caption_bubble.h
@@ -65,7 +65,7 @@
 };
 // LINT.ThenChange(/tools/metrics/histograms/metadata/accessibility/enums.xml:LiveCaptionSessionEvent)
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 // Used by ash window manager to place the caption bubble in the correct
 // container.
 extern const ui::ClassProperty<bool>* const kIsCaptionBubbleKey;
diff --git a/components/live_caption/views/caption_bubble_controller_views.cc b/components/live_caption/views/caption_bubble_controller_views.cc
index b887de2..979bc44 100644
--- a/components/live_caption/views/caption_bubble_controller_views.cc
+++ b/components/live_caption/views/caption_bubble_controller_views.cc
@@ -43,19 +43,19 @@
       views::BubbleDialogDelegateView::CreateBubble(caption_bubble_);
   caption_bubble_->SetCaptionBubbleStyle();
 
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
+#if !BUILDFLAG(IS_CHROMEOS)
   speech::SodaInstaller* soda_installer = speech::SodaInstaller::GetInstance();
   if (soda_installer) {
     soda_installer->AddObserver(this);
   }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 }
 
 CaptionBubbleControllerViews::~CaptionBubbleControllerViews() {
   if (caption_widget_)
     caption_widget_->CloseNow();
 
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
+#if !BUILDFLAG(IS_CHROMEOS)
   speech::SodaInstaller* soda_installer = speech::SodaInstaller::GetInstance();
   // `soda_installer` is not guaranteed to be valid, since it's possible for
   // this class to out-live it. This means that this class cannot use
@@ -63,7 +63,7 @@
   if (soda_installer) {
     soda_installer->RemoveObserver(this);
   }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 }
 
 void CaptionBubbleControllerViews::OnCaptionBubbleDestroyed() {
diff --git a/components/manta/walrus_provider.cc b/components/manta/walrus_provider.cc
index e883c82..5b75203 100644
--- a/components/manta/walrus_provider.cc
+++ b/components/manta/walrus_provider.cc
@@ -5,6 +5,7 @@
 #include "components/manta/walrus_provider.h"
 
 #include <algorithm>
+#include <cstdint>
 
 #include "components/manta/features.h"
 #include "third_party/skia/include/codec/SkJpegDecoder.h"
@@ -110,9 +111,36 @@
   return gfx::JPEGCodec::Encode(resized_bitmap, /*quality=*/90);
 }
 
+std::string GetImageTypeTag(WalrusProvider::ImageType image_type) {
+  switch (image_type) {
+    case WalrusProvider::ImageType::kInputImage:
+      return "input_image";
+    case WalrusProvider::ImageType::kOutputImage:
+      return "output_image";
+    case WalrusProvider::ImageType::kGeneratedRegion:
+      return "generated_region";
+    default:
+      return "input_image";
+  }
+}
+
 void WalrusProvider::Filter(const std::optional<std::string>& text_prompt,
                             const std::vector<std::vector<uint8_t>>& images,
                             MantaGenericCallback done_callback) {
+  std::vector<ImageType> image_types(images.size(), ImageType::kInputImage);
+  Filter(text_prompt, images, image_types, std::move(done_callback));
+}
+
+void WalrusProvider::Filter(const std::optional<std::string>& text_prompt,
+                            const std::vector<std::vector<uint8_t>>& images,
+                            const std::vector<ImageType>& image_types,
+                            MantaGenericCallback done_callback) {
+  if (images.size() != image_types.size()) {
+    std::move(done_callback)
+        .Run(base::Value::Dict(), {MantaStatusCode::kInvalidInput});
+    return;
+  }
+
   proto::Request request;
   request.set_feature_name(proto::FeatureName::CHROMEOS_WALRUS);
 
@@ -122,9 +150,12 @@
     input_data->set_text(text_prompt.value());
   }
 
-  for (auto& image : images) {
+  for (size_t i = 0; i < images.size(); ++i) {
+    const std::vector<uint8_t>& image = images[i];
+    const ImageType& image_type = image_types[i];
+
     auto* input_data = request.add_input_data();
-    input_data->set_tag("input_image");
+    input_data->set_tag(GetImageTypeTag(image_type));
     auto resized_image_bytes = DownscaleImageIfNeeded(image);
     if (resized_image_bytes.has_value()) {
       input_data->mutable_image()->set_serialized_bytes(
diff --git a/components/manta/walrus_provider.h b/components/manta/walrus_provider.h
index 371252af..df033598 100644
--- a/components/manta/walrus_provider.h
+++ b/components/manta/walrus_provider.h
@@ -31,6 +31,13 @@
 // `IdentityManager` destruction.
 class COMPONENT_EXPORT(MANTA) WalrusProvider : virtual public BaseProvider {
  public:
+  // Enum for different image types used in Walrus requests.
+  enum class ImageType {
+    kInputImage,
+    kOutputImage,
+    kGeneratedRegion,
+  };
+
   // Returns a `WalrusProvider` instance tied to the profile of the passed
   // arguments.
   WalrusProvider(
@@ -52,6 +59,14 @@
                       const std::vector<std::vector<uint8_t>>& images,
                       MantaGenericCallback done_callback);
 
+  // Filters the given `text_prompt` and `images`. The `image_types` vector
+  // specifies the type of each image in the `images` vector.
+  // The sizes of `images` and `image_types` must match.
+  virtual void Filter(const std::optional<std::string>& text_prompt,
+                      const std::vector<std::vector<uint8_t>>& images,
+                      const std::vector<ImageType>& image_types,
+                      MantaGenericCallback done_callback);
+
   // Filters the given `text_prompt`.
   virtual void Filter(const std::string text_prompt,
                       MantaGenericCallback done_callback);
diff --git a/components/manta/walrus_provider_unittest.cc b/components/manta/walrus_provider_unittest.cc
index 0ba3e7b..3aa968a 100644
--- a/components/manta/walrus_provider_unittest.cc
+++ b/components/manta/walrus_provider_unittest.cc
@@ -319,4 +319,79 @@
   ASSERT_EQ(resized_image.height(), 12);
 }
 
+// Test the response when the generated region is provided.
+TEST_F(WalrusProviderTest, GeneratedRegion) {
+  std::string generated_region_image_bytes = "generated_region_image_bytes";
+  manta::proto::Response response;
+  auto* output_data = response.add_output_data();
+  output_data->set_text("text prompt");
+
+  output_data = response.add_output_data();
+  // Aratea should return the tag instead of image
+  output_data->set_text("generated_region");
+
+  std::string response_data;
+  response.SerializeToString(&response_data);
+
+  SetEndpointMockResponse(GURL{kMockEndpoint}, response_data, net::HTTP_OK,
+                          net::OK);
+  std::unique_ptr<FakeWalrusProvider> walrus_provider = CreateWalrusProvider();
+  auto quit_closure = task_environment_.QuitClosure();
+  std::optional<std::string> text_prompt = "text pompt";
+  std::vector<std::vector<uint8_t>> images = {
+      std::vector<uint8_t>(generated_region_image_bytes.begin(),
+                           generated_region_image_bytes.end())};
+  std::vector<manta::WalrusProvider::ImageType> image_types = {
+      manta::WalrusProvider::ImageType::kGeneratedRegion};
+
+  walrus_provider->Filter(
+      text_prompt, images, image_types,
+      base::BindLambdaForTesting([&quit_closure](base::Value::Dict response,
+                                                 MantaStatus manta_status) {
+        // Even though the response has text and image, walrus just
+        // returns the status code
+        ASSERT_EQ(MantaStatusCode::kOk, manta_status.status_code);
+        ASSERT_TRUE(response.empty());
+        quit_closure.Run();
+      }));
+  task_environment_.RunUntilQuit();
+}
+
+// Test the response when the image type argument size mismatch with number of
+// images.
+TEST_F(WalrusProviderTest, ImageTypeSizeMismatch) {
+  std::string generated_region_image_bytes = "generated_region_image_bytes";
+  manta::proto::Response response;
+  auto* output_data = response.add_output_data();
+  output_data->set_text("text prompt");
+
+  output_data = response.add_output_data();
+  // Aratea should return the tag instead of image
+  output_data->set_text("output_image");
+
+  std::string response_data;
+  response.SerializeToString(&response_data);
+
+  SetEndpointMockResponse(GURL{kMockEndpoint}, response_data, net::HTTP_OK,
+                          net::OK);
+  std::unique_ptr<FakeWalrusProvider> walrus_provider = CreateWalrusProvider();
+  auto quit_closure = task_environment_.QuitClosure();
+  std::optional<std::string> text_prompt = "text pompt";
+  std::vector<std::vector<uint8_t>> images = {
+      std::vector<uint8_t>(generated_region_image_bytes.begin(),
+                           generated_region_image_bytes.end())};
+  std::vector<manta::WalrusProvider::ImageType> image_types = {
+      manta::WalrusProvider::ImageType::kOutputImage,
+      manta::WalrusProvider::ImageType::kGeneratedRegion};
+
+  walrus_provider->Filter(
+      text_prompt, images, image_types,
+      base::BindLambdaForTesting([&quit_closure](base::Value::Dict response,
+                                                 MantaStatus manta_status) {
+        EXPECT_EQ(manta_status.status_code, MantaStatusCode::kInvalidInput);
+        quit_closure.Run();
+      }));
+  task_environment_.RunUntilQuit();
+}
+
 }  // namespace manta
diff --git a/components/media_effects/media_effects_mediapipe_unittests.cc b/components/media_effects/media_effects_mediapipe_unittests.cc
index d07bd68..45bc3c0 100644
--- a/components/media_effects/media_effects_mediapipe_unittests.cc
+++ b/components/media_effects/media_effects_mediapipe_unittests.cc
@@ -4,20 +4,14 @@
 
 #include <vector>
 
-#include "testing/gtest/include/gtest/gtest.h"
-
 #include "build/buildflag.h"
+#include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/mediapipe/buildflags.h"
 #include "third_party/mediapipe/src/mediapipe/framework/calculator.pb.h"
 #include "third_party/mediapipe/src/mediapipe/framework/calculator_graph.h"
-#include "third_party/mediapipe/src/mediapipe/framework/formats/image_frame.h"
 
 namespace {
 
-[[maybe_unused]] uint8_t GetPixelValue(int x, int y, int iteration) {
-  return (1 + 3 * x + 5 * y + 2 * iteration) % 256;
-}
-
 TEST(MediaEffectsMediaPipe, OnCpu) {
   // Configures a simple graph, which concatenates 2 PassThroughCalculators.
 
@@ -81,93 +75,4 @@
   ASSERT_TRUE(status.ok()) << "WaitUntilDone() failed, error: " << status;
 }
 
-#if BUILDFLAG(MEDIAPIPE_BUILD_WITH_GPU_SUPPORT)
-TEST(MediaEffectsMediaPipe, OnGpu) {
-  // Configures a simple graph, which sends an on-CPU frame to GPU and then
-  // reads back from it.
-
-  mediapipe::CalculatorGraphConfig config;
-  config.add_input_stream("in");
-  config.add_output_stream("out");
-
-  auto* node1 = config.add_node();
-  *node1->mutable_calculator() = "ImageFrameToGpuBufferCalculator";
-  node1->add_input_stream("in");
-  node1->add_output_stream("out1");
-
-  auto* node2 = config.add_node();
-  *node2->mutable_calculator() = "GpuBufferToImageFrameCalculator";
-  node2->add_input_stream("out1");
-  node2->add_output_stream("out");
-
-  mediapipe::CalculatorGraph graph;
-  absl::Status status = graph.Initialize(config);
-  ASSERT_TRUE(status.ok()) << "Failed to initialize calculator graph, error: "
-                           << status;
-
-  absl::StatusOr<mediapipe::OutputStreamPoller> maybe_poller =
-      graph.AddOutputStreamPoller("out");
-  ASSERT_TRUE(maybe_poller.ok())
-      << "Failed to obtain poller, error: " << maybe_poller.status();
-
-  mediapipe::OutputStreamPoller poller = std::move(maybe_poller.value());
-
-  status = graph.StartRun({});
-  ASSERT_TRUE(status.ok()) << "Failed to start run on the graph, error: "
-                           << status;
-
-  for (int i = 0; i < 10; ++i) {
-    mediapipe::ImageFrame input(mediapipe::ImageFormat::SRGBA, 10, 10);
-
-    uint8_t* pixel_data = input.MutablePixelData();
-    for (int col = 0; col < input.Width(); ++col) {
-      for (int row = 0; row < input.Height(); ++row) {
-        *(pixel_data + row + col * input.WidthStep()) =
-            GetPixelValue(col, row, i);
-      }
-    }
-
-    status = graph.AddPacketToInputStream(
-        "in", mediapipe::MakePacket<mediapipe::ImageFrame>(std::move(input))
-                  .At(mediapipe::Timestamp(i)));
-    ASSERT_TRUE(status.ok())
-        << "Failed to add packet to input stream, error: " << status;
-  }
-
-  // Close the input stream "in".
-  status = graph.CloseInputStream("in");
-  ASSERT_TRUE(status.ok()) << "Failed to close the input stream, error: "
-                           << status;
-
-  int iteration = 0;
-  mediapipe::Packet packet;
-  // Get the output packets string.
-  while (poller.Next(&packet)) {
-    const mediapipe::ImageFrame& output = packet.Get<mediapipe::ImageFrame>();
-
-    const uint8_t* pixel_data = output.PixelData();
-    for (int col = 0; col < output.Width(); ++col) {
-      for (int row = 0; row < output.Height(); ++row) {
-        const uint8_t expected = GetPixelValue(col, row, iteration);
-        const uint8_t got = *(pixel_data + row + col * output.WidthStep());
-
-        EXPECT_EQ(got, expected)
-            << "data mismatch at row " << row << ", column " << col
-            << ", iteration " << iteration << ", expected " << expected
-            << ", got " << got;
-      }
-    }
-
-    ++iteration;
-  }
-
-  EXPECT_EQ(iteration, 10)
-      << "insufficient number of packets read from the graph!";
-
-  status = graph.WaitUntilDone();
-  ASSERT_TRUE(status.ok()) << "WaitUntilDone() failed, error: " << status;
-}
-
-#endif
-
 }  // namespace
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index 4c0fd35..76dfc40e 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -1120,27 +1120,26 @@
   UMA_HISTOGRAM_ENUMERATION("Omnibox.SearchEngineType", search_engine_type,
                             SEARCH_ENGINE_MAX);
 
-  if (template_url->created_by_policy() !=
-      TemplateURLData::CreatedByPolicy::kNoPolicy) {
+  if (template_url->CreatedByPolicy()) {
     UMA_HISTOGRAM_ENUMERATION("Omnibox.SearchEngineType.SetByEnterprisePolicy",
                               search_engine_type, SEARCH_ENGINE_MAX);
 
-    switch (template_url->created_by_policy()) {
-      case TemplateURLData::CreatedByPolicy::kDefaultSearchProvider:
+    switch (template_url->policy_origin()) {
+      case TemplateURLData::PolicyOrigin::kDefaultSearchProvider:
         UMA_HISTOGRAM_ENUMERATION(
             "Omnibox.SearchEngineType.SetByEnterprisePolicy."
             "DefaultSearchProvider",
             search_engine_type, SEARCH_ENGINE_MAX);
         break;
 
-      case TemplateURLData::CreatedByPolicy::kSiteSearch:
+      case TemplateURLData::PolicyOrigin::kSiteSearch:
         UMA_HISTOGRAM_ENUMERATION(
             "Omnibox.SearchEngineType.SetByEnterprisePolicy."
             "SiteSearchSettings",
             search_engine_type, SEARCH_ENGINE_MAX);
         break;
 
-      case TemplateURLData::CreatedByPolicy::kSearchAggregator:
+      case TemplateURLData::PolicyOrigin::kSearchAggregator:
         UMA_HISTOGRAM_ENUMERATION(
             "Omnibox.SearchEngineType.SetByEnterprisePolicy."
             "EnterpriseSearchAggregatorSettings",
diff --git a/components/omnibox/browser/featured_search_provider_unittest.cc b/components/omnibox/browser/featured_search_provider_unittest.cc
index cb3be7a..259aa48 100644
--- a/components/omnibox/browser/featured_search_provider_unittest.cc
+++ b/components/omnibox/browser/featured_search_provider_unittest.cc
@@ -164,8 +164,8 @@
     template_url_data.SetKeyword(keyword);
     template_url_data.SetShortName(keyword + u" Name");
     template_url_data.SetURL(url);
-    template_url_data.created_by_policy =
-        TemplateURLData::CreatedByPolicy::kSiteSearch;
+    template_url_data.policy_origin =
+        TemplateURLData::PolicyOrigin::kSiteSearch;
     template_url_data.enforced_by_policy = false;
     template_url_data.featured_by_policy = true;
     template_url_data.safe_for_autoreplace = false;
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal
index b1fb5d5..3260a04b 160000
--- a/components/optimization_guide/internal
+++ b/components/optimization_guide/internal
@@ -1 +1 @@
-Subproject commit b1fb5d58cb230fb5d7e2a75cff00ab025d18a6fd
+Subproject commit 3260a04b709daada0fdf5039d580550c0ad96c9f
diff --git a/components/policy/resources/templates/policy_definitions/Miscellaneous/LacrosAvailability.yaml b/components/policy/resources/templates/policy_definitions/Miscellaneous/LacrosAvailability.yaml
index 2d329472..89fb2dc 100644
--- a/components/policy/resources/templates/policy_definitions/Miscellaneous/LacrosAvailability.yaml
+++ b/components/policy/resources/templates/policy_definitions/Miscellaneous/LacrosAvailability.yaml
@@ -48,6 +48,7 @@
   - lacros_only
   type: string
 supported_on:
-- chrome_os:92-
+- chrome_os:92-130
 tags: []
 type: string-enum
+deprecated: true
diff --git a/components/policy/test/data/pref_mapping/LacrosAvailability.json b/components/policy/test/data/pref_mapping/LacrosAvailability.json
deleted file mode 100644
index 3fcb1f64..0000000
--- a/components/policy/test/data/pref_mapping/LacrosAvailability.json
+++ /dev/null
@@ -1,52 +0,0 @@
-[
-  {
-    "can_be_recommended": false,
-    "os": [
-      "chromeos_ash"
-    ],
-    "policy_pref_mapping_tests": [
-      {
-        "policies": {},
-        "prefs": {
-          "lacros_launch_switch": {
-            "location": "local_state",
-            "value": 1
-          }
-        }
-      },
-      {
-        "policies": {
-          "LacrosAvailability": "user_choice"
-        },
-        "prefs": {
-          "lacros_launch_switch": {
-            "location": "local_state",
-            "value": 0
-          }
-        }
-      },
-      {
-        "policies": {
-          "LacrosAvailability": "lacros_disallowed"
-        },
-        "prefs": {
-          "lacros_launch_switch": {
-            "location": "local_state",
-            "value": 1
-          }
-        }
-      },
-      {
-        "policies": {
-          "LacrosAvailability": "lacros_only"
-        },
-        "prefs": {
-          "lacros_launch_switch": {
-            "location": "local_state",
-            "value": 4
-          }
-        }
-      }
-    ]
-  }
-]
diff --git a/components/power_bookmarks/core/bookmark_client_base.cc b/components/power_bookmarks/core/bookmark_client_base.cc
index 962348bf..1fbfbfc 100644
--- a/components/power_bookmarks/core/bookmark_client_base.cc
+++ b/components/power_bookmarks/core/bookmark_client_base.cc
@@ -124,8 +124,7 @@
   // If there's no suggested folder, ensure we're not accidentally suggesting
   // one via the most recently modified.
   for (const bookmarks::BookmarkNode* node :
-       bookmarks::GetMostRecentlyModifiedUserFolders(
-           bookmark_model_, save_location_providers_.size() + 1)) {
+       bookmarks::GetMostRecentlyModifiedUserFolders(bookmark_model_)) {
     // Suggest first non-suggested folder in the MRU.
     std::string was_saved_to_suggested;
     if (!node->GetMetaInfo(kWasSuggestedFolderKey, &was_saved_to_suggested) ||
diff --git a/components/safe_browsing/core/common/features.cc b/components/safe_browsing/core/common/features.cc
index dfb65b95..9081495 100644
--- a/components/safe_browsing/core/common/features.cc
+++ b/components/safe_browsing/core/common/features.cc
@@ -178,10 +178,6 @@
         &kExtensionTelemetryForEnterprise, "EnterpriseReportingIntervalSeconds",
         /*default_value=*/300};
 
-BASE_FEATURE(kExtensionTelemetryReportContactedHosts,
-             "SafeBrowsingExtensionTelemetryReportContactedHosts",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(
     kExtensionTelemetryInterceptRemoteHostsContactedInRenderer,
     "SafeBrowsingExtensionTelmetryInterceptRemoteHostsContactedInRenderer",
@@ -363,7 +359,6 @@
       &kExtensionTelemetryDeclarativeNetRequestActionSignal,
       &kExtensionTelemetryForEnterprise,
       &kExtensionTelemetryInterceptRemoteHostsContactedInRenderer,
-      &kExtensionTelemetryReportContactedHosts,
       &kExtensionTelemetryTabsExecuteScriptSignal,
       &kExternalAppRedirectTelemetry,
       &kHashPrefixRealTimeLookups,
diff --git a/components/safe_browsing/core/common/features.h b/components/safe_browsing/core/common/features.h
index b1e82e5..bf08c5d 100644
--- a/components/safe_browsing/core/common/features.h
+++ b/components/safe_browsing/core/common/features.h
@@ -172,9 +172,6 @@
 // tabs.executeScript API call.
 BASE_DECLARE_FEATURE(kExtensionTelemetryTabsExecuteScriptSignal);
 
-// Enables reporting of remote hosts contacted by extensions in telemetry.
-BASE_DECLARE_FEATURE(kExtensionTelemetryReportContactedHosts);
-
 // Enables intercepting remote hosts contacted by extensions in renderer
 // throttles.
 BASE_DECLARE_FEATURE(
diff --git a/components/search_engines/android/template_url_android.cc b/components/search_engines/android/template_url_android.cc
index d1661a0..50517fd5 100644
--- a/components/search_engines/android/template_url_android.cc
+++ b/components/search_engines/android/template_url_android.cc
@@ -37,8 +37,7 @@
     jlong template_url_ptr) {
   TemplateURL* template_url = ToTemplateURL(template_url_ptr);
   return template_url->prepopulate_id() > 0 ||
-         template_url->created_by_policy() !=
-             TemplateURLData::CreatedByPolicy::kNoPolicy ||
+         template_url->CreatedByPolicy() ||
          template_url->created_from_play_api();
 }
 
diff --git a/components/search_engines/default_search_manager.cc b/components/search_engines/default_search_manager.cc
index cdb0330..d6b631bc 100644
--- a/components/search_engines/default_search_manager.cc
+++ b/components/search_engines/default_search_manager.cc
@@ -69,7 +69,7 @@
 
 const char DefaultSearchManager::kUsageCount[] = "usage_count";
 const char DefaultSearchManager::kAlternateURLs[] = "alternate_urls";
-const char DefaultSearchManager::kCreatedByPolicy[] = "created_by_policy";
+const char DefaultSearchManager::kPolicyOrigin[] = "policy_origin";
 const char DefaultSearchManager::kDisabledByPolicy[] = "disabled_by_policy";
 const char DefaultSearchManager::kCreatedFromPlayAPI[] =
     "created_from_play_api";
diff --git a/components/search_engines/default_search_manager.h b/components/search_engines/default_search_manager.h
index 4b4d7df7..37f7266 100644
--- a/components/search_engines/default_search_manager.h
+++ b/components/search_engines/default_search_manager.h
@@ -78,7 +78,7 @@
 
   static const char kUsageCount[];
   static const char kAlternateURLs[];
-  static const char kCreatedByPolicy[];
+  static const char kPolicyOrigin[];
   static const char kDisabledByPolicy[];
   static const char kCreatedFromPlayAPI[];
   static const char kFeaturedByPolicy[];
diff --git a/components/search_engines/enterprise/default_search_policy_handler.cc b/components/search_engines/enterprise/default_search_policy_handler.cc
index e410594..3bf4e884a 100644
--- a/components/search_engines/enterprise/default_search_policy_handler.cc
+++ b/components/search_engines/enterprise/default_search_policy_handler.cc
@@ -208,9 +208,9 @@
   dict.Set(DefaultSearchManager::kLastModified,
            static_cast<double>(base::Time::Now().ToInternalValue()));
   dict.Set(DefaultSearchManager::kUsageCount, 0);
-  dict.Set(DefaultSearchManager::kCreatedByPolicy,
-           static_cast<int>(
-               TemplateURLData::CreatedByPolicy::kDefaultSearchProvider));
+  dict.Set(
+      DefaultSearchManager::kPolicyOrigin,
+      static_cast<int>(TemplateURLData::PolicyOrigin::kDefaultSearchProvider));
 
   // For the name and keyword, default to the host if not specified.  If
   // there is no host (as is the case with file URLs of the form:
diff --git a/components/search_engines/enterprise/default_search_policy_handler_unittest.cc b/components/search_engines/enterprise/default_search_policy_handler_unittest.cc
index 35e3131..210e892 100644
--- a/components/search_engines/enterprise/default_search_policy_handler_unittest.cc
+++ b/components/search_engines/enterprise/default_search_policy_handler_unittest.cc
@@ -202,9 +202,9 @@
   const base::Value::Dict* dictionary = temp->GetIfDict();
   ASSERT_TRUE(dictionary);
 
-  ASSERT_EQ(dictionary->FindInt(DefaultSearchManager::kCreatedByPolicy),
-            static_cast<int>(
-                TemplateURLData::CreatedByPolicy::kDefaultSearchProvider));
+  ASSERT_EQ(
+      dictionary->FindInt(DefaultSearchManager::kPolicyOrigin),
+      static_cast<int>(TemplateURLData::PolicyOrigin::kDefaultSearchProvider));
   const std::string* value = nullptr;
   ASSERT_TRUE(value = dictionary->FindString(DefaultSearchManager::kURL));
   EXPECT_EQ(kSearchURL, *value);
@@ -305,9 +305,9 @@
   ASSERT_TRUE(dictionary);
 
   // Name and keyword should be derived from host.
-  ASSERT_EQ(dictionary->FindInt(DefaultSearchManager::kCreatedByPolicy),
-            static_cast<int>(
-                TemplateURLData::CreatedByPolicy::kDefaultSearchProvider));
+  ASSERT_EQ(
+      dictionary->FindInt(DefaultSearchManager::kPolicyOrigin),
+      static_cast<int>(TemplateURLData::PolicyOrigin::kDefaultSearchProvider));
   const std::string* value = nullptr;
   ASSERT_TRUE(value = dictionary->FindString(DefaultSearchManager::kURL));
   EXPECT_EQ(kSearchURL, *value);
@@ -359,9 +359,9 @@
   const base::Value::Dict* dictionary = temp->GetIfDict();
   ASSERT_TRUE(dictionary);
 
-  ASSERT_EQ(dictionary->FindInt(DefaultSearchManager::kCreatedByPolicy),
-            static_cast<int>(
-                TemplateURLData::CreatedByPolicy::kDefaultSearchProvider));
+  ASSERT_EQ(
+      dictionary->FindInt(DefaultSearchManager::kPolicyOrigin),
+      static_cast<int>(TemplateURLData::PolicyOrigin::kDefaultSearchProvider));
   const std::string* value = nullptr;
   ASSERT_TRUE(value = dictionary->FindString(DefaultSearchManager::kURL));
   EXPECT_EQ(kFileSearchURL, *value);
diff --git a/components/search_engines/enterprise/enterprise_search_manager_unittest.cc b/components/search_engines/enterprise/enterprise_search_manager_unittest.cc
index eb01573..a3da45f 100644
--- a/components/search_engines/enterprise/enterprise_search_manager_unittest.cc
+++ b/components/search_engines/enterprise/enterprise_search_manager_unittest.cc
@@ -46,17 +46,16 @@
 base::Value::Dict GenerateSiteSearchPrefEntry(const std::string& keyword) {
   base::Value::Dict entry =
       GenerateSearchPrefEntry(keyword, /*featured=*/false);
-  entry.Set(DefaultSearchManager::kCreatedByPolicy,
-            static_cast<int>(TemplateURLData::CreatedByPolicy::kSiteSearch));
+  entry.Set(DefaultSearchManager::kPolicyOrigin,
+            static_cast<int>(TemplateURLData::PolicyOrigin::kSiteSearch));
   return entry;
 }
 
 base::Value::Dict GenerateSearchAggregatorPrefEntry(const std::string& keyword,
                                                     bool featured) {
   base::Value::Dict entry = GenerateSearchPrefEntry(keyword, featured);
-  entry.Set(
-      DefaultSearchManager::kCreatedByPolicy,
-      static_cast<int>(TemplateURLData::CreatedByPolicy::kSearchAggregator));
+  entry.Set(DefaultSearchManager::kPolicyOrigin,
+            static_cast<int>(TemplateURLData::PolicyOrigin::kSearchAggregator));
   entry.Set(DefaultSearchManager::kSuggestionsURL,
             std::string("https://") + keyword + ".com/suggest");
   return entry;
diff --git a/components/search_engines/enterprise/search_aggregator_policy_handler.cc b/components/search_engines/enterprise/search_aggregator_policy_handler.cc
index 5f540be0..47b15186 100644
--- a/components/search_engines/enterprise/search_aggregator_policy_handler.cc
+++ b/components/search_engines/enterprise/search_aggregator_policy_handler.cc
@@ -79,9 +79,8 @@
     dict.Set(DefaultSearchManager::kFaviconURL, *icon_url);
   }
 
-  dict.Set(
-      DefaultSearchManager::kCreatedByPolicy,
-      static_cast<int>(TemplateURLData::CreatedByPolicy::kSearchAggregator));
+  dict.Set(DefaultSearchManager::kPolicyOrigin,
+           static_cast<int>(TemplateURLData::PolicyOrigin::kSearchAggregator));
   dict.Set(DefaultSearchManager::kEnforcedByPolicy, false);
   dict.Set(DefaultSearchManager::kFeaturedByPolicy, featured);
   dict.Set(DefaultSearchManager::kIsActive,
diff --git a/components/search_engines/enterprise/search_aggregator_policy_handler_unittest.cc b/components/search_engines/enterprise/search_aggregator_policy_handler_unittest.cc
index 27fc016..8a98b73 100644
--- a/components/search_engines/enterprise/search_aggregator_policy_handler_unittest.cc
+++ b/components/search_engines/enterprise/search_aggregator_policy_handler_unittest.cc
@@ -231,9 +231,9 @@
                          test_case.icon_url ? std::string(test_case.icon_url)
                                             : std::string()),
           FieldNotSet(DefaultSearchManager::kFaviconURL)),
-      HasIntegerField(DefaultSearchManager::kCreatedByPolicy,
-                      static_cast<int>(
-                          TemplateURLData::CreatedByPolicy::kSearchAggregator)),
+      HasIntegerField(
+          DefaultSearchManager::kPolicyOrigin,
+          static_cast<int>(TemplateURLData::PolicyOrigin::kSearchAggregator)),
       HasBooleanField(DefaultSearchManager::kEnforcedByPolicy, false),
       HasBooleanField(DefaultSearchManager::kFeaturedByPolicy, featured),
       HasIntegerField(DefaultSearchManager::kIsActive,
diff --git a/components/search_engines/enterprise/site_search_policy_handler.cc b/components/search_engines/enterprise/site_search_policy_handler.cc
index 081073e..0e3d477 100644
--- a/components/search_engines/enterprise/site_search_policy_handler.cc
+++ b/components/search_engines/enterprise/site_search_policy_handler.cc
@@ -53,8 +53,8 @@
 
   dict.Set(DefaultSearchManager::kFeaturedByPolicy, featured);
 
-  dict.Set(DefaultSearchManager::kCreatedByPolicy,
-           static_cast<int>(TemplateURLData::CreatedByPolicy::kSiteSearch));
+  dict.Set(DefaultSearchManager::kPolicyOrigin,
+           static_cast<int>(TemplateURLData::PolicyOrigin::kSiteSearch));
   dict.Set(DefaultSearchManager::kEnforcedByPolicy, false);
   dict.Set(DefaultSearchManager::kIsActive,
            static_cast<int>(TemplateURLData::ActiveStatus::kTrue));
diff --git a/components/search_engines/enterprise/site_search_policy_handler_unittest.cc b/components/search_engines/enterprise/site_search_policy_handler_unittest.cc
index 09410d1..11f0f94 100644
--- a/components/search_engines/enterprise/site_search_policy_handler_unittest.cc
+++ b/components/search_engines/enterprise/site_search_policy_handler_unittest.cc
@@ -327,8 +327,8 @@
       HasStringField(DefaultSearchManager::kURL, std::string(test_case.url)),
       HasBooleanField(DefaultSearchManager::kFeaturedByPolicy, featured),
       HasIntegerField(
-          DefaultSearchManager::kCreatedByPolicy,
-          static_cast<int>(TemplateURLData::CreatedByPolicy::kSiteSearch)),
+          DefaultSearchManager::kPolicyOrigin,
+          static_cast<int>(TemplateURLData::PolicyOrigin::kSiteSearch)),
       HasBooleanField(DefaultSearchManager::kEnforcedByPolicy, false),
       HasIntegerField(DefaultSearchManager::kIsActive,
                       static_cast<int>(TemplateURLData::ActiveStatus::kTrue)),
diff --git a/components/search_engines/keyword_table.cc b/components/search_engines/keyword_table.cc
index 66637d2..47d0d5d1 100644
--- a/components/search_engines/keyword_table.cc
+++ b/components/search_engines/keyword_table.cc
@@ -576,8 +576,8 @@
   data.id = s.ColumnInt64(0);
   data.date_created = s.ColumnTime(7);
   data.last_modified = s.ColumnTime(13);
-  data.created_by_policy =
-      static_cast<TemplateURLData::CreatedByPolicy>(s.ColumnInt(12));
+  data.policy_origin =
+      static_cast<TemplateURLData::PolicyOrigin>(s.ColumnInt(12));
   data.created_from_play_api = s.ColumnBool(22);
   data.usage_count = s.ColumnInt(8);
   data.prepopulate_id = s.ColumnInt(11);
@@ -667,7 +667,7 @@
                 base::JoinString(data.input_encodings, ";"));
   s->BindString(starting_column + 9, data.suggestions_url);
   s->BindInt(starting_column + 10, data.prepopulate_id);
-  s->BindInt(starting_column + 11, static_cast<int>(data.created_by_policy));
+  s->BindInt(starting_column + 11, static_cast<int>(data.policy_origin));
   s->BindTime(starting_column + 12, data.last_modified);
   s->BindString(starting_column + 13, data.sync_guid);
   s->BindString(starting_column + 14, alternate_urls);
diff --git a/components/search_engines/keyword_table.h b/components/search_engines/keyword_table.h
index 18da16b..6577f97 100644
--- a/components/search_engines/keyword_table.h
+++ b/components/search_engines/keyword_table.h
@@ -54,7 +54,7 @@
 //                          encodings, may be empty.
 //   suggest_url
 //   prepopulate_id         See TemplateURLData::prepopulate_id.
-//   created_by_policy      See TemplateURLData::created_by_policy.  This was
+//   created_by_policy      See TemplateURLData::policy_origin.  This was
 //                          added in version 26.
 //   last_modified          See TemplateURLData::last_modified.  This was added
 //                          in version 38.
diff --git a/components/search_engines/keyword_table_unittest.cc b/components/search_engines/keyword_table_unittest.cc
index 24e4761..f650616 100644
--- a/components/search_engines/keyword_table_unittest.cc
+++ b/components/search_engines/keyword_table_unittest.cc
@@ -82,8 +82,8 @@
     keyword.date_created = base::Time::UnixEpoch();
     keyword.last_modified = base::Time::UnixEpoch();
     keyword.last_visited = base::Time::UnixEpoch();
-    keyword.created_by_policy =
-        TemplateURLData::CreatedByPolicy::kDefaultSearchProvider;
+    keyword.policy_origin =
+        TemplateURLData::PolicyOrigin::kDefaultSearchProvider;
     keyword.usage_count = 32;
     keyword.prepopulate_id = 10;
     keyword.sync_guid = "1234-5678-90AB-CDEF";
@@ -160,7 +160,7 @@
             restored_keyword.last_modified.ToTimeT());
   EXPECT_EQ(keyword.last_visited.ToTimeT(),
             restored_keyword.last_visited.ToTimeT());
-  EXPECT_EQ(keyword.created_by_policy, restored_keyword.created_by_policy);
+  EXPECT_EQ(keyword.policy_origin, restored_keyword.policy_origin);
   EXPECT_EQ(keyword.created_from_play_api,
             restored_keyword.created_from_play_api);
   EXPECT_EQ(keyword.usage_count, restored_keyword.usage_count);
diff --git a/components/search_engines/search_engine_choice/search_engine_choice_service.cc b/components/search_engines/search_engine_choice/search_engine_choice_service.cc
index bacadeb..6c238348 100644
--- a/components/search_engines/search_engine_choice/search_engine_choice_service.cc
+++ b/components/search_engines/search_engine_choice/search_engine_choice_service.cc
@@ -84,8 +84,7 @@
 
 bool IsSetOrBlockedByPolicy(const TemplateURL* default_search_engine) {
   return !default_search_engine ||
-         default_search_engine->created_by_policy() ==
-             TemplateURLData::CreatedByPolicy::kDefaultSearchProvider;
+         default_search_engine->CreatedByDefaultSearchProviderPolicy();
 }
 
 bool IsDefaultSearchProviderSetOrBlockedByPolicy(
diff --git a/components/search_engines/search_engine_choice/search_engine_choice_service_unittest.cc b/components/search_engines/search_engine_choice/search_engine_choice_service_unittest.cc
index 5708b1e..cb2e9d3 100644
--- a/components/search_engines/search_engine_choice/search_engine_choice_service_unittest.cc
+++ b/components/search_engines/search_engine_choice/search_engine_choice_service_unittest.cc
@@ -373,9 +373,9 @@
   TemplateURLData data_from_policies;
   data_from_policies.SetURL("test");
   base::Value::Dict dict = TemplateURLDataToDictionary(data_from_policies);
-  dict.Set(DefaultSearchManager::kCreatedByPolicy,
-           static_cast<int>(
-               TemplateURLData::CreatedByPolicy::kDefaultSearchProvider));
+  dict.Set(
+      DefaultSearchManager::kPolicyOrigin,
+      static_cast<int>(TemplateURLData::PolicyOrigin::kDefaultSearchProvider));
   pref_service()->SetManagedPref(
       DefaultSearchManager::kDefaultSearchProviderDataPrefName,
       std::move(dict));
diff --git a/components/search_engines/search_host_to_urls_map_unittest.cc b/components/search_engines/search_host_to_urls_map_unittest.cc
index 796d420..9821ba3b 100644
--- a/components/search_engines/search_host_to_urls_map_unittest.cc
+++ b/components/search_engines/search_host_to_urls_map_unittest.cc
@@ -83,8 +83,7 @@
   TemplateURLData data;
   data.SetURL("http://" + host_ + "/path1");
   // Make the new TemplateURL "better" by having it created by policy.
-  data.created_by_policy =
-      TemplateURLData::CreatedByPolicy::kDefaultSearchProvider;
+  data.policy_origin = TemplateURLData::PolicyOrigin::kDefaultSearchProvider;
 
   TemplateURL new_t_url(data);
   provider_map_->Add(&new_t_url, SearchTermsData());
diff --git a/components/search_engines/template_url.cc b/components/search_engines/template_url.cc
index 99077fa4..9ab21cc 100644
--- a/components/search_engines/template_url.cc
+++ b/components/search_engines/template_url.cc
@@ -221,12 +221,8 @@
   // the `SiteSearchSettings` or `EnterpriseSearchAggregatorSettings` policy,
   // `other_engine` should have been created by something else, but not via
   // policy.
-  CHECK(policy_engine->created_by_policy() ==
-            TemplateURLData::CreatedByPolicy::kSiteSearch ||
-        policy_engine->created_by_policy() ==
-            TemplateURLData::CreatedByPolicy::kSearchAggregator);
-  CHECK_EQ(other_engine->created_by_policy(),
-           TemplateURLData::CreatedByPolicy::kNoPolicy);
+  CHECK(policy_engine->CreatedByNonDefaultSearchProviderPolicy());
+  CHECK(!other_engine->CreatedByPolicy());
 
   const std::u16string& keyword = policy_engine->keyword();
   // Prefer `policy_engine` if the `keyword` starts with the "@" symbol.
@@ -1645,26 +1641,16 @@
     const TemplateURL* other) const {
   DCHECK(other);
 
-  auto by_policy = [](const TemplateURL* turl) {
-    return turl->created_by_policy() ==
-               TemplateURLData::CreatedByPolicy::kSiteSearch ||
-           turl->created_by_policy() ==
-               TemplateURLData::CreatedByPolicy::kSearchAggregator;
-  };
-
-  auto no_policy = [](const TemplateURL* turl) {
-    return turl->created_by_policy() ==
-           TemplateURLData::CreatedByPolicy::kNoPolicy;
-  };
-
   // Site search and Enterprise Search Aggregator engines set by enterprise
   // policy have different priority over existing search engines because we
   // don't want to break current workflows for power users.
-  if (by_policy(this) && no_policy(other)) {
+  if (CreatedByNonDefaultSearchProviderPolicy() && !other->CreatedByPolicy()) {
     return IsPolicySearchEngineBetterThanNonPolicyEngine(this, other);
-  } else if (no_policy(this) && by_policy(other)) {
+  } else if (!CreatedByPolicy() &&
+             other->CreatedByNonDefaultSearchProviderPolicy()) {
     return !IsPolicySearchEngineBetterThanNonPolicyEngine(other, this);
-  } else if (by_policy(this) && by_policy(other)) {
+  } else if (CreatedByNonDefaultSearchProviderPolicy() &&
+             other->CreatedByNonDefaultSearchProviderPolicy()) {
     // If both engines are created by the `SiteSearchSettings` or
     // `EnterpriseSearchAggregatorSettings` policy, prefer the one that is
     // featured. Otherwise, fallback to the comparison based on the signals
@@ -1680,8 +1666,7 @@
     return std::make_tuple(
         // Policy-created engines always win over non-policy created engines.
         // At this point, managed search engine should be created by DSP policy.
-        engine->created_by_policy() ==
-            TemplateURLData::CreatedByPolicy::kDefaultSearchProvider,
+        engine->CreatedByDefaultSearchProviderPolicy(),
         // Policy-enforced engines always win over policy-recommended engines.
         engine->enforced_by_policy(),
         // The integral value of the type enum is used to sort next.
@@ -2007,6 +1992,18 @@
       TemplateURLRef::SearchTermsArgs(), search_terms_data, nullptr));
 }
 
+bool TemplateURL::CreatedByPolicy() const {
+  return data().CreatedByPolicy();
+}
+
+bool TemplateURL::CreatedByDefaultSearchProviderPolicy() const {
+  return data().CreatedByDefaultSearchProviderPolicy();
+}
+
+bool TemplateURL::CreatedByNonDefaultSearchProviderPolicy() const {
+  return data().CreatedByNonDefaultSearchProviderPolicy();
+}
+
 RegulatoryExtensionType TemplateURL::GetRegulatoryExtensionType() const {
   if (data().created_from_play_api) {
     return RegulatoryExtensionType::kAndroidEEA;
diff --git a/components/search_engines/template_url.h b/components/search_engines/template_url.h
index 0ea3f24..3ef0938 100644
--- a/components/search_engines/template_url.h
+++ b/components/search_engines/template_url.h
@@ -805,8 +805,8 @@
   base::Time last_modified() const { return data().last_modified; }
   base::Time last_visited() const { return data().last_visited; }
 
-  TemplateURLData::CreatedByPolicy created_by_policy() const {
-    return data().created_by_policy;
+  TemplateURLData::PolicyOrigin policy_origin() const {
+    return data().policy_origin;
   }
   bool enforced_by_policy() const { return data().enforced_by_policy; }
   bool created_from_play_api() const { return data().created_from_play_api; }
@@ -994,6 +994,15 @@
   const TemplateURLData::RegulatoryExtension* GetRegulatoryExtension(
       RegulatoryExtensionType type) const;
 
+  // Returns whether this search engine was created by an Enterprise policy.
+  bool CreatedByPolicy() const;
+  // Returns whether this search engine was created by the Default Search
+  // Provider Enterprise policy.
+  bool CreatedByDefaultSearchProviderPolicy() const;
+  // Returns whether this search engine was created by an Enterprise policy that
+  // doesn't define the Default Search Provider.
+  bool CreatedByNonDefaultSearchProviderPolicy() const;
+
   void SetURL(const std::string& url);
   void SetPrepopulateId(int id);
 
diff --git a/components/search_engines/template_url_data.cc b/components/search_engines/template_url_data.cc
index dd207a0f..b762ee02 100644
--- a/components/search_engines/template_url_data.cc
+++ b/components/search_engines/template_url_data.cc
@@ -52,7 +52,7 @@
       id(0),
       date_created(base::Time::Now()),
       last_modified(base::Time::Now()),
-      created_by_policy(CreatedByPolicy::kNoPolicy),
+      policy_origin(PolicyOrigin::kNoPolicy),
       enforced_by_policy(false),
       created_from_play_api(false),
       usage_count(0),
@@ -115,7 +115,7 @@
       favicon_url(favicon_url),
       safe_for_autoreplace(true),
       id(0),
-      created_by_policy(CreatedByPolicy::kNoPolicy),
+      policy_origin(PolicyOrigin::kNoPolicy),
       enforced_by_policy(false),
       created_from_play_api(false),
       usage_count(0),
@@ -216,3 +216,15 @@
 
   return res;
 }
+
+bool TemplateURLData::CreatedByPolicy() const {
+  return policy_origin != PolicyOrigin::kNoPolicy;
+}
+
+bool TemplateURLData::CreatedByDefaultSearchProviderPolicy() const {
+  return policy_origin == PolicyOrigin::kDefaultSearchProvider;
+}
+
+bool TemplateURLData::CreatedByNonDefaultSearchProviderPolicy() const {
+  return CreatedByPolicy() && !CreatedByDefaultSearchProviderPolicy();
+}
diff --git a/components/search_engines/template_url_data.h b/components/search_engines/template_url_data.h
index 1acffdfc..07a69b1 100644
--- a/components/search_engines/template_url_data.h
+++ b/components/search_engines/template_url_data.h
@@ -21,7 +21,7 @@
 // users to do SSA-style usage of TemplateURL: construct a TemplateURLData with
 // whatever fields are desired, then create an immutable TemplateURL from it.
 struct TemplateURLData {
-  enum class CreatedByPolicy {
+  enum class PolicyOrigin {
     kNoPolicy = 0,
     kDefaultSearchProvider = 1,
     kSiteSearch = 2,
@@ -97,6 +97,15 @@
   // See base/trace_event/memory_usage_estimator.h for more info.
   size_t EstimateMemoryUsage() const;
 
+  // Returns whether this search engine was created by an Enterprise policy.
+  bool CreatedByPolicy() const;
+  // Returns whether this search engine was created by the Default Search
+  // Provider Enterprise policy.
+  bool CreatedByDefaultSearchProviderPolicy() const;
+  // Returns whether this search engine was created by an Enterprise policy that
+  // doesn't define the Default Search Provider.
+  bool CreatedByNonDefaultSearchProviderPolicy() const;
+
   // Optional additional raw URLs.
   std::string suggestions_url;
   std::string image_url;
@@ -180,7 +189,7 @@
 
   // True if this TemplateURL was automatically created by the administrator via
   // group policy.
-  CreatedByPolicy created_by_policy;
+  PolicyOrigin policy_origin;
 
   // True if this TemplateURL is forced to be the default search engine via
   // policy. This prevents the user from setting another search engine as
diff --git a/components/search_engines/template_url_data_util.cc b/components/search_engines/template_url_data_util.cc
index 18364f4..127bfc5 100644
--- a/components/search_engines/template_url_data_util.cc
+++ b/components/search_engines/template_url_data_util.cc
@@ -214,9 +214,9 @@
     }
   }
 
-  result->created_by_policy = static_cast<TemplateURLData::CreatedByPolicy>(
-      dict.FindInt(DefaultSearchManager::kCreatedByPolicy)
-          .value_or(static_cast<int>(result->created_by_policy)));
+  result->policy_origin = static_cast<TemplateURLData::PolicyOrigin>(
+      dict.FindInt(DefaultSearchManager::kPolicyOrigin)
+          .value_or(static_cast<int>(result->policy_origin)));
   result->created_from_play_api =
       dict.FindBool(DefaultSearchManager::kCreatedFromPlayAPI)
           .value_or(result->created_from_play_api);
@@ -306,8 +306,8 @@
     encodings.Append(input_encoding);
   url_dict.Set(DefaultSearchManager::kInputEncodings, std::move(encodings));
 
-  url_dict.Set(DefaultSearchManager::kCreatedByPolicy,
-               static_cast<int>(data.created_by_policy));
+  url_dict.Set(DefaultSearchManager::kPolicyOrigin,
+               static_cast<int>(data.policy_origin));
   url_dict.Set(DefaultSearchManager::kCreatedFromPlayAPI,
                data.created_from_play_api);
   url_dict.Set(DefaultSearchManager::kFeaturedByPolicy,
diff --git a/components/search_engines/template_url_service.cc b/components/search_engines/template_url_service.cc
index 0051a9a46..4851820 100644
--- a/components/search_engines/template_url_service.cc
+++ b/components/search_engines/template_url_service.cc
@@ -497,8 +497,7 @@
 bool TemplateURLService::IsPrepopulatedOrDefaultProviderByPolicy(
     const TemplateURL* t_url) const {
   return (t_url->prepopulate_id() > 0 ||
-          t_url->created_by_policy() ==
-              TemplateURLData::CreatedByPolicy::kDefaultSearchProvider ||
+          t_url->CreatedByDefaultSearchProviderPolicy() ||
           t_url->created_from_play_api()) &&
          t_url->SupportsReplacement(search_terms_data());
 }
@@ -513,20 +512,19 @@
 }
 
 bool TemplateURLService::HiddenFromLists(const TemplateURL* t_url) const {
-  switch (t_url->created_by_policy()) {
-    case TemplateURLData::CreatedByPolicy::kNoPolicy:
+  switch (t_url->policy_origin()) {
+    case TemplateURLData::PolicyOrigin::kNoPolicy:
       // Hide if the preferred search engine for the keyword is created by
       // policy. The call to `GetTemplateURLForKeyword` already ensure
       // prioritization of search engines, so there is no need to replicate the
       // logic here.
-      return GetTemplateURLForKeyword(t_url->keyword())->created_by_policy() !=
-             TemplateURLData::CreatedByPolicy::kNoPolicy;
+      return GetTemplateURLForKeyword(t_url->keyword())->CreatedByPolicy();
 
-    case TemplateURLData::CreatedByPolicy::kDefaultSearchProvider:
+    case TemplateURLData::PolicyOrigin::kDefaultSearchProvider:
       return false;
 
-    case TemplateURLData::CreatedByPolicy::kSiteSearch:
-    case TemplateURLData::CreatedByPolicy::kSearchAggregator: {
+    case TemplateURLData::PolicyOrigin::kSiteSearch:
+    case TemplateURLData::PolicyOrigin::kSearchAggregator: {
       // Always show featured Enterprise site search engines.
       if (t_url->featured_by_policy()) {
         return false;
@@ -548,10 +546,7 @@
       const TemplateURL* t_url_with_at =
           GetTemplateURLForKeyword(u"@" + t_url->keyword());
       return t_url_with_at &&
-             (t_url_with_at->created_by_policy() ==
-                  TemplateURLData::CreatedByPolicy::kSiteSearch ||
-              t_url_with_at->created_by_policy() ==
-                  TemplateURLData::CreatedByPolicy::kSearchAggregator) &&
+             t_url_with_at->CreatedByNonDefaultSearchProviderPolicy() &&
              t_url_with_at->featured_by_policy();
     }
   }
@@ -563,10 +558,7 @@
 
   // Check 'template_url` is a featured site or featured aggregator search.
   if (!template_url->featured_by_policy() ||
-    (template_url->created_by_policy() !=
-        TemplateURLData::CreatedByPolicy::kSiteSearch &&
-    template_url->created_by_policy() !=
-        TemplateURLData::CreatedByPolicy::kSearchAggregator)) {
+      !template_url->CreatedByNonDefaultSearchProviderPolicy()) {
     return false;
   }
 
@@ -578,10 +570,7 @@
       GetTemplateURLForKeyword(std::u16string(keyword, 1));
 
   CHECK(turl_without_at);
-  return (turl_without_at->created_by_policy() ==
-              TemplateURLData::CreatedByPolicy::kSiteSearch ||
-          turl_without_at->created_by_policy() ==
-              TemplateURLData::CreatedByPolicy::kSearchAggregator) &&
+  return turl_without_at->CreatedByNonDefaultSearchProviderPolicy() &&
          !turl_without_at->featured_by_policy();
 }
 
@@ -863,8 +852,7 @@
 TemplateURLService::GetFeaturedEnterpriseSearchEngines() const {
   TemplateURLVector result;
   for (const auto& turl : template_urls_) {
-    if (turl->created_by_policy() ==
-            TemplateURLData::CreatedByPolicy::kSiteSearch &&
+    if (turl->policy_origin() == TemplateURLData::PolicyOrigin::kSiteSearch &&
         turl->featured_by_policy()) {
       result.push_back(turl.get());
     }
@@ -1511,8 +1499,7 @@
         default_search_provider_->GetEngineType(search_terms_data());
     base::UmaHistogramEnumeration("Search.DefaultSearchProviderType2",
                                   engine_type, SEARCH_ENGINE_MAX);
-    if (default_search_provider_->created_by_policy() ==
-        TemplateURLData::CreatedByPolicy::kDefaultSearchProvider) {
+    if (default_search_provider_->CreatedByDefaultSearchProviderPolicy()) {
       base::UmaHistogramEnumeration(
           "Search.DefaultSearchProviderType2.SetByEnterprisePolicy",
           engine_type, SEARCH_ENGINE_MAX);
@@ -1601,8 +1588,7 @@
   syncer::SyncDataList current_data;
   for (const auto& turl : template_urls_) {
     // We don't sync keywords managed by policy.
-    if (turl->created_by_policy() !=
-        TemplateURLData::CreatedByPolicy::kNoPolicy) {
+    if (turl->CreatedByPolicy()) {
       continue;
     }
     // We don't sync extension-controlled search engines.
@@ -1854,8 +1840,7 @@
   }
 
   // Avoid syncing keywords managed by policy.
-  if (turl->created_by_policy() !=
-      TemplateURLData::CreatedByPolicy::kNoPolicy) {
+  if (turl->CreatedByPolicy()) {
     return;
   }
 
@@ -2181,10 +2166,7 @@
     }
   }
 
-  if (template_url->created_by_policy() ==
-          TemplateURLData::CreatedByPolicy::kSiteSearch ||
-      template_url->created_by_policy() ==
-          TemplateURLData::CreatedByPolicy::kSearchAggregator) {
+  if (template_url->CreatedByNonDefaultSearchProviderPolicy()) {
     enterprise_search_keyword_to_turl_.erase(keyword);
   }
 
@@ -2206,10 +2188,7 @@
     guid_to_turl_[template_url->sync_guid()] = template_url;
   }
 
-  if (template_url->created_by_policy() ==
-          TemplateURLData::CreatedByPolicy::kSiteSearch ||
-      template_url->created_by_policy() ==
-          TemplateURLData::CreatedByPolicy::kSearchAggregator) {
+  if (template_url->CreatedByNonDefaultSearchProviderPolicy()) {
     enterprise_search_keyword_to_turl_[keyword] = template_url;
   }
 
@@ -2735,8 +2714,7 @@
 
   for (auto i = template_urls->begin(); i != template_urls->end();) {
     TemplateURL* template_url = i->get();
-    if (template_url->created_by_policy() ==
-        TemplateURLData::CreatedByPolicy::kDefaultSearchProvider) {
+    if (template_url->CreatedByDefaultSearchProviderPolicy()) {
       if (default_from_prefs &&
           TemplateURL::MatchesData(template_url, default_from_prefs,
                                    search_terms_data())) {
@@ -2779,8 +2757,8 @@
     if (new_data.sync_guid.empty()) {
       new_data.GenerateSyncGUID();
     }
-    new_data.created_by_policy =
-        TemplateURLData::CreatedByPolicy::kDefaultSearchProvider;
+    new_data.policy_origin =
+        TemplateURLData::PolicyOrigin::kDefaultSearchProvider;
     new_data.enforced_by_policy = is_mandatory;
     new_data.safe_for_autoreplace = false;
     new_data.is_active = TemplateURLData::ActiveStatus::kTrue;
@@ -2829,8 +2807,7 @@
     // Play API created engines, as those also seem local-only and should not
     // be merged into Synced engines. crbug.com/1414224.
     if (local_turl->type() == TemplateURL::NORMAL &&
-        local_turl->created_by_policy() ==
-            TemplateURLData::CreatedByPolicy::kNoPolicy &&
+        !local_turl->CreatedByPolicy() &&
         !local_turl->created_from_play_api()) {
       local_duplicates.push_back(local_turl);
     }
@@ -3071,10 +3048,7 @@
 
   // Do not replace existing search engines if `candidate` was created by the
   // policy.
-  if (candidate->created_by_policy() ==
-          TemplateURLData::CreatedByPolicy::kSiteSearch ||
-      candidate->created_by_policy() ==
-          TemplateURLData::CreatedByPolicy::kSearchAggregator) {
+  if (candidate->CreatedByNonDefaultSearchProviderPolicy()) {
     return false;
   }
 
@@ -3192,8 +3166,7 @@
     bool conflicts_with_active =
         std::any_of(match_range.first, match_range.second,
                     [](const KeywordToTURL::value_type& entry) {
-                      return entry.second->created_by_policy() ==
-                                 TemplateURLData::CreatedByPolicy::kNoPolicy &&
+                      return !entry.second->CreatedByPolicy() &&
                              !entry.second->safe_for_autoreplace();
                     });
     SearchPolicyConflictType type =
diff --git a/components/search_engines/template_url_service_unittest.cc b/components/search_engines/template_url_service_unittest.cc
index 1e19baee..846610c 100644
--- a/components/search_engines/template_url_service_unittest.cc
+++ b/components/search_engines/template_url_service_unittest.cc
@@ -349,8 +349,7 @@
   const TemplateURL* policy_engine =
       template_url_service().GetDefaultSearchProvider();
   ASSERT_EQ(policy_engine->keyword(), policy_engine_data.keyword());
-  ASSERT_EQ(policy_engine->created_by_policy(),
-            TemplateURLData::CreatedByPolicy::kDefaultSearchProvider);
+  ASSERT_TRUE(policy_engine->CreatedByDefaultSearchProviderPolicy());
 
   const auto new_play_engine_data =
       CreatePlayAPITemplateURLData(kNewPlayEngineKeyword);
@@ -383,8 +382,7 @@
   const TemplateURL* policy_engine =
       template_url_service().GetDefaultSearchProvider();
   ASSERT_EQ(policy_engine->keyword(), policy_engine_data.keyword());
-  ASSERT_EQ(policy_engine->created_by_policy(),
-            TemplateURLData::CreatedByPolicy::kDefaultSearchProvider);
+  ASSERT_TRUE(policy_engine->CreatedByDefaultSearchProviderPolicy());
 
   // Add the Play API engine using the same keyword as the policy engine.
   const auto new_play_engine_data =
diff --git a/components/search_engines/template_url_unittest.cc b/components/search_engines/template_url_unittest.cc
index 54fcad05..754fa54 100644
--- a/components/search_engines/template_url_unittest.cc
+++ b/components/search_engines/template_url_unittest.cc
@@ -36,7 +36,7 @@
 #include "ui/base/device_form_factor.h"
 
 using base::ASCIIToUTF16;
-using CreatedByPolicy = TemplateURLData::CreatedByPolicy;
+using PolicyOrigin = TemplateURLData::PolicyOrigin;
 using RequestSource = SearchTermsData::RequestSource;
 
 namespace {
@@ -3119,7 +3119,7 @@
 
 struct IsBetterThanEngineTestEngine {
   std::u16string keyword;
-  CreatedByPolicy created_by_policy = CreatedByPolicy::kNoPolicy;
+  PolicyOrigin policy_origin = PolicyOrigin::kNoPolicy;
   bool enforced_by_policy = false;
   bool featured_by_policy = false;
   bool safe_for_autoreplace = false;
@@ -3133,7 +3133,7 @@
   template_url_data.SetShortName(engine.keyword + u"_name");
   template_url_data.SetURL("https://" + base::UTF16ToUTF8(engine.keyword) +
                            ".com/q={searchTerms}");
-  template_url_data.created_by_policy = engine.created_by_policy;
+  template_url_data.policy_origin = engine.policy_origin;
   template_url_data.enforced_by_policy = engine.enforced_by_policy;
   template_url_data.featured_by_policy = engine.featured_by_policy;
   template_url_data.safe_for_autoreplace = engine.safe_for_autoreplace;
@@ -3151,7 +3151,7 @@
         .better_engine =
             {
                 .keyword = u"kw",
-                .created_by_policy = CreatedByPolicy::kSiteSearch,
+                .policy_origin = PolicyOrigin::kSiteSearch,
             },
         .worse_engine =
             {
@@ -3169,7 +3169,7 @@
         .worse_engine =
             {
                 .keyword = u"kw",
-                .created_by_policy = CreatedByPolicy::kSiteSearch,
+                .policy_origin = PolicyOrigin::kSiteSearch,
             },
     },
     {
@@ -3177,7 +3177,7 @@
         .better_engine =
             {
                 .keyword = u"@kw",
-                .created_by_policy = CreatedByPolicy::kSiteSearch,
+                .policy_origin = PolicyOrigin::kSiteSearch,
                 .featured_by_policy = true,
             },
         .worse_engine =
@@ -3192,13 +3192,13 @@
         .better_engine =
             {
                 .keyword = u"@kw",
-                .created_by_policy = CreatedByPolicy::kSiteSearch,
+                .policy_origin = PolicyOrigin::kSiteSearch,
                 .featured_by_policy = true,
             },
         .worse_engine =
             {
                 .keyword = u"kw",
-                .created_by_policy = CreatedByPolicy::kSiteSearch,
+                .policy_origin = PolicyOrigin::kSiteSearch,
             },
     },
     {
@@ -3206,13 +3206,13 @@
         .better_engine =
             {
                 .keyword = u"kw",
-                .created_by_policy = CreatedByPolicy::kDefaultSearchProvider,
+                .policy_origin = PolicyOrigin::kDefaultSearchProvider,
                 .enforced_by_policy = true,
             },
         .worse_engine =
             {
                 .keyword = u"kw",
-                .created_by_policy = CreatedByPolicy::kNoPolicy,
+                .policy_origin = PolicyOrigin::kNoPolicy,
                 .safe_for_autoreplace = false,
             },
     },
@@ -3221,13 +3221,13 @@
         .better_engine =
             {
                 .keyword = u"kw",
-                .created_by_policy = CreatedByPolicy::kDefaultSearchProvider,
+                .policy_origin = PolicyOrigin::kDefaultSearchProvider,
                 .enforced_by_policy = true,
             },
         .worse_engine =
             {
                 .keyword = u"kw",
-                .created_by_policy = CreatedByPolicy::kDefaultSearchProvider,
+                .policy_origin = PolicyOrigin::kDefaultSearchProvider,
             },
     },
     {
@@ -3235,13 +3235,13 @@
         .better_engine =
             {
                 .keyword = u"kw",
-                .created_by_policy = CreatedByPolicy::kSiteSearch,
+                .policy_origin = PolicyOrigin::kSiteSearch,
                 .last_modified = base::Time::FromTimeT(2000),
             },
         .worse_engine =
             {
                 .keyword = u"kw",
-                .created_by_policy = CreatedByPolicy::kSiteSearch,
+                .policy_origin = PolicyOrigin::kSiteSearch,
                 .last_modified = base::Time::FromTimeT(1000),
             },
     },
@@ -3250,7 +3250,7 @@
         .better_engine =
             {
                 .keyword = u"kw",
-                .created_by_policy = CreatedByPolicy::kSearchAggregator,
+                .policy_origin = PolicyOrigin::kSearchAggregator,
             },
         .worse_engine =
             {
@@ -3268,7 +3268,7 @@
         .worse_engine =
             {
                 .keyword = u"kw",
-                .created_by_policy = CreatedByPolicy::kSearchAggregator,
+                .policy_origin = PolicyOrigin::kSearchAggregator,
             },
 
     },
@@ -3277,7 +3277,7 @@
         .better_engine =
             {
                 .keyword = u"@kw",
-                .created_by_policy = CreatedByPolicy::kSearchAggregator,
+                .policy_origin = PolicyOrigin::kSearchAggregator,
                 .featured_by_policy = true,
             },
         .worse_engine =
@@ -3292,13 +3292,13 @@
         .better_engine =
             {
                 .keyword = u"@kw",
-                .created_by_policy = CreatedByPolicy::kSearchAggregator,
+                .policy_origin = PolicyOrigin::kSearchAggregator,
                 .featured_by_policy = true,
             },
         .worse_engine =
             {
                 .keyword = u"kw",
-                .created_by_policy = CreatedByPolicy::kSearchAggregator,
+                .policy_origin = PolicyOrigin::kSearchAggregator,
             },
     },
 };
diff --git a/components/sync/base/features.cc b/components/sync/base/features.cc
index 3ae0449..187689cc 100644
--- a/components/sync/base/features.cc
+++ b/components/sync/base/features.cc
@@ -169,6 +169,12 @@
              "SyncPasswordCleanUpAccidentalBatchDeletions",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
+BASE_FEATURE(kMigrateAccountPrefs,
+             "MigrateAccountPrefs",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+#endif  // BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
+
 BASE_FEATURE(kSeparateLocalAndAccountThemes,
              "SeparateLocalAndAccountThemes",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/sync/base/features.h b/components/sync/base/features.h
index 5bfa181..f64152f 100644
--- a/components/sync/base/features.h
+++ b/components/sync/base/features.h
@@ -161,6 +161,12 @@
 // sync metadata isn't available (i.e. initial sync never completed).
 BASE_DECLARE_FEATURE(kSyncAlwaysForceImmediateStartIfTransportDataMissing);
 
+#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
+// If enabled, holds the account preference values under a dictionary in the
+// main preferences file.
+BASE_DECLARE_FEATURE(kMigrateAccountPrefs);
+#endif  // BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
+
 // If enabled, distinguishes between local and account themes.
 BASE_DECLARE_FEATURE(kSeparateLocalAndAccountThemes);
 
diff --git a/components/tracing/BUILD.gn b/components/tracing/BUILD.gn
index 1de469f..e4eb125 100644
--- a/components/tracing/BUILD.gn
+++ b/components/tracing/BUILD.gn
@@ -45,6 +45,8 @@
 
   if (is_win) {
     sources += [
+      "common/active_processes_win.cc",
+      "common/active_processes_win.h",
       "common/etw_consumer_win.cc",
       "common/etw_consumer_win.h",
       "common/etw_export_win.cc",
@@ -121,8 +123,14 @@
   data = [ "$root_gen_dir/third_party/perfetto/protos/perfetto/config/chrome/scenario_config.descriptor" ]
 
   if (is_win) {
-    sources += [ "common/etw_consumer_win_unittest.cc" ]
-    deps += [ "//third_party/perfetto:libperfetto" ]
+    sources += [
+      "common/active_processes_win_unittest.cc",
+      "common/etw_consumer_win_unittest.cc",
+    ]
+    deps += [
+      "//base/version_info:generate_version_info",
+      "//third_party/perfetto:libperfetto",
+    ]
   }
   deps += [
     ":background_tracing_utils",
diff --git a/components/tracing/common/active_processes_win.cc b/components/tracing/common/active_processes_win.cc
new file mode 100644
index 0000000..4e4c255
--- /dev/null
+++ b/components/tracing/common/active_processes_win.cc
@@ -0,0 +1,300 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/tracing/common/active_processes_win.h"
+
+#include "base/base_paths.h"
+#include "base/command_line.h"
+#include "base/path_service.h"
+#include "base/ranges/algorithm.h"
+#include "base/version.h"
+
+namespace tracing {
+
+namespace {
+
+// Returns the directory immediately above the current executable's directory if
+// the directory of the current executable is of the form "W.X.Y.Z"; otherwise,
+// returns the current executable's directory.
+base::FilePath DetermineApplicationDirectory() {
+  base::FilePath dir_path = base::PathService::CheckedGet(base::DIR_EXE);
+  if (base::Version(dir_path.BaseName().MaybeAsASCII()).IsValid()) {
+    // This is likely a production install, where the elevated tracing service
+    // is installed in the version directory.
+    return dir_path.DirName();
+  }
+  // Otherwise, this is likely a developer, where the elevated tracing service
+  // is in the build output directory next to the browser.
+  return dir_path;
+}
+
+// Returns true if `one` and `two` are equal or if `one` is a parent of `two`.
+bool IsSameOrParent(const base::FilePath& one, const base::FilePath& two) {
+  // Use a simple string comparison here, as the expectation is that the paths
+  // will be formatted the same if they truly are the same since they share a
+  // common origin in that case. There are cases where this will return a false
+  // negative, but for now this is acceptable since it will lead to under-
+  // rather than over-reporting.
+  return one == two || one.IsParent(two);
+}
+
+}  // namespace
+
+ActiveProcesses::Process::Process(uint32_t pid,
+                                  uint32_t parent_pid,
+                                  uint32_t session_id,
+                                  std::optional<base::win::Sid> sid,
+                                  std::string image_file_name,
+                                  std::wstring command_line)
+    : pid(pid),
+      parent_pid(parent_pid),
+      session_id(session_id),
+      sid(std::move(sid)),
+      image_file_name(std::move(image_file_name)),
+      command_line(std::move(command_line)),
+      category(Category::kOther) {}
+
+ActiveProcesses::Process::~Process() = default;
+
+ActiveProcesses::ActiveProcesses(base::ProcessId client_pid)
+    : client_pid_(client_pid),
+      application_dir_(DetermineApplicationDirectory()) {
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+ActiveProcesses::~ActiveProcesses() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void ActiveProcesses::AddProcess(uint32_t pid,
+                                 uint32_t parent_pid,
+                                 uint32_t session_id,
+                                 std::optional<base::win::Sid> sid,
+                                 std::string image_file_name,
+                                 std::wstring command_line) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  enum {
+    kNonClientAdded,
+    kClientAdded,
+    kDuplicateClientAdded,
+  } addition = kNonClientAdded;
+  if (pid != client_pid_) {
+    addition = kNonClientAdded;
+  } else if (!client_process_) {
+    addition = kClientAdded;
+  } else {
+    // A second process with the same pid as the client is not possible since
+    // the tracing service self-terminates when the client process terminates.
+    // Conservatively consider this to be an "other" process and forget about
+    // the client.
+    addition = kDuplicateClientAdded;
+    OnClientRemoved(client_process_.get());
+  }
+
+  auto [iter, inserted] = processes_.try_emplace(
+      pid, pid, parent_pid, session_id, std::move(sid),
+      std::move(image_file_name), std::move(command_line));
+  auto& process = iter->second;
+  if (!inserted) {
+    // Duplicate pid. The event for the removal of this pid must have been lost.
+    // Forget about the old process's threads before replacing it.
+    base::ranges::for_each(process.threads,
+                           [this](uint32_t tid) { threads_.erase(tid); });
+    process.threads.clear();
+    // Move the new process's properties into the instance.
+    process.parent_pid = parent_pid;
+    process.session_id = session_id;
+    process.sid = std::move(sid);
+    process.image_file_name = std::move(image_file_name);
+    process.command_line = std::move(command_line);
+  }
+
+  // Finally, set the process's category.
+  switch (addition) {
+    case kNonClientAdded:
+      process.category = DetermineCategory(process);
+      break;
+    case kClientAdded:
+      process.category = Category::kClient;  // This is the client's process.
+      OnClientAdded(&process);
+      break;
+    case kDuplicateClientAdded:
+      process.category = Category::kOther;
+      break;
+  }
+}
+
+void ActiveProcesses::RemoveProcess(uint32_t pid) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (pid == client_pid_ && client_process_) {
+    OnClientRemoved(client_process_.get());
+  }
+
+  if (auto iter = processes_.find(pid); iter != processes_.end()) {
+    // Forget about this process's threads if they haven't already been removed.
+    base::ranges::for_each(iter->second.threads,
+                           [this](uint32_t tid) { threads_.erase(tid); });
+    processes_.erase(iter);
+  }  // else the event for the addition of this process must have been lost.
+}
+
+void ActiveProcesses::AddThread(uint32_t pid,
+                                uint32_t tid,
+                                std::wstring thread_name) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  auto process_iter = processes_.find(pid);
+  if (process_iter == processes_.end()) {
+    // The event for the addition of this thread's process must have been lost.
+    // The reason for tracking threads is to map a tid to its process. Since it
+    // will not be possible to do so for this tid, skip adding it to `threads_`.
+    return;
+  }
+  auto [iter, inserted] =
+      threads_.try_emplace(tid, std::move(thread_name), &process_iter->second);
+  auto& [name, process_ptr] = iter->second;
+  if (!inserted) {
+    // The event for the removal of this tid must have been lost.
+    // Remove the thread from the previous process's collection.
+    process_ptr->threads.erase(tid);
+    // Associate this thread with its new name and process.
+    name = std::move(thread_name);
+    process_ptr = &process_iter->second;
+  }
+
+  // Add this thread to its process's collection.
+  process_ptr->threads.insert(tid);
+}
+
+void ActiveProcesses::SetThreadName(uint32_t pid,
+                                    uint32_t tid,
+                                    std::wstring thread_name) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  auto process_iter = processes_.find(pid);
+  if (process_iter == processes_.end()) {
+    // The event for the addition of this thread's process must have been lost.
+    return;
+  }
+  auto thread_iter = threads_.find(tid);
+  if (thread_iter == threads_.end()) {
+    // The event for the addition of this thread must have been lost.
+    return;
+  }
+  if (thread_iter->second.second.get() != &process_iter->second) {
+    // The pid and tid are both known, but don't relate. Aggressive id reuse
+    // and lost events make this possible.
+    return;
+  }
+  thread_iter->second.first = std::move(thread_name);
+}
+
+void ActiveProcesses::RemoveThread(uint32_t pid, uint32_t tid) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  auto iter = threads_.find(tid);
+  if (iter == threads_.end()) {
+    // The event for the addition of this thread must have been lost.
+    return;
+  }
+  auto& process_ptr = iter->second.second;
+  if (process_ptr->pid != pid) {
+    // Events for the removal of this tid and its addition to a different pid
+    // must have been lost. Ignore this removal to avoid corrupting tracking for
+    // the other process
+    return;
+  }
+  process_ptr->threads.erase(tid);
+  threads_.erase(iter);
+}
+
+ActiveProcesses::Category ActiveProcesses::GetThreadCategory(
+    uint32_t tid) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (auto iter = threads_.find(tid); iter != threads_.end()) {
+    return iter->second.second->category;
+  }
+  return Category::kOther;
+}
+
+std::wstring_view ActiveProcesses::GetThreadName(uint32_t tid) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (auto iter = threads_.find(tid); iter != threads_.end()) {
+    return iter->second.first;
+  }
+  return {};
+}
+
+void ActiveProcesses::OnClientAdded(Process* client) {
+  client_process_ = client;
+  client_in_application_ =
+      IsSameOrParent(application_dir_, GetProgram(*client).DirName());
+
+  // Re-categorize all existing "other" processes to detect client processes.
+  base::ranges::for_each(
+      processes_,
+      [this](auto& process) {
+        if (process.category == Category::kOther) {
+          process.category = DetermineCategory(process);
+        }
+      },
+      &PidProcessMap::value_type::second);
+}
+
+void ActiveProcesses::OnClientRemoved(Process* client) {
+  client_process_ = nullptr;
+  client_in_application_ = false;
+
+  // All previously-discovered client processes are now "other" processes.
+  base::ranges::for_each(
+      processes_,
+      [](auto& process) {
+        if (process.category == Category::kClient) {
+          process.category = Category::kOther;
+        }
+      },
+      &PidProcessMap::value_type::second);
+}
+
+ActiveProcesses::Category ActiveProcesses::DetermineCategory(
+    const Process& process) {
+  // The session id for Idle, System, Secure System, Registry, smss.exe, and
+  // MemCompression.
+  static constexpr uint32_t kSystemSession = 0xFFFFFFFF;
+
+  if (process.session_id == kSystemSession) {
+    return Category::kSystem;  // Windows kernel processes.
+  }
+
+  if (!client_process_) {
+    return Category::kOther;  // Not yet possible to associate with the client.
+  }
+
+  const Process& client = *client_process_;
+  if (process.session_id != client.session_id) {
+    return Category::kOther;  // Not running in the same session as the client.
+  }
+
+  if (!process.sid.has_value() || process.sid != client.sid) {
+    return Category::kOther;  // Not the same user.
+  }
+
+  if (client_in_application_ &&
+      IsSameOrParent(application_dir_, GetProgram(process).DirName())) {
+    return Category::kClient;  // A program belonging to the client.
+  }
+
+  return Category::kOther;
+}
+
+// static
+base::FilePath ActiveProcesses::GetProgram(const Process& process) {
+  return base::CommandLine::FromString(process.command_line).GetProgram();
+}
+
+}  // namespace tracing
diff --git a/components/tracing/common/active_processes_win.h b/components/tracing/common/active_processes_win.h
new file mode 100644
index 0000000..61803bd3
--- /dev/null
+++ b/components/tracing/common/active_processes_win.h
@@ -0,0 +1,152 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_TRACING_COMMON_ACTIVE_PROCESSES_WIN_H_
+#define COMPONENTS_TRACING_COMMON_ACTIVE_PROCESSES_WIN_H_
+
+#include <stdint.h>
+
+#include <optional>
+#include <string>
+#include <string_view>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+
+#include "base/files/file_path.h"
+#include "base/memory/raw_ptr.h"
+#include "base/process/process_handle.h"
+#include "base/sequence_checker.h"
+#include "base/win/sid.h"
+#include "components/tracing/tracing_export.h"
+
+namespace tracing {
+
+// A helper that tracks active processes on the system and categorizes them,
+// providing an efficient determination of a process's category given a thread
+// id. An instance of this class is expected to be populated dynamically based
+// on Process and Thread events sourced from the Windows system event provider
+// via ETW. It provides accurate results to the extent possible, given that
+// trace events may be lost.
+class TRACING_EXPORT ActiveProcesses {
+ public:
+  // A process's category. Values of this type must be sequential and begin with
+  // zero, but are not persisted or transmitted. Values may be reordered, added,
+  // or removed.
+  enum class Category {
+    // A process that belongs to the tracing client.
+    kClient = 0,
+    // A process that belongs to the system.
+    kSystem = 1,
+    // Any process that doesn't meet the criteria above.
+    kOther = 2,
+  };
+
+  // Constructs an instance for a trace initiated on behalf of the process
+  // identified by `client_pid`. This and 1) any of its direct children of it
+  // with the same image filename and 2) any other program residing in the same
+  // directory tree will be categorized as belonging to the tracing client.
+  explicit ActiveProcesses(base::ProcessId client_pid);
+  ActiveProcesses(const ActiveProcesses&) = delete;
+  ActiveProcesses& operator=(const ActiveProcesses&) = delete;
+  ~ActiveProcesses();
+
+  // Adds a process to the collection of active processes. The process is
+  // categorized upon addition unless the client process has yet to be added.
+  // If `pid` matches `client_pid`, all previously-added processes are
+  // categorized.
+  void AddProcess(uint32_t pid,
+                  uint32_t parent_pid,
+                  uint32_t session_id,
+                  std::optional<base::win::Sid> sid,
+                  std::string image_file_name,
+                  std::wstring command_line);
+
+  // Removes a process and all of its threads from the collection.
+  void RemoveProcess(uint32_t pid);
+
+  // Adds a process's thread to the collection.
+  void AddThread(uint32_t pid, uint32_t tid, std::wstring thread_name);
+
+  // Sets the name of a thread in the collection.
+  void SetThreadName(uint32_t pid, uint32_t tid, std::wstring thread_name);
+
+  // Remove's a process's thread from the collection, if it is present.
+  void RemoveThread(uint32_t pid, uint32_t tid);
+
+  // Returns the category for the process to which the thread `tid` belongs.
+  // Returns kOther if `tid` is unknown.
+  Category GetThreadCategory(uint32_t tid) const;
+
+  // Returns a thread's name, or an empty view if not found or unset. The
+  // returned view may become invalidated following any other operation on this
+  // instance.
+  std::wstring_view GetThreadName(uint32_t tid) const;
+
+ private:
+  struct Process {
+    Process(uint32_t pid,
+            uint32_t parent_pid,
+            uint32_t session_id,
+            std::optional<base::win::Sid> sid,
+            std::string image_file_name,
+            std::wstring command_line);
+    ~Process();
+
+    uint32_t pid;
+    uint32_t parent_pid;
+    uint32_t session_id;
+    std::optional<base::win::Sid> sid;
+    std::string image_file_name;
+    std::wstring command_line;
+    Category category;
+    std::unordered_set<uint32_t> threads;
+  };
+
+  // Handles addition of the `Process` corresponding to the tracing client. All
+  // previously-added processes of type `kOther` are recategorized.
+  void OnClientAdded(Process* client);
+
+  // Handles removal of the `Process` corresponding to the tracing client. All
+  // previously-added processes of type `kClient` are recategorized as
+  // `kOther`.
+  void OnClientRemoved(Process* client);
+
+  // Compute and returns the category of `process`.
+  Category DetermineCategory(const Process& process);
+
+  // Returns the first component of `process`'s `command_line.
+  static base::FilePath GetProgram(const Process& process);
+
+  // The pid of the client process on behalf of which traces are collected.
+  const base::ProcessId client_pid_;
+
+  // The path to the application directory of which the service is a part. In
+  // the case of Google Chrome, this is the path to the "Application" directory
+  // containing chrome.exe and the version directory.
+  const base::FilePath application_dir_;
+
+  // True if the client appears to "belong to" the service, in the sense that it
+  // resides either in the same directory as the service or one directory above
+  // if the service is in a version directory.
+  bool client_in_application_ = false;
+
+  // A mapping of a process's id (pid) to its `Process` struct.
+  using PidProcessMap = std::unordered_map<uint32_t, Process>;
+  PidProcessMap processes_;
+
+  // A mapping of a thread's id (tid) to its name and corresponding process.
+  std::unordered_map<uint32_t, std::pair<std::wstring, raw_ptr<Process>>>
+      threads_;
+
+  // The `Process` struct with pid `client_pid_`, or null if the process has
+  // not yet been added or has been removed.
+  raw_ptr<Process> client_process_ = nullptr;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+};
+
+}  // namespace tracing
+
+#endif  // COMPONENTS_TRACING_COMMON_ACTIVE_PROCESSES_WIN_H_
diff --git a/components/tracing/common/active_processes_win_unittest.cc b/components/tracing/common/active_processes_win_unittest.cc
new file mode 100644
index 0000000..e675d758
--- /dev/null
+++ b/components/tracing/common/active_processes_win_unittest.cc
@@ -0,0 +1,549 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/tracing/common/active_processes_win.h"
+
+#include <windows.h>
+
+#include <optional>
+
+#include "base/base_paths.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/process/process.h"
+#include "base/test/scoped_path_override.h"
+#include "base/threading/platform_thread.h"
+#include "base/version_info/version_info_values.h"
+#include "base/win/access_token.h"
+#include "base/win/sid.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace tracing {
+
+class ActiveProcessesTest : public testing::Test {
+ protected:
+  using PidAndTid = std::pair<base::ProcessId, base::PlatformThreadId>;
+
+  // The pid and tid of the client. Named "base" because the offsets below are
+  // applied to compute distinct pids and tids for other processes.
+  static constexpr uint32_t kBasePid = 0x1000;
+  static constexpr uint32_t kBaseTid = 0x1000;
+
+  // Offsets from the bases above for pids and tids for other processes.
+  static constexpr int kChildOffset = 100;
+  static constexpr int kUnrelatedOffset = 200;
+  static constexpr int kIndependentOffset = 300;
+  static constexpr int kSystemOffset = 400;
+
+  // testing::Test:
+  void SetUp() override {
+    // Create a version directory %TMP%\random\W.X.Y.Z.
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    fake_dir_exe_ =
+        temp_dir_.GetPath().Append(FILE_PATH_LITERAL(PRODUCT_VERSION));
+    ASSERT_TRUE(base::CreateDirectory(fake_dir_exe_));
+
+    // Pretend that it is the dir in which the current executable is running.
+    dir_exe_override_.emplace(base::DIR_EXE, fake_dir_exe_,
+                              /*is_absolute=*/true, /*create=*/false);
+
+    // Make a command line for a client residing in %TMP%\random.
+    base::CommandLine client_command_line(
+        temp_dir_.GetPath().AppendASCII(client_image_file_name_));
+    client_command_line.AppendArgNative(L"arg1");
+    client_command_line.AppendSwitchNative("switch1", L"value1");
+    client_command_line.AppendSwitch("switch2");
+    client_command_line.AppendArgNative(L"arg2");
+    client_command_line_ = client_command_line.GetCommandLineString();
+
+    // Make a command line for an external client residing in %TMP%.
+    external_client_command_line_ =
+        base::CommandLine(
+            temp_dir_.GetPath().DirName().AppendASCII(client_image_file_name_))
+            .GetCommandLineString();
+
+    // Now construct the instance to test.
+    active_processes_.emplace(kBasePid);
+  }
+
+  ActiveProcesses& active_processes() { return *active_processes_; }
+
+  // Some random sid.
+  const base::win::Sid& random_user_sid() const { return random_user_sid_; }
+
+  // The file name of the current process's image.
+  const std::string& client_image_file_name() const {
+    return client_image_file_name_;
+  }
+
+  // The command line string of a client that belongs to the application.
+  const std::wstring& client_command_line() const {
+    return client_command_line_;
+  }
+
+  // The command line string of a client that is unrelated to the application.
+  const std::wstring& external_client_command_line() const {
+    return external_client_command_line_;
+  }
+
+  // Adds the client.
+  PidAndTid AddClient() {
+    active_processes().AddProcess(
+        kBasePid, /*parent_pid=*/0, /*session_id=*/4, random_user_sid().Clone(),
+        client_image_file_name(), client_command_line());
+    active_processes().AddThread(kBasePid, kBaseTid, /*thread_name=*/{});
+    return {kBasePid, kBaseTid};
+  }
+
+  // Adds a child process of the client -- same image file name, parent pid
+  // matches the client.
+  PidAndTid AddChild() {
+    const base::ProcessId child_pid = kBasePid + kChildOffset;
+    const base::PlatformThreadId child_tid = kBaseTid + kChildOffset;
+    active_processes().AddProcess(
+        child_pid, kBasePid, /*session_id=*/4, random_user_sid().Clone(),
+        client_image_file_name(), client_command_line());
+    active_processes().AddThread(child_pid, child_tid, /*thread_name=*/{});
+    return {child_pid, child_tid};
+  }
+
+  // Adds a process unrelated to the client and returns its pid and a tid.
+  // `unrelated_pid` may be set to force a specific pid to be used.
+  PidAndTid AddUnrelated(base::ProcessId unrelated_pid = kBasePid +
+                                                         kUnrelatedOffset) {
+    base::CommandLine unrelated_command_line(base::CommandLine::NO_PROGRAM);
+    unrelated_command_line.ParseFromString(client_command_line());
+    unrelated_command_line.SetProgram(
+        unrelated_command_line.GetProgram().DirName().DirName().Append(
+            FILE_PATH_LITERAL("unrelated.exe")));
+
+    const base::PlatformThreadId unrelated_tid = kBaseTid + kUnrelatedOffset;
+    active_processes().AddProcess(
+        unrelated_pid, /*parent_pid=*/0, /*session_id=*/4,
+        random_user_sid().Clone(), "unrelated.exe",
+        unrelated_command_line.GetCommandLineString());
+    active_processes().AddThread(unrelated_pid, unrelated_tid,
+                                 /*thread_name=*/{});
+    return {unrelated_pid, unrelated_tid};
+  }
+
+  // Adds an independent process of the client -- in the same directory tree.
+  PidAndTid AddIndependent() {
+    base::CommandLine independent_command_line(base::CommandLine::NO_PROGRAM);
+    independent_command_line.ParseFromString(client_command_line());
+    independent_command_line.SetProgram(
+        independent_command_line.GetProgram()
+            .DirName()
+            .Append(FILE_PATH_LITERAL("1.2.3"))
+            .Append(FILE_PATH_LITERAL("independent.exe")));
+
+    const base::ProcessId independent_pid = kBasePid + kIndependentOffset;
+    const base::PlatformThreadId independent_tid =
+        kBaseTid + kIndependentOffset;
+    active_processes().AddProcess(
+        independent_pid, /*parent_pid=*/0, /*session_id=*/4,
+        random_user_sid().Clone(), "independent.exe",
+        independent_command_line.GetCommandLineString());
+    active_processes().AddThread(independent_pid, independent_tid,
+                                 /*thread_name=*/{});
+    return {independent_pid, independent_tid};
+  }
+
+ private:
+  const std::string client_image_file_name_{"client.exe"};
+  const base::win::Sid random_user_sid_{base::win::Sid::GenerateRandomSid()};
+  base::ScopedTempDir temp_dir_;
+  base::FilePath fake_dir_exe_;
+  std::optional<base::ScopedPathOverride> dir_exe_override_;
+  std::wstring client_command_line_;
+  std::wstring external_client_command_line_;
+
+  // The base pid identifies the tracing client.
+  std::optional<ActiveProcesses> active_processes_;
+};
+
+TEST_F(ActiveProcessesTest, UnknownTidIsOther) {
+  ASSERT_EQ(active_processes().GetThreadCategory(kBaseTid),
+            ActiveProcesses::Category::kOther);
+}
+
+// Tests that a thread added for an unknown process is considered an "other"
+// process.
+TEST_F(ActiveProcessesTest, TidForUnknownPidIsOther) {
+  active_processes().AddThread(kBasePid, kBaseTid, /*thread_name=*/{});
+  ASSERT_EQ(active_processes().GetThreadCategory(kBaseTid),
+            ActiveProcesses::Category::kOther);
+}
+
+TEST_F(ActiveProcessesTest, ClientIsClient) {
+  // Add the client process and a thread, and confirm that it is categorized
+  // properly.
+  const auto [client_pid, client_tid] = AddClient();
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+}
+
+// Tests that categorization of the client works as threads come and go.
+TEST_F(ActiveProcessesTest, ClientThreadActivity) {
+  // Add the client and a couple of threads.
+  const auto [client_pid, client_tid] = AddClient();
+  const auto client_tid2 = client_tid + 1;
+  active_processes().AddThread(client_pid, client_tid2, /*thread_name=*/{});
+
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid2),
+            ActiveProcesses::Category::kClient);
+
+  // Now remove a thread.
+  active_processes().RemoveThread(client_pid, client_tid2);
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid2),
+            ActiveProcesses::Category::kOther);
+
+  // Now remove the process.
+  active_processes().RemoveProcess(client_pid);
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kOther);
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid2),
+            ActiveProcesses::Category::kOther);
+}
+
+// Tests that a child process of the client using the same image name is
+// categorized as a client proc.
+TEST_F(ActiveProcessesTest, ChildOfClient) {
+  // Add the client.
+  const auto [client_pid, client_tid] = AddClient();
+
+  // Add a child process of the client -- same image file name, parent pid
+  // matches the client.
+  const auto [child_pid, child_tid] = AddChild();
+
+  // The child is categorized as a Client process.
+  ASSERT_EQ(active_processes().GetThreadCategory(child_tid),
+            ActiveProcesses::Category::kClient);
+
+  // The child going away shouldn't change the categorization of the client.
+  active_processes().RemoveProcess(child_pid);
+  ASSERT_EQ(active_processes().GetThreadCategory(child_tid),
+            ActiveProcesses::Category::kOther);
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+}
+
+// Tests that a child process of the client using the same image name is
+// categorized as a client proc once the client is added.
+TEST_F(ActiveProcessesTest, ClientAfterChild) {
+  // Add a child process of the client -- same image file name, parent pid
+  // matches the client.
+  const auto [child_pid, child_tid] = AddChild();
+
+  // The client hasn't been added, so the child is still "other".
+  ASSERT_EQ(active_processes().GetThreadCategory(child_tid),
+            ActiveProcesses::Category::kOther);
+
+  // Add the client.
+  const auto [client_pid, client_tid] = AddClient();
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+
+  // Now the child is categorized as a Client process.
+  ASSERT_EQ(active_processes().GetThreadCategory(child_tid),
+            ActiveProcesses::Category::kClient);
+
+  // When the client goes away, the child is recategorized as "other".
+  active_processes().RemoveProcess(client_pid);
+  ASSERT_EQ(active_processes().GetThreadCategory(child_tid),
+            ActiveProcesses::Category::kOther);
+}
+
+// Tests that a process unrelated to the client is categorized as "other".
+TEST_F(ActiveProcessesTest, UnrelatedProcess) {
+  // Add a process unrelated to the client -- in some other directory tree.
+  const auto [unrelated_pid, unrelated_tid] = AddUnrelated();
+  ASSERT_EQ(active_processes().GetThreadCategory(unrelated_tid),
+            ActiveProcesses::Category::kOther);
+
+  // Add the client.
+  const auto [client_pid, client_tid] = AddClient();
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+
+  // The unrelated process is still categorized as "other".
+  ASSERT_EQ(active_processes().GetThreadCategory(unrelated_tid),
+            ActiveProcesses::Category::kOther);
+}
+
+// Tests that a process whose program resides within the directory tree of the
+// client is categorized as a client proc.
+TEST_F(ActiveProcessesTest, ProgramOfClient) {
+  // Add the client.
+  const auto [client_pid, client_tid] = AddClient();
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+
+  // Add an independent process of the client -- in the same directory tree.
+  const auto [independent_pid, independent_tid] = AddIndependent();
+
+  // The independent is categorized as a Client process.
+  ASSERT_EQ(active_processes().GetThreadCategory(independent_tid),
+            ActiveProcesses::Category::kClient);
+
+  // The independent going away shouldn't change the categorization of the
+  // client.
+  active_processes().RemoveProcess(independent_pid);
+  ASSERT_EQ(active_processes().GetThreadCategory(independent_tid),
+            ActiveProcesses::Category::kOther);
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+}
+
+// Tests that a process whose program resides within the directory tree of the
+// client is categorized as a client proc once the client is added.
+TEST_F(ActiveProcessesTest, ClientAfterProgram) {
+  // Add an independent process of the client -- in the same directory tree.
+  const auto [independent_pid, independent_tid] = AddIndependent();
+
+  // The client hasn't been added, so the independent is still "other".
+  ASSERT_EQ(active_processes().GetThreadCategory(independent_tid),
+            ActiveProcesses::Category::kOther);
+
+  // Add the client.
+  const auto [client_pid, client_tid] = AddClient();
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+
+  // Now the independent is categorized as a Client process.
+  ASSERT_EQ(active_processes().GetThreadCategory(independent_tid),
+            ActiveProcesses::Category::kClient);
+
+  // When the client goes away, the independent is recategorized as "other".
+  active_processes().RemoveProcess(client_pid);
+  ASSERT_EQ(active_processes().GetThreadCategory(independent_tid),
+            ActiveProcesses::Category::kOther);
+}
+
+// Tests that a process matching the client, but running as another user, is
+// categorized as "other".
+TEST_F(ActiveProcessesTest, ClientOtherUser) {
+  // Add the client.
+  const auto [client_pid, client_tid] = AddClient();
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+
+  // Add another instance of the client running as another user.
+  const base::ProcessId other_user_pid = client_pid + 1;
+  const base::PlatformThreadId other_user_tid = client_tid + 1;
+  active_processes().AddProcess(
+      other_user_pid, /*parent_pid=*/0, /*session_id=*/4,
+      base::win::Sid::GenerateRandomSid(), client_image_file_name(),
+      client_command_line());
+  active_processes().AddThread(other_user_pid, other_user_tid,
+                               /*thread_name=*/{});
+
+  // This process running as another user is categorized as "other".
+  ASSERT_EQ(active_processes().GetThreadCategory(other_user_tid),
+            ActiveProcesses::Category::kOther);
+}
+
+// Tests that a process matching the client, but running in another window
+// session, is categorized as "other".
+TEST_F(ActiveProcessesTest, ClientOtherSession) {
+  // Add the client.
+  const auto [client_pid, client_tid] = AddClient();
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+
+  // Add another instance of the client running in a different session
+  const base::ProcessId other_session_pid = client_pid + 1;
+  const base::PlatformThreadId other_session_tid = client_tid + 1;
+  active_processes().AddProcess(other_session_pid, /*parent_pid=*/0,
+                                /*session_id=*/5, random_user_sid().Clone(),
+                                client_image_file_name(),
+                                client_command_line());
+  active_processes().AddThread(other_session_pid, other_session_tid,
+                               /*thread_name=*/{});
+
+  // This process running in another session is categorized as "other".
+  ASSERT_EQ(active_processes().GetThreadCategory(other_session_tid),
+            ActiveProcesses::Category::kOther);
+}
+
+// Tests that a client that is external to the application is considered the
+// client and that other processes belonging to the application are not.
+TEST_F(ActiveProcessesTest, ExternalClient) {
+  // Add a client that does not reside in the application's directory.
+  const base::ProcessId client_pid = kBasePid;
+  const base::PlatformThreadId client_tid = kBaseTid;
+  active_processes().AddProcess(
+      client_pid, /*parent_pid=*/0, /*session_id=*/4, random_user_sid().Clone(),
+      client_image_file_name(), external_client_command_line());
+  active_processes().AddThread(client_pid, client_tid, /*thread_name=*/{});
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+
+  // If it launches a child of the application, those children are considered
+  // "other" with respect to the client.
+  const base::ProcessId child_pid = kBasePid + kChildOffset;
+  const base::PlatformThreadId child_tid = kBaseTid + kChildOffset;
+  active_processes().AddProcess(
+      child_pid, client_pid, /*session_id=*/4, random_user_sid().Clone(),
+      client_image_file_name(), client_command_line());
+  active_processes().AddThread(child_pid, child_tid, /*thread_name=*/{});
+  ASSERT_EQ(active_processes().GetThreadCategory(child_tid),
+            ActiveProcesses::Category::kOther);
+}
+
+// Tests that a system process is categorized as "other".
+TEST_F(ActiveProcessesTest, SystemProcess) {
+  // Any process running in session 0xFFFFFFFF is a system process.
+  const base::ProcessId system_pid = kBasePid + kSystemOffset;
+  const base::PlatformThreadId system_tid = kBaseTid + kSystemOffset;
+  active_processes().AddProcess(system_pid, /*parent_pid=*/0,
+                                /*session_id=*/0xFFFFFFFF,
+                                base::win::Sid::GenerateRandomSid(), "system",
+                                /*command_line=*/{});
+  active_processes().AddThread(system_pid, system_tid, /*thread_name=*/{});
+  ASSERT_EQ(active_processes().GetThreadCategory(system_tid),
+            ActiveProcesses::Category::kSystem);
+}
+
+// Tests that inconsistencies from lost events are handled gracefully.
+TEST_F(ActiveProcessesTest, LostEvents) {
+  // Add the client, a child of it, and an unrelated process.
+  const auto [client_pid, client_tid] = AddClient();
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+
+  const auto [child_pid, child_tid] = AddChild();
+  ASSERT_EQ(active_processes().GetThreadCategory(child_tid),
+            ActiveProcesses::Category::kClient);
+
+  const auto [unrelated_pid, unrelated_tid] = AddUnrelated();
+  ASSERT_EQ(active_processes().GetThreadCategory(unrelated_tid),
+            ActiveProcesses::Category::kOther);
+
+  // Removing an unknown tid from an unknown pid is a noop.
+  active_processes().RemoveThread(client_pid + 1, client_tid + 1);
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+  ASSERT_EQ(active_processes().GetThreadCategory(child_tid),
+            ActiveProcesses::Category::kClient);
+
+  // Removing an unknown tid from a known pid is a noop.
+  active_processes().RemoveThread(client_pid, client_tid + 1);
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+  ASSERT_EQ(active_processes().GetThreadCategory(child_tid),
+            ActiveProcesses::Category::kClient);
+
+  // Removing a known tid from an unknown pid is a noop.
+  active_processes().RemoveThread(client_pid + 1, client_tid);
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+  ASSERT_EQ(active_processes().GetThreadCategory(child_tid),
+            ActiveProcesses::Category::kClient);
+
+  // Adding an existing tid to a different process removes the tid from the
+  // original.
+  active_processes().AddThread(client_pid, client_tid + 1, /*thread_name=*/{});
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid + 1),
+            ActiveProcesses::Category::kClient);
+  active_processes().AddThread(unrelated_pid, client_tid + 1,
+                               /*thread_name=*/{});
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid + 1),
+            ActiveProcesses::Category::kOther);
+
+  // Removing a pid also removes its tids.
+  active_processes().RemoveProcess(client_pid);
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kOther);
+}
+
+// Tests that a second process added with the same pid as a child of the client
+// leads to the child no longer categorized as a client proc.
+TEST_F(ActiveProcessesTest, DuplicatePid) {
+  // Add the client and a child of it.
+  const auto [client_pid, client_tid] = AddClient();
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+  const auto [child_pid, child_tid] = AddChild();
+  ASSERT_EQ(active_processes().GetThreadCategory(child_tid),
+            ActiveProcesses::Category::kClient);
+
+  // Imagine that events removing the child's thread and process are lost, and
+  // its pid is reused for a new process that is not related to the client.
+  const auto [unrelated_pid, unrelated_tid] = AddUnrelated(child_pid);
+  ASSERT_EQ(unrelated_pid, child_pid);
+  ASSERT_EQ(active_processes().GetThreadCategory(unrelated_tid),
+            ActiveProcesses::Category::kOther);
+  ASSERT_NE(unrelated_tid, child_tid);
+
+  // The tid of the replaced child is no longer considered related to the
+  // client.
+  ASSERT_EQ(active_processes().GetThreadCategory(child_tid),
+            ActiveProcesses::Category::kOther);
+}
+
+// Tests that a second process added with the same pid as the client leads to
+// the client being forgotten.
+TEST_F(ActiveProcessesTest, DuplicateClient) {
+  // Add the client.
+  const auto [client_pid, client_tid] = AddClient();
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+
+  // Imagine a new process with the same pid as the client is added. This should
+  // not be possible in practice since the tracing service observes termination
+  // of the client and exits, but a shutdown race plus lost events could make an
+  // unlikely event possible. The new process should be considered as "other".
+  const auto [unrelated_pid, unrelated_tid] = AddUnrelated(client_pid);
+  ASSERT_EQ(unrelated_pid, client_pid);
+  ASSERT_EQ(active_processes().GetThreadCategory(unrelated_tid),
+            ActiveProcesses::Category::kOther);
+
+  // The tid of the replaced process is no longer considered the client.
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kOther);
+}
+
+// Tests that SetThreadName works in the general case, and in the face of lost
+// events.
+TEST_F(ActiveProcessesTest, SetThreadName) {
+  // Getters return empty view for unknown inputs, while setter does nothing.
+  ASSERT_EQ(active_processes().GetThreadName(3), L"");
+  active_processes().SetThreadName(/*pid=*/2, /*tid=*/3, L"Hi");
+  ASSERT_EQ(active_processes().GetThreadName(3), L"");
+
+  // Add the client and a child.
+  const auto [client_pid, client_tid] = AddClient();
+  ASSERT_EQ(active_processes().GetThreadCategory(client_tid),
+            ActiveProcesses::Category::kClient);
+  const auto [child_pid, child_tid] = AddChild();
+  ASSERT_EQ(active_processes().GetThreadCategory(child_tid),
+            ActiveProcesses::Category::kClient);
+
+  // Set works on valid inputs.
+  ASSERT_EQ(active_processes().GetThreadName(client_tid), std::wstring_view());
+  active_processes().SetThreadName(client_pid, client_tid, L"Hi");
+  ASSERT_EQ(active_processes().GetThreadName(client_tid), L"Hi");
+
+  // Set is ignored for pid/tid mismatch.
+  active_processes().SetThreadName(child_pid, client_tid, L"Bye");
+  ASSERT_EQ(active_processes().GetThreadName(client_tid), L"Hi");
+
+  // Set is ignore for invalid tid.
+  active_processes().SetThreadName(client_pid, client_tid + 1, L"Bye");
+  ASSERT_EQ(active_processes().GetThreadName(client_tid), L"Hi");
+  ASSERT_EQ(active_processes().GetThreadName(client_tid + 1), L"");
+
+  // Set is ignore for invalid pid.
+  active_processes().SetThreadName(client_pid + 1, client_tid, L"Bye");
+  ASSERT_EQ(active_processes().GetThreadName(client_tid), L"Hi");
+}
+
+}  // namespace tracing
diff --git a/components/unified_consent/pref_names.cc b/components/unified_consent/pref_names.cc
index 51be18a..b71abb0 100644
--- a/components/unified_consent/pref_names.cc
+++ b/components/unified_consent/pref_names.cc
@@ -13,7 +13,5 @@
 const char kUrlKeyedAnonymizedDataCollectionEnabled[] =
     "url_keyed_anonymized_data_collection.enabled";
 
-const char kPageContentCollectionEnabled[] = "page_content_collection.enabled";
-
 }  // namespace prefs
 }  // namespace unified_consent
diff --git a/components/unified_consent/pref_names.h b/components/unified_consent/pref_names.h
index 40110a26..b59514d 100644
--- a/components/unified_consent/pref_names.h
+++ b/components/unified_consent/pref_names.h
@@ -28,9 +28,6 @@
 //     NewAnonymizedDataCollectionConsentHelper.
 extern const char kUrlKeyedAnonymizedDataCollectionEnabled[];
 
-// Whether the user has enabled sharing page content.
-extern const char kPageContentCollectionEnabled[];
-
 }  // namespace unified_consent::prefs
 
 #endif  // COMPONENTS_UNIFIED_CONSENT_PREF_NAMES_H_
diff --git a/components/unified_consent/unified_consent_service.cc b/components/unified_consent/unified_consent_service.cc
index 8e58c72..d90746c 100644
--- a/components/unified_consent/unified_consent_service.cc
+++ b/components/unified_consent/unified_consent_service.cc
@@ -191,7 +191,6 @@
       prefs::kUnifiedConsentMigrationState,
       static_cast<int>(MigrationState::kNotInitialized));
 #endif
-  registry->RegisterBooleanPref(prefs::kPageContentCollectionEnabled, false);
 }
 
 void UnifiedConsentService::SetUrlKeyedAnonymizedDataCollectionEnabled(
diff --git a/components/user_education/common/feature_promo/impl/common_preconditions.cc b/components/user_education/common/feature_promo/impl/common_preconditions.cc
index 66144bc..3cbc113 100644
--- a/components/user_education/common/feature_promo/impl/common_preconditions.cc
+++ b/components/user_education/common/feature_promo/impl/common_preconditions.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/functional/bind.h"
+#include "base/strings/stringprintf.h"
 #include "components/feature_engagement/public/tracker.h"
 #include "components/user_education/common/feature_promo/feature_promo_lifecycle.h"
 #include "components/user_education/common/feature_promo/feature_promo_precondition.h"
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 0598eca..184507a 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -4,8 +4,6 @@
 
 import("//base/allocator/partition_allocator/partition_alloc.gni")
 import("//build/buildflag_header.gni")
-import("//build/config/chromeos/ui_mode.gni")
-import("//build/config/chromeos/ui_mode.gni")
 import("//build/config/compiler/pgo/pgo.gni")
 import("//build/config/features.gni")
 import("//build/config/linux/pangocairo/pangocairo.gni")
@@ -88,7 +86,6 @@
     "//build:android_buildflags",
     "//build:branding_buildflags",
     "//build:chromecast_buildflags",
-    "//build:chromeos_buildflags",
     "//build/config/compiler:compiler_buildflags",
     "//cc",
     "//cc/animation",
@@ -2551,7 +2548,7 @@
   }
 
   # ChromeOS also defines linux but their memory-monitors conflict.
-  if (is_chromeos_ash) {
+  if (is_chromeos) {
     sources += [
       "gpu/chromeos/delegate_to_browser_gpu_service_accelerator_factory.cc",
       "gpu/chromeos/video_capture_dependencies.cc",
@@ -2856,7 +2853,7 @@
       frameworks += [ "CoreMedia.framework" ]
       weak_frameworks = [ "ScreenCaptureKit.framework" ]  # macOS 12.3
     }
-    if (is_chromeos_ash) {
+    if (is_chromeos) {
       sources += [
         "media/capture/desktop_capturer_ash.cc",
         "media/capture/desktop_capturer_ash.h",
@@ -3216,7 +3213,6 @@
       "date_time_chooser/android/date_time_chooser_android.h",
       "device_posture/device_posture_platform_provider_android.cc",
       "device_posture/device_posture_platform_provider_android.h",
-      "file_system_access/file_path_watcher/file_path_watcher_stub.cc",
       "font_unique_name_lookup/font_unique_name_lookup_android.cc",
       "font_unique_name_lookup/font_unique_name_lookup_android.h",
       "font_unique_name_lookup/font_unique_name_lookup_service.cc",
diff --git a/content/browser/accessibility/accessibility_action_browsertest.cc b/content/browser/accessibility/accessibility_action_browsertest.cc
index 89e7dbe..5758e08 100644
--- a/content/browser/accessibility/accessibility_action_browsertest.cc
+++ b/content/browser/accessibility/accessibility_action_browsertest.cc
@@ -17,7 +17,6 @@
 #include "base/test/test_timeouts.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/test/accessibility_notification_waiter.h"
 #include "content/public/test/browser_test.h"
diff --git a/content/browser/accessibility/browser_accessibility_state_impl.cc b/content/browser/accessibility/browser_accessibility_state_impl.cc
index e17a5c4..7f8a93d 100644
--- a/content/browser/accessibility/browser_accessibility_state_impl.cc
+++ b/content/browser/accessibility/browser_accessibility_state_impl.cc
@@ -21,7 +21,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/thread_pool.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
index d12a0f7..ec5015a 100644
--- a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
+++ b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -19,7 +19,6 @@
 #include "base/timer/elapsed_timer.h"
 #include "build/build_config.h"
 #include "build/chromecast_buildflags.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
index b542739..86087035 100644
--- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -18,7 +18,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
 #include "content/browser/accessibility/dump_accessibility_browsertest_base.h"
 #include "content/browser/web_contents/web_contents_impl.h"
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index ce3657f..81679e05 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -15,7 +15,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
 #include "content/browser/accessibility/dump_accessibility_browsertest_base.h"
diff --git a/content/browser/accessibility/hit_testing_browsertest.cc b/content/browser/accessibility/hit_testing_browsertest.cc
index b2c3e8c0..e4c8cd26 100644
--- a/content/browser/accessibility/hit_testing_browsertest.cc
+++ b/content/browser/accessibility/hit_testing_browsertest.cc
@@ -10,7 +10,6 @@
 #include "base/test/bind.h"
 #include "build/build_config.h"
 #include "build/chromecast_buildflags.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/ax_inspect_factory.h"
diff --git a/content/browser/android/synchronous_compositor_host.cc b/content/browser/android/synchronous_compositor_host.cc
index bd0c95b0..fdc8483 100644
--- a/content/browser/android/synchronous_compositor_host.cc
+++ b/content/browser/android/synchronous_compositor_host.cc
@@ -716,8 +716,7 @@
   if (on_compute_scroll_called_ ||
       !rwhva_->GetViewRenderInputRouter()->is_currently_scrolling_viewport()) {
     rwhva_->host()->ProgressFlingIfNeeded(args.frame_time);
-  } else if (base::FeatureList::IsEnabled(
-                 features::kWebViewSuppressTapDuringFling)) {
+  } else {
     // Normally, `OnComputeScroll` is called after `OnBeginFrame`, but before
     // `DemandDrawHwAsync`. So `OnBeginFrame` calls before the first draw will
     // end up here regardless of whether `OnComputeScroll` will be called. If
diff --git a/content/browser/audio/audio_service.cc b/content/browser/audio/audio_service.cc
index 63c4d957b..d461065 100644
--- a/content/browser/audio/audio_service.cc
+++ b/content/browser/audio/audio_service.cc
@@ -87,12 +87,12 @@
   if (!BrowserMainLoop::GetInstance())
     return;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH) && BUILDFLAG(USE_CRAS)
+#if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(USE_CRAS)
   if (GetContentClient()->browser()->EnforceSystemAudioEchoCancellation()) {
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kSystemAecEnabled);
   }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH) && BUILDFLAG(USE_CRAS)
+#endif  // BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(USE_CRAS)
 
   // TODO(crbug.com/40580951): Remove
   // BrowserMainLoop::GetAudioManager().
@@ -127,7 +127,7 @@
   switches.push_back(base::StrCat({switches::kAudioCodecsFromEDID, "=",
                                    base::NumberToString(codec_bitmask)}));
 #endif  // BUILDFLAG(ENABLE_PASSTHROUGH_AUDIO_CODECS)
-#if BUILDFLAG(IS_CHROMEOS_ASH) && BUILDFLAG(USE_CRAS)
+#if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(USE_CRAS)
   if (GetContentClient()->browser()->EnforceSystemAudioEchoCancellation()) {
     switches.push_back(switches::kSystemAecEnabled);
   }
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index 3237face..dacaf31 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -27,7 +27,6 @@
 #include "base/trace_event/trace_log.h"
 #include "build/build_config.h"
 #include "build/chromecast_buildflags.h"
-#include "build/chromeos_buildflags.h"
 #include "components/ukm/test_ukm_recorder.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/renderer_host/back_forward_cache_can_store_document_result.h"
diff --git a/content/browser/back_forward_cache_features_browsertest.cc b/content/browser/back_forward_cache_features_browsertest.cc
index 58084e2..068f5668 100644
--- a/content/browser/back_forward_cache_features_browsertest.cc
+++ b/content/browser/back_forward_cache_features_browsertest.cc
@@ -6,7 +6,6 @@
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/back_forward_cache_browsertest.h"
 #include "content/browser/generic_sensor/frame_sensor_provider_proxy.h"
 #include "content/browser/generic_sensor/web_contents_sensor_provider_proxy.h"
@@ -3920,7 +3919,7 @@
     adapter_ =
         base::MakeRefCounted<testing::NiceMock<device::MockBluetoothAdapter>>();
     device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     // In CHROMEOS build, even when |adapter_| object is released at TearDown()
     // it causes the test to fail on exit with an error indicating |adapter_| is
     // leaked.
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc
index cea4b4a1..3c86b406 100644
--- a/content/browser/browser_child_process_host_impl.cc
+++ b/content/browser/browser_child_process_host_impl.cc
@@ -29,7 +29,6 @@
 #include "base/token.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/metrics/histogram_controller.h"
 #include "components/tracing/common/tracing_switches.h"
 #include "content/browser/browser_main_loop.h"
@@ -678,7 +677,7 @@
     NotifyProcessLaunchedAndConnected(data_);
   }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   // In ChromeOS, there are still child processes of NaCl modules, and they
   // don't contribute to tracing actually. So do not register those clients
   // to the tracing service. See https://crbug.com/1101468.
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index 25777a0..72b73a2 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -27,7 +27,6 @@
 #include "base/notreached.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/download/public/common/in_progress_download_manager.h"
 #include "components/services/storage/privileged/mojom/indexed_db_control.mojom.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
diff --git a/content/browser/browser_context_impl.cc b/content/browser/browser_context_impl.cc
index 6e2831f..2e25e3c 100644
--- a/content/browser/browser_context_impl.cc
+++ b/content/browser/browser_context_impl.cc
@@ -33,7 +33,7 @@
 #include "media/mojo/services/video_decode_perf_history.h"
 #include "media/mojo/services/webrtc_video_perf_history.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "storage/browser/file_system/external_mount_points.h"
 #endif
 
@@ -296,7 +296,7 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
          !BrowserThread::IsThreadInitialized(BrowserThread::UI));
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   if (!external_mount_points_)
     external_mount_points_ = storage::ExternalMountPoints::CreateRefCounted();
   return external_mount_points_.get();
diff --git a/content/browser/browser_context_impl.h b/content/browser/browser_context_impl.h
index 29a99a9..f5a3c17b 100644
--- a/content/browser/browser_context_impl.h
+++ b/content/browser/browser_context_impl.h
@@ -11,7 +11,6 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/resource_context.h"
 #include "content/public/browser/shared_cors_origin_access_list.h"
@@ -156,7 +155,7 @@
   std::unique_ptr<ResourceContext> resource_context_ =
       std::make_unique<ResourceContext>();
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   scoped_refptr<storage::ExternalMountPoints> external_mount_points_;
 #endif
 };
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 2f5efe0..ab40e72 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -53,7 +53,6 @@
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "build/chromecast_buildflags.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/base/histograms.h"
 #include "components/discardable_memory/service/discardable_shared_memory_manager.h"
 #include "components/memory_pressure/multi_source_memory_pressure_monitor.h"
@@ -203,7 +202,7 @@
 #include "net/base/winsock_init.h"
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "services/data_decoder/public/cpp/data_decoder.h"
 #endif
@@ -383,7 +382,7 @@
   return monitor;
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 mojo::PendingRemote<data_decoder::mojom::BleScanParser> GetBleScanParser() {
   static base::NoDestructor<data_decoder::DataDecoder> decoder;
   mojo::PendingRemote<data_decoder::mojom::BleScanParser> ble_scan_parser;
@@ -391,7 +390,7 @@
       ble_scan_parser.InitWithNewPipeAndPassReceiver());
   return ble_scan_parser;
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 class OopDataDecoder : public data_decoder::ServiceProvider {
  public:
@@ -756,7 +755,7 @@
 
   base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
       sql::SqlMemoryDumpProvider::GetInstance(), "Sql", nullptr);
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   device::BluetoothAdapterFactory::SetBleScanParserCallback(
       base::BindRepeating(&GetBleScanParser));
 #else
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h
index 27b1a74..d761e64 100644
--- a/content/browser/browser_main_loop.h
+++ b/content/browser/browser_main_loop.h
@@ -16,7 +16,6 @@
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "base/types/strong_alias.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/browser_process_io_thread.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/browser_main_runner.h"
diff --git a/content/browser/browser_process_io_thread.cc b/content/browser/browser_process_io_thread.cc
index 2c3d067..3ccebd1 100644
--- a/content/browser/browser_process_io_thread.cc
+++ b/content/browser/browser_process_io_thread.cc
@@ -13,7 +13,6 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/browser_child_process_host_impl.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/child_process_host_impl.h"
@@ -113,7 +112,7 @@
 #if BUILDFLAG(CLANG_PROFILING)
       // On profiling build, browser_tests runs 10x slower.
       const int kMaxSecondsToWaitForNetworkProcess = 100;
-#elif BUILDFLAG(IS_CHROMEOS_ASH)
+#elif BUILDFLAG(IS_CHROMEOS)
       // ChromeOS will kill the browser process if it doesn't shut down within
       // 3 seconds, so make sure we wait for less than that.
       const int kMaxSecondsToWaitForNetworkProcess = 1;
diff --git a/content/browser/browsing_data/browsing_data_remover_impl_browsertest.cc b/content/browser/browsing_data/browsing_data_remover_impl_browsertest.cc
index 14629fc..d0447c9 100644
--- a/content/browser/browsing_data/browsing_data_remover_impl_browsertest.cc
+++ b/content/browser/browsing_data/browsing_data_remover_impl_browsertest.cc
@@ -697,19 +697,6 @@
 }
 
 namespace {
-// Provide BrowsingDataRemoverImplTrustTokenTest the Trust Tokens
-// feature as a mixin so that it gets set before the superclass initializes
-// the test's NetworkContext, as the NetworkContext's initialization must
-// occur with the feature enabled.
-class WithTrustTokensEnabled {
- public:
-  WithTrustTokensEnabled() {
-    feature_list_.InitAndEnableFeature(network::features::kPrivateStateTokens);
-  }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-};
 
 // Tests Trust Tokens clearing by calling
 // TrustTokenQueryAnswerer::HasTrustTokens with a TrustTokenQueryAnswerer
@@ -813,9 +800,8 @@
 
 }  // namespace
 
-class BrowsingDataRemoverImplTrustTokenTest
-    : public WithTrustTokensEnabled,
-      public BrowsingDataRemoverImplBrowserTest {};
+using BrowsingDataRemoverImplTrustTokenTest =
+    BrowsingDataRemoverImplBrowserTest;
 
 IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverImplTrustTokenTest, Remove) {
   TrustTokensTester tester(network_context());
diff --git a/content/browser/child_process_host_impl.cc b/content/browser/child_process_host_impl.cc
index 7cc8188..583a386 100644
--- a/content/browser/child_process_host_impl.cc
+++ b/content/browser/child_process_host_impl.cc
@@ -173,7 +173,7 @@
   child_process_->BindReceiver(std::move(receiver));
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 void ChildProcessHostImpl::ReinitializeLogging(
     uint32_t logging_dest,
     base::ScopedFD log_file_descriptor) {
@@ -183,7 +183,7 @@
       mojo::PlatformHandle(std::move(log_file_descriptor));
   child_process()->ReinitializeLogging(std::move(logging_settings));
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 base::Process& ChildProcessHostImpl::GetPeerProcess() {
   if (!peer_process_.IsValid()) {
diff --git a/content/browser/child_process_host_impl.h b/content/browser/child_process_host_impl.h
index 77bbaff..ad21f9f1 100644
--- a/content/browser/child_process_host_impl.h
+++ b/content/browser/child_process_host_impl.h
@@ -81,7 +81,7 @@
   void BindReceiver(mojo::GenericPendingReceiver receiver) override;
   void SetBatterySaverMode(bool battery_saver_mode_enabled) override;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   void ReinitializeLogging(uint32_t logging_dest,
                            base::ScopedFD log_file_descriptor) override;
 #endif
diff --git a/content/browser/compositor/image_transport_factory_browsertest.cc b/content/browser/compositor/image_transport_factory_browsertest.cc
index 2b75d61..1adea48 100644
--- a/content/browser/compositor/image_transport_factory_browsertest.cc
+++ b/content/browser/compositor/image_transport_factory_browsertest.cc
@@ -6,7 +6,6 @@
 
 #include "base/run_loop.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/viz/common/gpu/context_lost_observer.h"
 #include "components/viz/common/gpu/raster_context_provider.h"
 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
@@ -30,7 +29,7 @@
 
 // TODO(crbug.com/394083, crbug.com/1305007, crbug.com/1302879): Flaky on
 // ChromeOS, Linux, and Windows.
-#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
+#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
 #define MAYBE_TestLostContext DISABLED_TestLostContext
 #else
 #define MAYBE_TestLostContext TestLostContext
diff --git a/content/browser/compositor/viz_process_transport_factory.cc b/content/browser/compositor/viz_process_transport_factory.cc
index d36b140..c8986a39 100644
--- a/content/browser/compositor/viz_process_transport_factory.cc
+++ b/content/browser/compositor/viz_process_transport_factory.cc
@@ -21,7 +21,6 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/mojo_embedder/async_layer_tree_frame_sink.h"
 #include "cc/raster/single_thread_task_graph_runner.h"
 #include "cc/tiles/image_decode_cache_utils.h"
@@ -127,11 +126,11 @@
   }
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   void SetPreferredRefreshRate(float refresh_rate) override {
     compositor_->OnSetPreferredRefreshRate(refresh_rate);
   }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
  private:
   [[maybe_unused]] const raw_ptr<ui::Compositor> compositor_;
@@ -275,7 +274,7 @@
 
 void VizProcessTransportFactory::DisableGpuCompositing(
     ui::Compositor* guilty_compositor) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   // A fatal error has occurred and we can't fall back to software compositing
   // on CrOS. These can be unrecoverable hardware errors, or bugs that should
   // not happen. Crash the browser process to reset everything.
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index 7325d90..05240699 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -27,7 +27,6 @@
 #include "base/test/values_test_util.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/download/public/common/download_file_factory.h"
 #include "components/download/public/common/download_file_impl.h"
 #include "components/download/public/common/download_task_runner.h"
@@ -855,7 +854,7 @@
 // TODO(crbug.com/40156819) Android Lollipop has a problem with capturing
 // screenshot.
 // TODO(crbug.com/40815512): Failing on MacOS.
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_MAC)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
 #define MAYBE_CaptureScreenshotBeyondViewport_InnerScrollbarsAreShown \
   DISABLED_CaptureScreenshotBeyondViewport_InnerScrollbarsAreShown
 #else
@@ -898,7 +897,7 @@
 }
 
 // ChromeOS and Android don't support software compositing.
-#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
+#if !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)
 
 class NoGPUCaptureScreenshotTest : public CaptureScreenshotTest {
   void SetUpCommandLine(base::CommandLine* command_line) override {
@@ -957,7 +956,7 @@
   EXPECT_GT(static_cast<int>(SkColorGetB(bottom_left)), 128);
 }
 
-#endif  // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
+#endif  // !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)
 
 // Setting frame size (through RWHV) is not supported on Android.
 // This test seems to be very flaky on all platforms: https://crbug.com/801173
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc
index 6a3a2c2..a23f0fa 100644
--- a/content/browser/devtools/protocol/target_handler.cc
+++ b/content/browser/devtools/protocol/target_handler.cc
@@ -21,7 +21,6 @@
 #include "base/unguessable_token.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/devtools/browser_devtools_agent_host.h"
 #include "content/browser/devtools/devtools_agent_host_impl.h"
 #include "content/browser/devtools/devtools_manager.h"
diff --git a/content/browser/file_system/browser_file_system_helper.cc b/content/browser/file_system/browser_file_system_helper.cc
index e8a13f7..b3f2597 100644
--- a/content/browser/file_system/browser_file_system_helper.cc
+++ b/content/browser/file_system/browser_file_system_helper.cc
@@ -17,7 +17,6 @@
 #include "base/task/lazy_thread_pool_task_runner.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/thread_pool.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -187,7 +186,7 @@
     ChildProcessSecurityPolicyImpl* security_policy,
     int child_id,
     const storage::FileSystemContext* file_system_context) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   // The externalfile:// scheme is used in Chrome OS to open external files in a
   // browser tab.
   // TODO(https://crbug.com/858972): This seems like it could be forged by the
diff --git a/content/browser/file_system_access/features.cc b/content/browser/file_system_access/features.cc
index 97e27f1e..dcdcd88 100644
--- a/content/browser/file_system_access/features.cc
+++ b/content/browser/file_system_access/features.cc
@@ -6,8 +6,6 @@
 
 #include "base/feature_list.h"
 #include "build/build_config.h"
-#include "third_party/blink/public/common/features.h"
-#include "third_party/blink/public/common/features_generated.h"
 
 namespace content::features {
 
@@ -29,54 +27,4 @@
 BASE_FEATURE(kFileSystemAccessDirectoryIterationBlocklistCheck,
              "FileSystemAccessDirectoryIterationBlocklistCheck",
              base::FEATURE_ENABLED_BY_DEFAULT);
-
-// When enabled, sites are limited in how much underlying operating resources
-// they can access through the `FileSystemObserver` API. This limit is called
-// the quota limit. Without this enabled, sites will be limited by the system
-// limit.
-BASE_FEATURE(kFileSystemAccessObserverQuotaLimit,
-             "FileSystemAccessObserverQuotaLimit",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
-// On Linux, the quota limit is found by:
-// 1. Rounding down the system limit (read from
-//    /proc/sys/fs/inotify/max_user_watches) to the nearest
-//    `kFileSystemObserverQuotaLimitLinuxBucketSize`.
-// 2. Taking that max of that result and
-//    `kFileSystemObserverQuotaLimitLinuxMin`.
-// 3. And setting quota limit to `kFileSystemObserverQuotaLimitLinuxPercent`% of
-//    that result.
-BASE_FEATURE_PARAM(size_t,
-                   kFileSystemObserverQuotaLimitLinuxBucketSize,
-                   &kFileSystemAccessObserverQuotaLimit,
-                   "file_system_observer_quota_limit_linux_bucket_size",
-                   100000);
-BASE_FEATURE_PARAM(size_t,
-                   kFileSystemObserverQuotaLimitLinuxMin,
-                   &kFileSystemAccessObserverQuotaLimit,
-                   "file_system_observer_quota_limit_linux_min",
-                   8192);
-BASE_FEATURE_PARAM(double,
-                   kFileSystemObserverQuotaLimitLinuxPercent,
-                   &kFileSystemAccessObserverQuotaLimit,
-                   "file_system_observer_quota_limit_linux_percent",
-                   0.8);
-
-// On Mac, the quota limit is `kFileSystemObserverQuotaLimitMacPercent`% of the
-// system limit (512) which is constant across all devices.
-BASE_FEATURE_PARAM(double,
-                   kFileSystemObserverQuotaLimitMacPercent,
-                   &kFileSystemAccessObserverQuotaLimit,
-                   "file_system_observer_quota_limit_mac_percent",
-                   0.2  // About 100 FSEventStreamCreate calls.
-);
-
-// On Windows, the quota limit is a constant memory size.
-BASE_FEATURE_PARAM(size_t,
-                   kFileSystemObserverQuotaLimitWindows,
-                   &kFileSystemAccessObserverQuotaLimit,
-                   "file_system_observer_quota_limit_windows",
-                   2 << 28  // 1/2GiB
-);
-
 }  // namespace content::features
diff --git a/content/browser/file_system_access/features.h b/content/browser/file_system_access/features.h
index 1dd96ff..17e560ae 100644
--- a/content/browser/file_system_access/features.h
+++ b/content/browser/file_system_access/features.h
@@ -6,7 +6,6 @@
 #define CONTENT_BROWSER_FILE_SYSTEM_ACCESS_FEATURES_H_
 
 #include "base/feature_list.h"
-#include "base/metrics/field_trial_params.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
 
@@ -19,21 +18,6 @@
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFileSystemAccessDragAndDropCheckBlocklist);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(
     kFileSystemAccessDirectoryIterationBlocklistCheck);
-CONTENT_EXPORT BASE_DECLARE_FEATURE(kFileSystemAccessObserverQuotaLimit);
-CONTENT_EXPORT BASE_DECLARE_FEATURE_PARAM(
-    size_t,
-    kFileSystemObserverQuotaLimitLinuxBucketSize);
-CONTENT_EXPORT BASE_DECLARE_FEATURE_PARAM(
-    size_t,
-    kFileSystemObserverQuotaLimitLinuxMin);
-CONTENT_EXPORT BASE_DECLARE_FEATURE_PARAM(
-    double,
-    kFileSystemObserverQuotaLimitLinuxPercent);
-CONTENT_EXPORT BASE_DECLARE_FEATURE_PARAM(
-    double,
-    kFileSystemObserverQuotaLimitMacPercent);
-CONTENT_EXPORT BASE_DECLARE_FEATURE_PARAM(size_t,
-                                          kFileSystemObserverQuotaLimitWindows);
 
 }  // namespace content::features
 
diff --git a/content/browser/file_system_access/file_path_watcher/file_path_watcher.cc b/content/browser/file_system_access/file_path_watcher/file_path_watcher.cc
index 3013fa8..e8770d6e 100644
--- a/content/browser/file_system_access/file_path_watcher/file_path_watcher.cc
+++ b/content/browser/file_system_access/file_path_watcher/file_path_watcher.cc
@@ -13,7 +13,6 @@
 #include "base/check.h"
 #include "base/files/file_path.h"
 #include "build/build_config.h"
-#include "content/browser/file_system_access/features.h"
 
 namespace content {
 
@@ -135,12 +134,8 @@
 
 // static
 size_t FilePathWatcher::quota_limit() {
-  if (base::FeatureList::IsEnabled(
-          features::kFileSystemAccessObserverQuotaLimit)) {
-    return GetQuotaLimitImpl();
-  }
-
-  return std::numeric_limits<size_t>::max();
+  // TODO(crbug.com/338457523): Decide per platform limits.
+  return SIZE_MAX;
 }
 
 }  // namespace content
diff --git a/content/browser/file_system_access/file_path_watcher/file_path_watcher.h b/content/browser/file_system_access/file_path_watcher/file_path_watcher.h
index d121d05..9ee6886 100644
--- a/content/browser/file_system_access/file_path_watcher/file_path_watcher.h
+++ b/content/browser/file_system_access/file_path_watcher/file_path_watcher.h
@@ -265,8 +265,6 @@
  private:
   explicit FilePathWatcher(std::unique_ptr<PlatformDelegate> delegate);
 
-  static size_t GetQuotaLimitImpl();
-
   std::unique_ptr<PlatformDelegate> impl_;
 
   SEQUENCE_CHECKER(sequence_checker_);
diff --git a/content/browser/file_system_access/file_path_watcher/file_path_watcher_fsevents.cc b/content/browser/file_system_access/file_path_watcher/file_path_watcher_fsevents.cc
index 9b7be93..b7fa0ab0 100644
--- a/content/browser/file_system_access/file_path_watcher/file_path_watcher_fsevents.cc
+++ b/content/browser/file_system_access/file_path_watcher/file_path_watcher_fsevents.cc
@@ -93,7 +93,7 @@
 }
 
 size_t FilePathWatcherFSEvents::current_usage() const {
-  return kNumberOfFSEventStreamCreateCalls;
+  return kNumberOfWatches;
 }
 
 bool FilePathWatcherFSEvents::Watch(const base::FilePath& path,
@@ -248,6 +248,10 @@
       base::apple::FilePathToCFString(resolved_target_);
   CFStringRef paths_array[] = {cf_path.get()};
 
+  static_assert(std::size(paths_array) == kNumberOfWatches,
+                "Update kNumberOfWatches to equal the number of paths we're "
+                "watching so that usage is reported accurately.");
+
   base::apple::ScopedCFTypeRef<CFArrayRef> watched_paths(
       CFArrayCreate(NULL, reinterpret_cast<const void**>(paths_array),
                     std::size(paths_array), &kCFTypeArrayCallBacks));
@@ -259,9 +263,6 @@
   context.release = NULL;
   context.copyDescription = NULL;
 
-  // Ensure that if more `FSEventStreamCreate` calls are added that
-  // `kNumberOfFSEventStreamCreateCalls` is updated to match.
-
   // The parameters of `FSEventStreamCreate` are defined by the FSEvents API:
   // (https://developer.apple.com/documentation/coreservices/1443980-fseventstreamcreate).
   fsevent_stream_ = FSEventStreamCreate(
diff --git a/content/browser/file_system_access/file_path_watcher/file_path_watcher_fsevents.h b/content/browser/file_system_access/file_path_watcher/file_path_watcher_fsevents.h
index dfe4d30f..a8d748b 100644
--- a/content/browser/file_system_access/file_path_watcher/file_path_watcher_fsevents.h
+++ b/content/browser/file_system_access/file_path_watcher/file_path_watcher_fsevents.h
@@ -31,10 +31,7 @@
  public:
   using ChangeEvent = FilePathWatcherFSEventsChangeTracker::ChangeEvent;
 
-  // We only call FSEventStreamCreate once per FilePathWatcher. This number is
-  // used to report usage. If more FSEventStreamCreate calls are added, this
-  // number must be updated.
-  static constexpr size_t kNumberOfFSEventStreamCreateCalls = 1;
+  static constexpr size_t kNumberOfWatches = 1;
 
   FilePathWatcherFSEvents();
   FilePathWatcherFSEvents(const FilePathWatcherFSEvents&) = delete;
diff --git a/content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.cc b/content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.cc
index 0d83433..fa046d1 100644
--- a/content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.cc
+++ b/content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.cc
@@ -45,7 +45,6 @@
 #include "base/trace_event/base_tracing.h"
 #include "base/types/expected.h"
 #include "build/build_config.h"
-#include "content/browser/file_system_access/features.h"
 #include "content/browser/file_system_access/file_path_watcher/file_path_watcher.h"
 #include "content/browser/file_system_access/file_path_watcher/file_path_watcher_histogram.h"
 
@@ -59,6 +58,11 @@
 constexpr char kInotifyMaxUserWatchesPath[] =
     "/proc/sys/fs/inotify/max_user_watches";
 
+// This is a soft limit. If there are more than |kExpectedFilePathWatches|
+// FilePathWatchers for a user, than they might affect each other's inotify
+// watchers limit.
+constexpr size_t kExpectedFilePathWatchers = 16u;
+
 // The default max inotify watchers limit per user, if reading
 // /proc/sys/fs/inotify/max_user_watches fails.
 constexpr size_t kDefaultInotifyMaxUserWatches = 8192u;
@@ -71,23 +75,6 @@
 // Used by test to override inotify watcher limit.
 size_t g_override_max_inotify_watches = 0u;
 
-// Rounds `value` down to nearest multiple of `multiple`.
-size_t RoundDownToNearestMultiple(size_t value, size_t multiple) {
-  return value / multiple * multiple;
-}
-
-size_t GetQuotaLimitFromSystemLimit(size_t system_limit) {
-  size_t nearest_bucket = RoundDownToNearestMultiple(
-      system_limit,
-      features::kFileSystemObserverQuotaLimitLinuxBucketSize.Get());
-
-  size_t effective_system_limit = std::max(
-      nearest_bucket, features::kFileSystemObserverQuotaLimitLinuxMin.Get());
-
-  return features::kFileSystemObserverQuotaLimitLinuxPercent.Get() *
-         effective_system_limit;
-}
-
 class InotifyReaderThreadDelegate final
     : public base::PlatformThread::Delegate {
  public:
@@ -1358,10 +1345,10 @@
     std::ifstream in(kInotifyMaxUserWatchesPath);
     if (!in.is_open() || !(in >> max_number_of_inotify_watches)) {
       LOG(ERROR) << "Failed to read " << kInotifyMaxUserWatchesPath;
-      return kDefaultInotifyMaxUserWatches;
+      return kDefaultInotifyMaxUserWatches / kExpectedFilePathWatchers;
     }
 
-    return max_number_of_inotify_watches;
+    return max_number_of_inotify_watches / kExpectedFilePathWatchers;
   }();
   return g_override_max_inotify_watches ? g_override_max_inotify_watches : max;
 #endif  // if BUILDFLAG(IS_FUCHSIA)
@@ -1378,18 +1365,9 @@
   g_override_max_inotify_watches = 0u;
 }
 
-size_t GetQuotaLimitFromSystemLimitForTesting(size_t system_limit) {
-  return GetQuotaLimitFromSystemLimit(system_limit);
-}
-
 FilePathWatcher::FilePathWatcher()
     : FilePathWatcher(std::make_unique<FilePathWatcherImpl>()) {}
 
-// static
-size_t FilePathWatcher::GetQuotaLimitImpl() {
-  return GetQuotaLimitFromSystemLimit(GetMaxNumberOfInotifyWatches());
-}
-
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 // Put inside "BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)" because Android
 // includes file_path_watcher_linux.cc.
diff --git a/content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.h b/content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.h
index 51182a58..7a8d27d 100644
--- a/content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.h
+++ b/content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.h
@@ -22,9 +22,6 @@
   ~ScopedMaxNumberOfInotifyWatchesOverrideForTest();
 };
 
-CONTENT_EXPORT size_t
-GetQuotaLimitFromSystemLimitForTesting(size_t system_limit);
-
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_FILE_SYSTEM_ACCESS_FILE_PATH_WATCHER_FILE_PATH_WATCHER_INOTIFY_H_
diff --git a/content/browser/file_system_access/file_path_watcher/file_path_watcher_mac.cc b/content/browser/file_system_access/file_path_watcher/file_path_watcher_mac.cc
index a442601..139b4a4 100644
--- a/content/browser/file_system_access/file_path_watcher/file_path_watcher_mac.cc
+++ b/content/browser/file_system_access/file_path_watcher/file_path_watcher_mac.cc
@@ -8,7 +8,6 @@
 
 #include "base/memory/ptr_util.h"
 #include "build/build_config.h"
-#include "content/browser/file_system_access/features.h"
 #include "content/browser/file_system_access/file_path_watcher/file_path_watcher_kqueue.h"
 
 #if !BUILDFLAG(IS_IOS)
@@ -19,11 +18,6 @@
 
 namespace {
 
-// From experiment, we determined that the max calls to FSEventStreamCreate per
-// process is 512. There is a higher system wide limit (at least 970), but we
-// use the process limit since we'll hit it first.
-constexpr size_t kMaxCreateFSEventCalls = 512u;
-
 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
  public:
   FilePathWatcherImpl() = default;
@@ -77,13 +71,4 @@
 FilePathWatcher::FilePathWatcher()
     : FilePathWatcher(std::make_unique<FilePathWatcherImpl>()) {}
 
-// static
-size_t FilePathWatcher::GetQuotaLimitImpl() {
-  // TODO(crbug.com/383148762): This is only applicable to the
-  // `FilePathWatcherFSEvents` implementation. `FilePathWatcherKQueue` is unused
-  // so this shouldn't matter.
-  return kMaxCreateFSEventCalls *
-         features::kFileSystemObserverQuotaLimitMacPercent.Get();
-}
-
 }  // namespace content
diff --git a/content/browser/file_system_access/file_path_watcher/file_path_watcher_stub.cc b/content/browser/file_system_access/file_path_watcher/file_path_watcher_stub.cc
index cc000d0..d41f454 100644
--- a/content/browser/file_system_access/file_path_watcher/file_path_watcher_stub.cc
+++ b/content/browser/file_system_access/file_path_watcher/file_path_watcher_stub.cc
@@ -42,9 +42,4 @@
 FilePathWatcher::FilePathWatcher()
     : FilePathWatcher(std::make_unique<FilePathWatcherImpl>()) {}
 
-// static
-size_t FilePathWatcher::GetQuotaLimitImpl() {
-  return std::numeric_limits<size_t>::max();
-}
-
 }  // namespace content
diff --git a/content/browser/file_system_access/file_path_watcher/file_path_watcher_unittest.cc b/content/browser/file_system_access/file_path_watcher/file_path_watcher_unittest.cc
index 75f2db8..db9f3811 100644
--- a/content/browser/file_system_access/file_path_watcher/file_path_watcher_unittest.cc
+++ b/content/browser/file_system_access/file_path_watcher/file_path_watcher_unittest.cc
@@ -21,13 +21,11 @@
 #include "base/run_loop.h"
 #include "base/sequence_checker.h"
 #include "base/strings/stringprintf.h"
-#include "base/strings/to_string.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/bind.h"
 #include "base/test/run_until.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/test/test_file_util.h"
 #include "base/test/test_future.h"
@@ -35,7 +33,6 @@
 #include "base/thread_annotations.h"
 #include "base/threading/thread.h"
 #include "build/build_config.h"
-#include "content/browser/file_system_access/features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -1874,53 +1871,6 @@
   }
 }
 
-TEST_F(FilePathWatcherTest, InotifyQuotaLimit) {
-  size_t quota_bucket_size = 100000;
-  size_t quota_min = 8192;
-  double quota_percent = 0.8;
-
-  base::FieldTrialParams params;
-  params["file_system_observer_quota_limit_linux_bucket_size"] =
-      base::ToString(quota_bucket_size);
-  params["file_system_observer_quota_limit_linux_min"] =
-      base::ToString(quota_min);
-  params["file_system_observer_quota_limit_linux_percent"] =
-      base::ToString(quota_percent);
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeatureWithParameters(
-      features::kFileSystemAccessObserverQuotaLimit, params);
-
-  // The quota limit is always set to the `quota_percent` of a "effective system
-  // limit" which is the system limit we choose and is less than or equal to the
-  // actual system limit.
-
-  // The first bucket's effective system limit is the `quota_min`.
-  size_t expected_min_quota_limit = quota_min * quota_percent;
-
-  // The first bucket should have a quota limit of `expected_min_quota_limit`.
-  EXPECT_EQ(GetQuotaLimitFromSystemLimitForTesting(0),
-            expected_min_quota_limit);
-  EXPECT_EQ(GetQuotaLimitFromSystemLimitForTesting(quota_bucket_size / 2),
-            expected_min_quota_limit);
-  EXPECT_EQ(GetQuotaLimitFromSystemLimitForTesting(quota_bucket_size - 1),
-            expected_min_quota_limit);
-
-  // Every other bucket should have an effective system limit of the bucket's
-  // minimum value.
-  for (size_t bucket = quota_bucket_size; bucket < 10 * quota_bucket_size;
-       bucket += quota_bucket_size) {
-    size_t expected_quota_limit = bucket * quota_percent;
-    EXPECT_EQ(GetQuotaLimitFromSystemLimitForTesting(bucket),
-              expected_quota_limit);
-    EXPECT_EQ(
-        GetQuotaLimitFromSystemLimitForTesting(bucket + quota_bucket_size / 2),
-        expected_quota_limit);
-    EXPECT_EQ(
-        GetQuotaLimitFromSystemLimitForTesting(bucket + quota_bucket_size - 1),
-        expected_quota_limit);
-  }
-}
-
 // Verify that "Watch()" returns false and callback is not invoked when limit is
 // hit during setup.
 TEST_F(FilePathWatcherTest, InotifyLimitInWatch) {
diff --git a/content/browser/file_system_access/file_path_watcher/file_path_watcher_win.cc b/content/browser/file_system_access/file_path_watcher/file_path_watcher_win.cc
index a9c672a..14e58c59 100644
--- a/content/browser/file_system_access/file_path_watcher/file_path_watcher_win.cc
+++ b/content/browser/file_system_access/file_path_watcher/file_path_watcher_win.cc
@@ -39,7 +39,6 @@
 #include "base/win/object_watcher.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/windows_types.h"
-#include "content/browser/file_system_access/features.h"
 #include "content/browser/file_system_access/file_path_watcher/file_path_watcher_change_tracker.h"
 #include "content/browser/file_system_access/file_path_watcher/file_path_watcher_histogram.h"
 
@@ -794,9 +793,4 @@
 FilePathWatcher::FilePathWatcher()
     : FilePathWatcher(std::make_unique<FilePathWatcherImpl>()) {}
 
-// static
-size_t FilePathWatcher::GetQuotaLimitImpl() {
-  return features::kFileSystemObserverQuotaLimitWindows.Get();
-}
-
 }  // namespace content
diff --git a/content/browser/file_system_access/file_system_access_clipboard_browsertest.cc b/content/browser/file_system_access/file_system_access_clipboard_browsertest.cc
index c03acb11..34633551 100644
--- a/content/browser/file_system_access/file_system_access_clipboard_browsertest.cc
+++ b/content/browser/file_system_access/file_system_access_clipboard_browsertest.cc
@@ -8,7 +8,6 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
diff --git a/content/browser/file_system_access/file_system_access_file_modification_host_impl_browsertest.cc b/content/browser/file_system_access/file_system_access_file_modification_host_impl_browsertest.cc
index a63ab87e..e8c8581 100644
--- a/content/browser/file_system_access/file_system_access_file_modification_host_impl_browsertest.cc
+++ b/content/browser/file_system_access/file_system_access_file_modification_host_impl_browsertest.cc
@@ -6,7 +6,6 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/test/bind.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/content/browser/file_system_access/file_system_access_safe_move_helper.cc b/content/browser/file_system_access/file_system_access_safe_move_helper.cc
index 4fe08e48..1925a6c 100644
--- a/content/browser/file_system_access/file_system_access_safe_move_helper.cc
+++ b/content/browser/file_system_access/file_system_access_safe_move_helper.cc
@@ -13,7 +13,6 @@
 #include "base/task/thread_pool.h"
 #include "base/thread_annotations.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/services/quarantine/quarantine.h"
 #include "content/browser/file_system_access/features.h"
 #include "content/browser/file_system_access/file_system_access_error.h"
@@ -325,7 +324,7 @@
   // On ChromeOS on the other hand anything that isn't in the sandboxed file
   // system is also uniquely identifiable by its FileSystemURL::path(), and
   // thus we accept all other FileSystemURL types.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   DCHECK(target_url.type() != storage::kFileSystemTypeTemporary &&
          target_url.type() != storage::kFileSystemTypePersistent)
       << target_url.type();
diff --git a/content/browser/form_controls_browsertest.cc b/content/browser/form_controls_browsertest.cc
index 689e48a..71825876 100644
--- a/content/browser/form_controls_browsertest.cc
+++ b/content/browser/form_controls_browsertest.cc
@@ -5,7 +5,6 @@
 #include "base/files/file_util.h"
 #include "base/path_service.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/test/pixel_comparator.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/common/content_paths.h"
diff --git a/content/browser/gpu/browser_gpu_channel_host_factory.cc b/content/browser/gpu/browser_gpu_channel_host_factory.cc
index 672cfb0d..761672c0 100644
--- a/content/browser/gpu/browser_gpu_channel_host_factory.cc
+++ b/content/browser/gpu/browser_gpu_channel_host_factory.cc
@@ -18,7 +18,6 @@
 #include "base/timer/timer.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/viz/host/gpu_host_impl.h"
 #include "content/browser/child_process_host_impl.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
@@ -341,7 +340,7 @@
 // CrOS and this check failed when tested on an experimental builder. Revert
 // https://crrev.com/c/3174621 to enable it. See go/chrome-dcheck-on-cros
 // or http://crbug.com/1113456 for more details.
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
+#if !BUILDFLAG(IS_CHROMEOS)
     DCHECK(!pending_request_.get());
 #endif
     // Recreate the channel if it has been lost.
diff --git a/content/browser/gpu/chromeos/video_capture_dependencies.cc b/content/browser/gpu/chromeos/video_capture_dependencies.cc
index a29543bb..6deb825 100644
--- a/content/browser/gpu/chromeos/video_capture_dependencies.cc
+++ b/content/browser/gpu/chromeos/video_capture_dependencies.cc
@@ -5,7 +5,6 @@
 #include "content/browser/gpu/chromeos/video_capture_dependencies.h"
 
 #include "base/functional/bind.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/gpu/gpu_process_host.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -33,7 +32,7 @@
   }
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 // static
 void VideoCaptureDependencies::CreateJpegEncodeAccelerator(
     mojo::PendingReceiver<chromeos_camera::mojom::JpegEncodeAccelerator>
@@ -54,6 +53,6 @@
     LOG(ERROR) << "No GpuProcessHost";
   }
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 }  // namespace content
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index 486d4fc..815d9cb 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -24,7 +24,6 @@
 #include "base/system/sys_info.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/base/switches.h"
 #include "components/viz/common/features.h"
 #include "content/browser/compositor/image_transport_factory.h"
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index 8e2f989a..c845384 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -42,7 +42,6 @@
 #include "base/trace_event/trace_event.h"
 #include "base/version.h"
 #include "build/chromecast_buildflags.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/base/switches.h"
 #include "components/viz/common/features.h"
 #include "content/browser/gpu/gpu_memory_buffer_manager_singleton.h"
@@ -513,7 +512,7 @@
   // Android and Chrome OS can't switch to software compositing. If the GPU
   // process initialization fails or GPU process is too unstable then crash the
   // browser process to reset everything.
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
   fallback_modes_.push_back(gpu::GpuMode::DISPLAY_COMPOSITOR);
   if (SwiftShaderAllowed())
     fallback_modes_.push_back(gpu::GpuMode::SWIFTSHADER);
@@ -531,7 +530,7 @@
 #endif  // BUILDFLAG(IS_CASTOS)
 
 #if (BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CAST_ANDROID)) || \
-    BUILDFLAG(IS_CHROMEOS_ASH)
+    BUILDFLAG(IS_CHROMEOS)
     NOTREACHED() << "GPU acceleration is required on certain platforms!";
 #endif
   } else if (features::IsSkiaGraphiteEnabled(command_line)) {
diff --git a/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc b/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
index 3cec508..d3dcebb 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
@@ -18,7 +18,6 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "build/chromecast_buildflags.h"
-#include "build/chromeos_buildflags.h"
 #include "content/public/browser/gpu_data_manager_observer.h"
 #include "content/public/common/content_switches.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
@@ -487,7 +486,7 @@
 
 // Android and Chrome OS do not support software compositing, while Fuchsia does
 // not support falling back to software from Vulkan.
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_IOS)
 #if !BUILDFLAG(IS_FUCHSIA)
 TEST_F(GpuDataManagerImplPrivateTest, NoDefaultFallbackToSwiftShader) {
   base::test::ScopedFeatureList feature_list;
@@ -573,7 +572,7 @@
   EXPECT_EQ(gpu::GpuMode::DISPLAY_COMPOSITOR, manager->GetGpuMode());
 }
 #endif  // !defined(CAST_AUDIO_ONLY)
-#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) &&
+#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS) &&
         // !BUILDFLAG(IS_IOS)
 
 // Chromecast audio-only builds should not launch the GPU process.
@@ -628,14 +627,14 @@
 
   // The first fallback should go to the display compositor on platforms where
   // fallback to software is allowed.
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_IOS)
   manager->FallBackToNextGpuMode();
   EXPECT_EQ(gpu::GpuMode::DISPLAY_COMPOSITOR, manager->GetGpuMode());
-#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) &&
+#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS) &&
         // !BUILDFLAG(IS_IOS)
 }
 
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_IOS)
 TEST_F(GpuDataManagerImplPrivateTest, FallbackFromVulkanWithGLDisabled) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures({features::kVulkan},
@@ -651,7 +650,7 @@
   manager->FallBackToNextGpuMode();
   EXPECT_EQ(gpu::GpuMode::DISPLAY_COMPOSITOR, manager->GetGpuMode());
 }
-#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) &&
+#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS) &&
         // !BUILDFLAG(IS_IOS)
 #endif  // !BUILDFLAG(IS_FUCHSIA)
 #endif  // BUILDFLAG(ENABLE_VULKAN)
diff --git a/content/browser/gpu/gpu_ipc_browsertests.cc b/content/browser/gpu/gpu_ipc_browsertests.cc
index 2681a46..cc7ce54 100644
--- a/content/browser/gpu/gpu_ipc_browsertests.cc
+++ b/content/browser/gpu/gpu_ipc_browsertests.cc
@@ -105,7 +105,6 @@
 #define CONTEXT_TEST_F IN_PROC_BROWSER_TEST_F
 #include "base/functional/bind.h"
 #include "base/task/single_thread_task_runner.h"
-#include "build/chromeos_buildflags.h"
 #include "content/public/browser/browser_thread.h"
 #include "gpu/ipc/client/gpu_context_tests.h"
 
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 9112c7c4..4bdf399 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -34,7 +34,6 @@
 #include "base/threading/thread.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/discardable_memory/service/discardable_shared_memory_manager.h"
 #include "components/tracing/common/tracing_switches.h"
 #include "components/viz/common/features.h"
@@ -1156,7 +1155,7 @@
 }
 
 void GpuProcessHost::DisableGpuCompositing() {
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
   DLOG(ERROR) << "Can't disable GPU compositing";
 #else
   // TODO(crbug.com/40565996): The switch from GPU to software compositing
diff --git a/content/browser/gpu/gpu_process_host_receiver_bindings.cc b/content/browser/gpu/gpu_process_host_receiver_bindings.cc
index bbf984c..004b4e1 100644
--- a/content/browser/gpu/gpu_process_host_receiver_bindings.cc
+++ b/content/browser/gpu/gpu_process_host_receiver_bindings.cc
@@ -7,7 +7,6 @@
 #include "content/browser/gpu/gpu_process_host.h"
 
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
@@ -20,7 +19,7 @@
 #include "media/mojo/mojom/android_overlay.mojom.h"
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "components/services/font/public/mojom/font_service.mojom.h"  // nogncheck
 #include "content/browser/font_service.h"  // nogncheck
 #endif
@@ -49,7 +48,7 @@
   }
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   if (auto font_receiver =
           generic_receiver.As<font_service::mojom::FontService>()) {
     ConnectToFontService(std::move(font_receiver));
diff --git a/content/browser/gpu/peak_gpu_memory_tracker_impl_browsertest.cc b/content/browser/gpu/peak_gpu_memory_tracker_impl_browsertest.cc
index affbe73..27d54f5 100644
--- a/content/browser/gpu/peak_gpu_memory_tracker_impl_browsertest.cc
+++ b/content/browser/gpu/peak_gpu_memory_tracker_impl_browsertest.cc
@@ -12,7 +12,6 @@
 #include "base/task/thread_pool.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/viz/test/gpu_host_impl_test_api.h"
 #include "content/browser/gpu/gpu_process_host.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -72,7 +71,7 @@
   void OnDiskCacheHandleDestoyed(
       const gpu::GpuDiskCacheHandle& handle) override {}
   void CloseChannel(int32_t client_id) override {}
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
   void CreateArcVideoDecodeAccelerator(
       mojo::PendingReceiver<arc::mojom::VideoDecodeAccelerator> vda_receiver)
@@ -95,7 +94,7 @@
   void CreateJpegEncodeAccelerator(
       mojo::PendingReceiver<chromeos_camera::mojom::JpegEncodeAccelerator>
           jea_receiver) override {}
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 #if BUILDFLAG(IS_WIN)
   void RegisterDCOMPSurfaceHandle(
       mojo::PlatformHandle surface_handle,
diff --git a/content/browser/handwriting/handwriting_recognition_service_impl_cros.cc b/content/browser/handwriting/handwriting_recognition_service_impl_cros.cc
index aa1af7b..fed945c 100644
--- a/content/browser/handwriting/handwriting_recognition_service_impl_cros.cc
+++ b/content/browser/handwriting/handwriting_recognition_service_impl_cros.cc
@@ -9,13 +9,12 @@
 
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/handwriting/handwriting_recognizer_impl_cros.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "third_party/blink/public/mojom/handwriting/handwriting.mojom.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "chromeos/services/machine_learning/public/cpp/ml_switches.h"
 #endif
 
@@ -27,7 +26,7 @@
 // supported by the CrOS Downloadable Content (DLC) service other than on
 // rootfs.
 bool IsCrOSLibHandwritingRootfsEnabled() {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   // TODO(https://crbug.com/1168978): mlservice should provide an interface to
   // query this.
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
diff --git a/content/browser/indexed_db/indexed_db_browsertest.cc b/content/browser/indexed_db/indexed_db_browsertest.cc
index 413084d..9e82343 100644
--- a/content/browser/indexed_db/indexed_db_browsertest.cc
+++ b/content/browser/indexed_db/indexed_db_browsertest.cc
@@ -33,7 +33,6 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_database.h"
 #include "components/services/storage/privileged/mojom/indexed_db_control.mojom-test-utils.h"
 #include "components/services/storage/privileged/mojom/indexed_db_control_test.mojom.h"
diff --git a/content/browser/indexed_db/indexed_db_feature_observer_browsertest.cc b/content/browser/indexed_db/indexed_db_feature_observer_browsertest.cc
index 337bb89f..477d188 100644
--- a/content/browser/indexed_db/indexed_db_feature_observer_browsertest.cc
+++ b/content/browser/indexed_db/indexed_db_feature_observer_browsertest.cc
@@ -6,7 +6,6 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/test_timeouts.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/feature_observer.h"
 #include "content/public/browser/back_forward_cache.h"
 #include "content/public/browser/content_browser_client.h"
@@ -193,7 +192,7 @@
 // IndexedDB connections (notifications only when the number of held connections
 // switches between zero and non-zero).
 // Disabled on ChromeOS release build for flakiness. See crbug.com/1030733.
-#if BUILDFLAG(IS_CHROMEOS_ASH) && defined(NDEBUG)
+#if BUILDFLAG(IS_CHROMEOS) && defined(NDEBUG)
 #define MAYBE_ObserverTwoLocks DISABLED_ObserverTwoLocks
 #else
 #define MAYBE_ObserverTwoLocks ObserverTwoLocks
diff --git a/content/browser/interest_group/interest_group_auction.cc b/content/browser/interest_group/interest_group_auction.cc
index 54c63d0..ab8d5a8 100644
--- a/content/browser/interest_group/interest_group_auction.cc
+++ b/content/browser/interest_group/interest_group_auction.cc
@@ -4834,6 +4834,8 @@
   // BuyerHelper may filter out additional interest groups on construction.
   if (buyer_helper->has_potential_bidder()) {
     buyer_helpers_.emplace_back(std::move(buyer_helper));
+    interest_group_manager_->UpdateCachedOriginsIfEnabled(
+        interest_groups[0]->interest_group.owner);
   } else {
     // `buyer_helper` has a raw pointer to `this`, so if it's not added to
     // buyer_helpers_, delete it now to avoid a dangling pointer, since
diff --git a/content/browser/interest_group/interest_group_browsertest.cc b/content/browser/interest_group/interest_group_browsertest.cc
index a119e8fa..7be3abda 100644
--- a/content/browser/interest_group/interest_group_browsertest.cc
+++ b/content/browser/interest_group/interest_group_browsertest.cc
@@ -23913,8 +23913,6 @@
   url::Origin joining_origin = url::Origin::Create(joining_url);
   ASSERT_TRUE(NavigateToURL(shell(), joining_url));
 
-  // Join an interest group. The owner, a.test, will be in the in-memory
-  // cache.
   GURL ad_url =
       embedded_https_test_server().GetURL("a.test", "/echo?render_winner");
   // Use a bidding script that does not bid to prevent the auction from having a
@@ -23934,8 +23932,6 @@
   WaitForAccessObserved({{"global", TestInterestGroupObserver::kJoin,
                           interest_group.owner, "interest_group"}});
   std::optional<url::Origin> cached_signals_origin;
-  EXPECT_TRUE(manager_->GetCachedOwnerAndSignalsOrigins(interest_group.owner,
-                                                        cached_signals_origin));
 
   const char kConfigTemplate[] = R"({
         seller: $1,
@@ -23965,6 +23961,26 @@
       component_seller_script, interest_group.owner,
       url::Origin::Create(embedded_https_test_server().GetURL("b.test", "/")));
 
+  // Run an auction so that a.test will be cached.
+  {
+    base::HistogramTester histogram_tester;
+    auto result = RunAuctionAndWait(auction_config);
+    histogram_tester.ExpectUniqueSample("Ads.InterestGroup.Auction.Result",
+                                        AuctionResult::kNoBids, 1);
+    histogram_tester.ExpectUniqueSample(
+        "Ads.InterestGroup.Auction.Seller.RequestWorkletServiceOutcome",
+        AuctionProcessManager::RequestWorkletServiceOutcome::
+            kCreatedNewDedicatedProcess,
+        2);
+    histogram_tester.ExpectUniqueSample(
+        "Ads.InterestGroup.Auction.Buyer.RequestWorkletServiceOutcome",
+        AuctionProcessManager::RequestWorkletServiceOutcome::
+            kCreatedNewDedicatedProcess,
+        1);
+    EXPECT_TRUE(manager_->GetCachedOwnerAndSignalsOrigins(
+        interest_group.owner, cached_signals_origin));
+  }
+
   // Run the auction.
   //
   // 1. a.test, the first buyer, is cached. That means we should start an
@@ -23977,18 +23993,21 @@
   //
   // Overall there will be 1 anticipatory process started and 3 worklets
   // requested.
-  base::HistogramTester histogram_tester;
-  auto result = RunAuctionAndWait(auction_config);
-  histogram_tester.ExpectUniqueSample("Ads.InterestGroup.Auction.Result",
-                                      AuctionResult::kNoBids, 1);
-  histogram_tester.ExpectUniqueSample(
-      "Ads.InterestGroup.Auction.Seller.RequestWorkletServiceOutcome",
-      AuctionProcessManager::RequestWorkletServiceOutcome::
-          kCreatedNewDedicatedProcess,
-      2);
-  histogram_tester.ExpectUniqueSample(
-      "Ads.InterestGroup.Auction.Buyer.RequestWorkletServiceOutcome",
-      AuctionProcessManager::RequestWorkletServiceOutcome::kUsedIdleProcess, 1);
+  {
+    base::HistogramTester histogram_tester;
+    auto result = RunAuctionAndWait(auction_config);
+    histogram_tester.ExpectUniqueSample("Ads.InterestGroup.Auction.Result",
+                                        AuctionResult::kNoBids, 1);
+    histogram_tester.ExpectUniqueSample(
+        "Ads.InterestGroup.Auction.Seller.RequestWorkletServiceOutcome",
+        AuctionProcessManager::RequestWorkletServiceOutcome::
+            kCreatedNewDedicatedProcess,
+        2);
+    histogram_tester.ExpectUniqueSample(
+        "Ads.InterestGroup.Auction.Buyer.RequestWorkletServiceOutcome",
+        AuctionProcessManager::RequestWorkletServiceOutcome::kUsedIdleProcess,
+        1);
+  }
 }
 
 class AuctionConfigReportingTimeoutEnabledTest
@@ -26603,13 +26622,16 @@
 
   // Join the interest group with no ads so that when we run an auction, it will
   // get filtered after it's loaded -- but we'll still preconnect to the server.
-  // This join will cache the bidding signals and owner origins.
+  // Loading the interest group and running UpdateCachedOriginsIfEnabled will
+  // cache the bidding signals and owner origins.
   blink::InterestGroup interest_group_without_ads = interest_group;
   interest_group_without_ads.ads = std::nullopt;
   AttachInterestGroupObserver();
   manager_->JoinInterestGroup(interest_group_without_ads, joining_url);
   WaitForAccessObserved({{"global", TestInterestGroupObserver::kJoin,
                           interest_group_without_ads.owner, "interest_group"}});
+  GetInterestGroupsForOwner(interest_group.owner);
+  manager_->UpdateCachedOriginsIfEnabled(interest_group.owner);
   std::optional<url::Origin> cached_signals_origin;
   EXPECT_TRUE(manager_->GetCachedOwnerAndSignalsOrigins(
       interest_group_without_ads.owner, cached_signals_origin));
diff --git a/content/browser/interest_group/interest_group_caching_storage.cc b/content/browser/interest_group/interest_group_caching_storage.cc
index 1641a84a..20b12fac 100644
--- a/content/browser/interest_group/interest_group_caching_storage.cc
+++ b/content/browser/interest_group/interest_group_caching_storage.cc
@@ -195,6 +195,32 @@
   return true;
 }
 
+void InterestGroupCachingStorage::UpdateCachedOriginsIfEnabled(
+    const url::Origin& owner) {
+  if (!base::FeatureList::IsEnabled(features::kFledgeUsePreconnectCache) &&
+      !base::FeatureList::IsEnabled(
+          features::kFledgeStartAnticipatoryProcesses)) {
+    return;
+  }
+
+  auto cached_groups_it = cached_interest_groups_.find(owner);
+  if (cached_groups_it == cached_interest_groups_.end()) {
+    return;
+  }
+  scoped_refptr<StorageInterestGroups> groups = cached_groups_it->second.get();
+  if (groups->IsExpired() || groups->size() == 0) {
+    return;
+  }
+
+  CachedOriginsInfo cached_origins_info;
+  for (const StorageInterestGroup& group : groups->storage_interest_groups_) {
+    if (group.interest_group.expiry > cached_origins_info.expiry) {
+      cached_origins_info = CachedOriginsInfo(group.interest_group);
+    }
+  }
+  cached_owners_and_signals_origins_[owner] = std::move(cached_origins_info);
+}
+
 void InterestGroupCachingStorage::JoinInterestGroup(
     const blink::InterestGroup& group,
     const GURL& main_frame_joining_url,
@@ -535,13 +561,9 @@
     auto it = cached_owners_and_signals_origins_.find(owner);
     if (it != cached_owners_and_signals_origins_.end()) {
       if (it->second.interest_group_name ==
-              cached_origins_info.interest_group_name ||
-          it->second.expiry < cached_origins_info.expiry) {
+          cached_origins_info.interest_group_name) {
         it->second = std::move(cached_origins_info);
       }
-    } else {
-      cached_owners_and_signals_origins_[owner] =
-          std::move(cached_origins_info);
     }
   }
   std::move(callback).Run(std::move(update));
@@ -557,8 +579,6 @@
     return;
   }
 
-  UpdateCachedOriginsIfEnabled(owner, interest_groups);
-
   scoped_refptr<StorageInterestGroups> interest_groups_ptr =
       base::MakeRefCounted<StorageInterestGroups>(std::move(interest_groups));
 
@@ -621,25 +641,4 @@
           weak_factory_.GetWeakPtr(), owner, groups));
 }
 
-void InterestGroupCachingStorage::UpdateCachedOriginsIfEnabled(
-    const url::Origin& owner,
-    const std::vector<StorageInterestGroup>& interest_groups) {
-  if (!base::FeatureList::IsEnabled(features::kFledgeUsePreconnectCache) &&
-      !base::FeatureList::IsEnabled(
-          features::kFledgeStartAnticipatoryProcesses)) {
-    return;
-  }
-  if (interest_groups.empty()) {
-    cached_owners_and_signals_origins_.erase(owner);
-    return;
-  }
-  CachedOriginsInfo cached_origins_info;
-  for (const StorageInterestGroup& group : interest_groups) {
-    if (group.interest_group.expiry > cached_origins_info.expiry) {
-      cached_origins_info = CachedOriginsInfo(group.interest_group);
-    }
-  }
-  cached_owners_and_signals_origins_[owner] = std::move(cached_origins_info);
-}
-
 }  // namespace content
diff --git a/content/browser/interest_group/interest_group_caching_storage.h b/content/browser/interest_group/interest_group_caching_storage.h
index d7d363bb..35add7dc 100644
--- a/content/browser/interest_group/interest_group_caching_storage.h
+++ b/content/browser/interest_group/interest_group_caching_storage.h
@@ -141,23 +141,27 @@
       base::OnceCallback<void(scoped_refptr<StorageInterestGroups>)> callback);
 
   // For a given `owner`, return whether the owner origin and bidding signal
-  // origin were cached in-memory in previous calls to
-  // GetInterestGroupsForOwner and JoinInterestGroup. If the `owner` origin was
-  // cached, update `signals_origin` to the one that was cached -- or set to
-  // nullopt if no bidding signals origin was cached or if it would be the same
-  // as the owner origin. The cache includes at most one entry per origin, and
-  // may not reflect the results of interest group updates. It's intended to be
-  // used for best-effort preconnecting, and should not be considered
-  // authoritative. It is guaranteed not to contain interest groups that have
-  // are beyond the max expiration time limit, so preconnecting should not leak
-  // data the bidder would otherwise have access to, if it so desired. That is,
-  // manual voluntarily removing or expiring of an interest group may not be
-  // reflected in the result, but hitting the the global interest group lifetime
-  // cap will be respected.
+  // origin were cached in-memory via UpdateCachedOriginsIfEnabled.
+  // If the `owner` origin was cached, update `signals_origin` to the one that
+  // was cached -- or set to nullopt if no bidding signals origin was cached or
+  // if it would be the same as the owner origin. The cache includes at most one
+  // entry per origin, and may not reflect the results of interest group
+  // updates. It's intended to be used for best-effort preconnecting, and should
+  // not be considered authoritative. It is guaranteed not to contain interest
+  // groups that have are beyond the max expiration time limit, so preconnecting
+  // should not leak data the bidder would otherwise have access to, if it so
+  // desired. That is, manual voluntarily removing or expiring of an interest
+  // group may not be reflected in the result, but hitting the the global
+  // interest group lifetime cap will be respected.
   bool GetCachedOwnerAndSignalsOrigins(
       const url::Origin& owner,
       std::optional<url::Origin>& signals_origin);
 
+  // Update the cached owner and signal origins for an owner's interest groups
+  // if kFledgeUsePreconnectCache or kFledgeStartAnticipatoryProcesses are
+  // enabled and the owner's IGs are still in memory.
+  void UpdateCachedOriginsIfEnabled(const url::Origin& owner);
+
   // Joins an interest group. If the interest group does not exist, a new one
   // is created based on the provided group information. If the interest group
   // exists, the existing interest group is overwritten. In either case a join
@@ -320,8 +324,8 @@
       base::RepeatingCallback<void(base::Time)> callback) const;
 
  private:
-  // Once JoinInterestGroup completes successfully, maybe cache the associated
-  // CachedOriginsInfo and run the callback.
+  // Once JoinInterestGroup completes successfully, maybe update the cached
+  // origins and run the callback.
   void OnJoinInterestGroup(
       const url::Origin& owner,
       CachedOriginsInfo cached_origins_info,
@@ -361,12 +365,6 @@
     timed_holds_of_interest_groups_.erase(owner);
   }
 
-  // Update `cached_owners_and_signals_origins_` for an owner's interest groups
-  // if kFledgeUsePreconnectCache is enabled.
-  void UpdateCachedOriginsIfEnabled(
-      const url::Origin& owner,
-      const std::vector<StorageInterestGroup>& interest_groups);
-
   base::SequenceBound<InterestGroupStorage> interest_group_storage_;
 
   // Used to retrieve interest groups that are still in memory (e.g. because
@@ -396,14 +394,14 @@
   // interest_groups_sequenced_callbacks_ becomes empty.
   std::map<url::Origin, uint32_t> valid_interest_group_versions_;
 
-  // For each owner for which we've loaded or joined interest groups,
-  // hold onto the owner origin and origin of the bidding signals url for the
-  // purpose of preconnecting to them in later auctions. CachedOriginsInfo
-  // tracks the latest expiring interest group that we know about to prevent
-  // preconnecting to origins no longer in the database. Owners may be cleared
-  // from the map if the corresponding interest group is left or expired.
-  // A flat map is used because the number of interest group owners is expected
-  // to be relatively small.
+  // For each owner for which we've run UpdateCachedOriginsIfEnabled,
+  // hold onto the owner origin and the origin of the bidding signals url for
+  // the purpose of preconnecting to them or starting worklets for them in later
+  // auctions. CachedOriginsInfo tracks the latest expiring interest group that
+  // we know about to prevent preconnecting to origins no longer in the
+  // database. Owners may be cleared from the map if the corresponding interest
+  // group is left or expired. A flat map is used because the number of interest
+  // group owners is expected to be relatively small.
   base::flat_map<url::Origin, CachedOriginsInfo>
       cached_owners_and_signals_origins_;
 
diff --git a/content/browser/interest_group/interest_group_caching_storage_unittest.cc b/content/browser/interest_group/interest_group_caching_storage_unittest.cc
index 59ad059..e9ec1a2d 100644
--- a/content/browser/interest_group/interest_group_caching_storage_unittest.cc
+++ b/content/browser/interest_group/interest_group_caching_storage_unittest.cc
@@ -63,6 +63,12 @@
     return result;
   }
 
+  void UpdateCachedOrigins(InterestGroupCachingStorage* caching_storage,
+                           const url::Origin& owner) {
+    GetInterestGroupsForOwner(caching_storage, owner);
+    caching_storage->UpdateCachedOriginsIfEnabled(owner);
+  }
+
   std::optional<SingleStorageInterestGroup> GetInterestGroup(
       InterestGroupCachingStorage* caching_storage,
       const blink::InterestGroupKey& group_key) {
@@ -858,27 +864,40 @@
 
   GURL test_url("https://www.test.test");
 
-  // Join an interest group without a bidding signals url.
+  // We shouldn't be able to cache owners which aren't in the
+  // database.
+  UpdateCachedOrigins(caching_storage.get(), owner1);
+  ASSERT_FALSE(caching_storage->GetCachedOwnerAndSignalsOrigins(
+      owner1, loaded_signals_origin));
+  ASSERT_FALSE(loaded_signals_origin);
+
+  // Join an interest group without a bidding signals url. We should be able to
+  // cache the owner.
   JoinInterestGroup(caching_storage.get(), ig1, test_url);
+  UpdateCachedOrigins(caching_storage.get(), owner1);
   ASSERT_TRUE(caching_storage->GetCachedOwnerAndSignalsOrigins(
       owner1, loaded_signals_origin));
   ASSERT_FALSE(loaded_signals_origin);
 
-  // Join an interest group with a bidding signals url (different origin).
+  // Join an interest group with a bidding signals url (different origin as the
+  // owner).
   task_environment_.FastForwardBy(base::Minutes(1));
   blink::InterestGroup ig2 = MakeInterestGroup(owner1, "2");
   ig2.trusted_bidding_signals_url = GURL("https://www.other.test");
   JoinInterestGroup(caching_storage.get(), ig2, test_url);
+  UpdateCachedOrigins(caching_storage.get(), owner1);
   ASSERT_TRUE(caching_storage->GetCachedOwnerAndSignalsOrigins(
       owner1, loaded_signals_origin));
   ASSERT_EQ(loaded_signals_origin,
             url::Origin::Create(*ig2.trusted_bidding_signals_url));
 
-  // Join an interest group with a bidding signals url (same origin).
+  // Join an interest group with a bidding signals url (same origin as the
+  // owner).
   task_environment_.FastForwardBy(base::Minutes(1));
   blink::InterestGroup ig3 = MakeInterestGroup(owner1, "3");
   ig3.trusted_bidding_signals_url = owner1.GetURL();
   JoinInterestGroup(caching_storage.get(), ig3, test_url);
+  UpdateCachedOrigins(caching_storage.get(), owner1);
   ASSERT_TRUE(caching_storage->GetCachedOwnerAndSignalsOrigins(
       owner1, loaded_signals_origin));
   ASSERT_FALSE(loaded_signals_origin);
@@ -893,6 +912,7 @@
   ig4.expiry = ig3.expiry + base::Minutes(3);
   ig4.trusted_bidding_signals_url = GURL("https://www.other.test");
   JoinInterestGroup(caching_storage.get(), ig4, test_url);
+  UpdateCachedOrigins(caching_storage.get(), owner2);
 
   InterestGroupCachingStorage::CachedOriginsInfo expected_owner2_cached_info(
       ig4);
@@ -912,6 +932,7 @@
   ig5.name = "5";
   ig5.expiry = ig3.expiry;
   JoinInterestGroup(caching_storage.get(), ig5, test_url);
+  UpdateCachedOrigins(caching_storage.get(), owner2);
   ASSERT_TRUE(caching_storage->GetCachedOwnerAndSignalsOrigins(
       owner1, loaded_signals_origin));
   ASSERT_FALSE(loaded_signals_origin);
@@ -975,6 +996,7 @@
   task_environment_.FastForwardBy(base::Seconds(1));
   blink::InterestGroup ig8 = MakeInterestGroup(owner1, "8");
   JoinInterestGroup(caching_storage.get(), ig8, test_url);
+  UpdateCachedOrigins(caching_storage.get(), owner1);
   ASSERT_TRUE(caching_storage->GetCachedOwnerAndSignalsOrigins(
       owner1, loaded_signals_origin));
   ASSERT_FALSE(loaded_signals_origin);
@@ -1010,6 +1032,7 @@
   // We can get this cache again from an IG load. The signals URL reflects
   // the update to ig8.
   groups = GetInterestGroupsForOwner(caching_storage.get(), owner1);
+  UpdateCachedOrigins(caching_storage.get(), owner1);
   ASSERT_TRUE(caching_storage->GetCachedOwnerAndSignalsOrigins(
       owner1, loaded_signals_origin));
   ASSERT_EQ(loaded_signals_origin,
@@ -1032,9 +1055,11 @@
   ASSERT_FALSE(caching_storage->GetCachedOwnerAndSignalsOrigins(
       owner1, loaded_signals_origin));
 
-  // We can get the cache again by loading IGs because there were other interest
-  // groups with the same owner. Now the latest expiring IG will be ig7.
+  // We can get the cache again by loading IGs + running
+  // UpdateCachedOriginsIfEnabled because there were other interest groups with
+  // the same owner. Now the latest expiring IG will be ig7.
   groups = GetInterestGroupsForOwner(caching_storage.get(), owner1);
+  UpdateCachedOrigins(caching_storage.get(), owner1);
   ASSERT_TRUE(groups.has_value());
   ASSERT_GT(groups.value()->size(), 0u);
   ASSERT_TRUE(caching_storage->GetCachedOwnerAndSignalsOrigins(
@@ -1063,11 +1088,26 @@
   // When the latest expiring interest group expires, the cache does too.
   blink::InterestGroup ig9 = MakeInterestGroup(owner1, "9");
   JoinInterestGroup(caching_storage.get(), ig9, test_url);
+  UpdateCachedOrigins(caching_storage.get(), owner1);
   ASSERT_TRUE(caching_storage->GetCachedOwnerAndSignalsOrigins(
       owner1, loaded_signals_origin));
   task_environment_.FastForwardBy(base::Days(1) + base::Minutes(2));
   ASSERT_FALSE(caching_storage->GetCachedOwnerAndSignalsOrigins(
       owner1, loaded_signals_origin));
+
+  // When we join the same interest group twice, the earlier expiry is
+  // respected.
+  blink::InterestGroup ig10 = MakeInterestGroup(owner1, "10");
+  JoinInterestGroup(caching_storage.get(), ig10, test_url);
+  UpdateCachedOrigins(caching_storage.get(), owner1);
+  ig10.expiry = ig10.expiry - base::Minutes(1);
+  ASSERT_TRUE(caching_storage->GetCachedOwnerAndSignalsOrigins(
+      owner1, loaded_signals_origin));
+  JoinInterestGroup(caching_storage.get(), ig10, test_url);
+  task_environment_.FastForwardBy(base::Days(1) - base::Minutes(1) +
+                                  base::Milliseconds(1));
+  ASSERT_FALSE(caching_storage->GetCachedOwnerAndSignalsOrigins(
+      owner1, loaded_signals_origin));
 }
 
 }  // namespace content
diff --git a/content/browser/interest_group/interest_group_manager_impl.cc b/content/browser/interest_group/interest_group_manager_impl.cc
index 87bb423..02e30f8 100644
--- a/content/browser/interest_group/interest_group_manager_impl.cc
+++ b/content/browser/interest_group/interest_group_manager_impl.cc
@@ -531,6 +531,11 @@
                                                           signals_origin);
 }
 
+void InterestGroupManagerImpl::UpdateCachedOriginsIfEnabled(
+    const url::Origin& owner) {
+  caching_storage_.UpdateCachedOriginsIfEnabled(owner);
+}
+
 void InterestGroupManagerImpl::DeleteInterestGroupData(
     StoragePartition::StorageKeyMatcherFunction storage_key_matcher,
     base::OnceClosure completion_callback) {
diff --git a/content/browser/interest_group/interest_group_manager_impl.h b/content/browser/interest_group/interest_group_manager_impl.h
index 4f8e680..29e6757 100644
--- a/content/browser/interest_group/interest_group_manager_impl.h
+++ b/content/browser/interest_group/interest_group_manager_impl.h
@@ -304,23 +304,27 @@
       base::OnceCallback<void(scoped_refptr<StorageInterestGroups>)> callback);
 
   // For a given `owner`, return whether the owner origin and bidding signal
-  // origin were cached in-memory in previous calls to
-  // GetInterestGroupsForOwner and JoinInterestGroup. If the `owner` origin was
-  // cached, update `signals_origin` to the one that was cached -- or set to
-  // nullopt if no bidding signals origin was cached or if it would be the same
-  // as the owner origin. The cache includes at most one entry per origin, and
-  // may not reflect the results of interest group updates. It's intended to be
-  // used for best-effort preconnecting, and should not be considered
-  // authoritative. It is guaranteed not to contain interest groups that have
-  // are beyond the max expiration time limit, so preconnecting should not leak
-  // data the bidder would otherwise have access to, if it so desired. That is,
-  // manual voluntarily removing or expiring of an interest group may not be
-  // reflected in the result, but hitting the the global interest group lifetime
-  // cap will be respected.
+  // origin were cached in-memory via UpdateCachedOriginsIfEnabled. If the
+  // `owner` origin was cached, update `signals_origin` to the one that was
+  // cached -- or set to nullopt if no bidding signals origin was cached or if
+  // it would be the same as the owner origin. The cache includes at most one
+  // entry per origin, and may not reflect the results of interest group
+  // updates. It's intended to be used for best-effort preconnecting, and should
+  // not be considered authoritative. It is guaranteed not to contain interest
+  // groups that have are beyond the max expiration time limit, so preconnecting
+  // should not leak data the bidder would otherwise have access to, if it so
+  // desired. That is, manual voluntarily removing or expiring of an interest
+  // group may not be reflected in the result, but hitting the the global
+  // interest group lifetime cap will be respected.
   bool GetCachedOwnerAndSignalsOrigins(
       const url::Origin& owner,
       std::optional<url::Origin>& signals_origin);
 
+  // Update the cached owner and signal origins for an owner's interest groups
+  // if kFledgeUsePreconnectCache or kFledgeStartAnticipatoryProcesses are
+  // enabled and the owner's IGs are still in memory.
+  void UpdateCachedOriginsIfEnabled(const url::Origin& owner);
+
   // Clear out storage for the matching owning storage key. If the matcher is
   // empty then apply to all storage keys.
   void DeleteInterestGroupData(
diff --git a/content/browser/launch_as_mojo_client_browsertest.cc b/content/browser/launch_as_mojo_client_browsertest.cc
index 30169a1..c8097d4 100644
--- a/content/browser/launch_as_mojo_client_browsertest.cc
+++ b/content/browser/launch_as_mojo_client_browsertest.cc
@@ -13,7 +13,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/variations/field_trial_config/field_trial_util.h"
 #include "components/variations/variations_switches.h"
 #include "content/public/common/content_switches.h"
@@ -30,7 +29,7 @@
 #include "ui/ozone/public/ozone_switches.h"
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(MEMORY_SANITIZER)
+#if BUILDFLAG(IS_CHROMEOS) || defined(MEMORY_SANITIZER)
 #include "ui/gl/gl_switches.h"
 #endif
 
@@ -76,7 +75,7 @@
     command_line.CopySwitchesFrom(cmdline, kSwitchesToCopy);
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     command_line.AppendSwitchASCII(switches::kUseGL,
                                    gl::kGLImplementationANGLEName);
     command_line.AppendSwitchASCII(switches::kUseANGLE,
diff --git a/content/browser/loader/cors_file_origin_browsertest.cc b/content/browser/loader/cors_file_origin_browsertest.cc
index c7486b333..e6d3e7a 100644
--- a/content/browser/loader/cors_file_origin_browsertest.cc
+++ b/content/browser/loader/cors_file_origin_browsertest.cc
@@ -14,7 +14,6 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/test/scoped_command_line.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_paths.h"
diff --git a/content/browser/manifest/manifest_browsertest.cc b/content/browser/manifest/manifest_browsertest.cc
index d89ac67c..71aaa68 100644
--- a/content/browser/manifest/manifest_browsertest.cc
+++ b/content/browser/manifest/manifest_browsertest.cc
@@ -19,7 +19,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/public/browser/page.h"
 #include "content/public/browser/render_frame_host.h"
diff --git a/content/browser/media/audio_input_stream_broker.cc b/content/browser/media/audio_input_stream_broker.cc
index 0e4b468d..22d5ed1d 100644
--- a/content/browser/media/audio_input_stream_broker.cc
+++ b/content/browser/media/audio_input_stream_broker.cc
@@ -14,7 +14,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/media/audio_stream_broker_helper.h"
 #include "content/browser/media/media_internals.h"
diff --git a/content/browser/media/audio_stream_monitor_unittest.cc b/content/browser/media/audio_stream_monitor_unittest.cc
index 2abe07f..727c80b5 100644
--- a/content/browser/media/audio_stream_monitor_unittest.cc
+++ b/content/browser/media/audio_stream_monitor_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/functional/callback_helpers.h"
 #include "base/memory/raw_ptr.h"
 #include "base/time/time.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/invalidate_type.h"
 #include "content/public/browser/web_contents_delegate.h"
diff --git a/content/browser/media/capture/aura_window_video_capture_device.cc b/content/browser/media/capture/aura_window_video_capture_device.cc
index 45dd780..65eeb6f7 100644
--- a/content/browser/media/capture/aura_window_video_capture_device.cc
+++ b/content/browser/media/capture/aura_window_video_capture_device.cc
@@ -14,7 +14,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/task/single_thread_task_runner.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/media/capture/mouse_cursor_overlay_controller.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/content/browser/media/capture/aura_window_video_capture_device.h b/content/browser/media/capture/aura_window_video_capture_device.h
index b739cfd..3081c8e8 100644
--- a/content/browser/media/capture/aura_window_video_capture_device.h
+++ b/content/browser/media/capture/aura_window_video_capture_device.h
@@ -9,7 +9,6 @@
 
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/media/capture/frame_sink_video_capture_device.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/content/browser/media/capture/aura_window_video_capture_device_browsertest.cc b/content/browser/media/capture/aura_window_video_capture_device_browsertest.cc
index 5860f468..661e70b8 100644
--- a/content/browser/media/capture/aura_window_video_capture_device_browsertest.cc
+++ b/content/browser/media/capture/aura_window_video_capture_device_browsertest.cc
@@ -9,7 +9,6 @@
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/test/pixel_test_utils.h"
 #include "components/viz/common/features.h"
 #include "content/browser/media/capture/content_capture_device_browsertest_base.h"
@@ -338,7 +337,7 @@
 }
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 // Disabled (https://crbug.com/1096946)
 // On ChromeOS, another window may occlude a window that is being captured.
 // Make sure the visibility is set to visible during capture if it's occluded.
@@ -362,7 +361,7 @@
   window.reset();
   StopAndDeAllocate();
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 class AuraWindowVideoCaptureDeviceBrowserTestP
     : public AuraWindowVideoCaptureDeviceBrowserTest,
@@ -376,7 +375,7 @@
   }
 };
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 INSTANTIATE_TEST_SUITE_P(
     All,
     AuraWindowVideoCaptureDeviceBrowserTestP,
@@ -393,7 +392,7 @@
                                      true /* software compositing */),
                      testing::Values(false /* variable aspect ratio */,
                                      true /* fixed aspect ratio */)));
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 // Disabled (https://crbug.com/1096946)
 // Tests that the device successfully captures a series of content changes,
diff --git a/content/browser/media/capture/desktop_capture_device.cc b/content/browser/media/capture/desktop_capture_device.cc
index fba9bdf..3ba87e5 100644
--- a/content/browser/media/capture/desktop_capture_device.cc
+++ b/content/browser/media/capture/desktop_capture_device.cc
@@ -30,7 +30,6 @@
 #include "base/timer/timer.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/media/capture/desktop_capture_device_uma_types.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/content/browser/media/capture/frame_sink_video_capture_device_unittest.cc b/content/browser/media/capture/frame_sink_video_capture_device_unittest.cc
index c45dda87..6aa87c8 100644
--- a/content/browser/media/capture/frame_sink_video_capture_device_unittest.cc
+++ b/content/browser/media/capture/frame_sink_video_capture_device_unittest.cc
@@ -13,7 +13,6 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/read_only_shared_memory_region.h"
 #include "base/memory/shared_memory_mapping.h"
-#include "build/chromeos_buildflags.h"
 #include "components/viz/common/surfaces/region_capture_bounds.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/content/browser/media/capture/mouse_cursor_overlay_controller_browsertest.cc b/content/browser/media/capture/mouse_cursor_overlay_controller_browsertest.cc
index 8ca8c30..03385a2 100644
--- a/content/browser/media/capture/mouse_cursor_overlay_controller_browsertest.cc
+++ b/content/browser/media/capture/mouse_cursor_overlay_controller_browsertest.cc
@@ -7,7 +7,6 @@
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_tick_clock.h"
-#include "build/chromeos_buildflags.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
@@ -23,10 +22,10 @@
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/geometry/size_f.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "ui/aura/client/cursor_shape_client.h"
 #include "ui/wm/core/cursor_loader.h"  // nogncheck
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif                                 // BUILDFLAG(IS_CHROMEOS)
 
 using ::testing::Mock;
 
@@ -91,10 +90,10 @@
 
     // On Ash content browsertests, ash::Shell isn't initialized and thus
     // neither NativeCursorManagerAsh, the owner of CursorLoader.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     cursor_loader_ = std::make_unique<wm::CursorLoader>();
     aura::client::SetCursorShapeClient(cursor_loader_.get());
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
     controller_.SetTargetView(shell()->web_contents()->GetNativeView());
     controller_.DisconnectFromToolkitForTesting();
@@ -246,7 +245,7 @@
 
   MouseCursorOverlayController controller_;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   std::unique_ptr<wm::CursorLoader> cursor_loader_;
 #endif
 };
diff --git a/content/browser/media/capture/web_contents_video_capture_device_browsertest.cc b/content/browser/media/capture/web_contents_video_capture_device_browsertest.cc
index e9e09d1a..dc0b606 100644
--- a/content/browser/media/capture/web_contents_video_capture_device_browsertest.cc
+++ b/content/browser/media/capture/web_contents_video_capture_device_browsertest.cc
@@ -13,7 +13,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/test/pixel_test_utils.h"
 #include "content/browser/media/capture/content_capture_device_browsertest_base.h"
 #include "content/browser/media/capture/fake_video_capture_stack.h"
@@ -605,7 +604,7 @@
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_ANDROID)
+#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
 INSTANTIATE_TEST_SUITE_P(
     All,
     WebContentsVideoCaptureDeviceBrowserTestP,
@@ -660,7 +659,7 @@
 // TODO(crbug/329654821): Also flaky for ChromeOS ASAN LSAN and debug.
 #if defined(MEMORY_SANITIZER) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
     (BUILDFLAG(IS_CHROMEOS) && defined(ADDRESS_SANITIZER)) ||                \
-    (BUILDFLAG(IS_CHROMEOS_ASH) && !defined(NDEBUG))
+    (BUILDFLAG(IS_CHROMEOS) && !defined(NDEBUG))
 #define MAYBE_CapturesContentChanges DISABLED_CapturesContentChanges
 #else
 #define MAYBE_CapturesContentChanges CapturesContentChanges
diff --git a/content/browser/media/cdm_registry_impl.cc b/content/browser/media/cdm_registry_impl.cc
index 539a6b4..34f5f393b 100644
--- a/content/browser/media/cdm_registry_impl.cc
+++ b/content/browser/media/cdm_registry_impl.cc
@@ -17,7 +17,6 @@
 #include "base/types/expected.h"
 #include "base/types/optional_util.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/public/common/cdm_info.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
diff --git a/content/browser/media/cdm_registry_impl_unittest.cc b/content/browser/media/cdm_registry_impl_unittest.cc
index 4402ff64..b9799af 100644
--- a/content/browser/media/cdm_registry_impl_unittest.cc
+++ b/content/browser/media/cdm_registry_impl_unittest.cc
@@ -28,7 +28,6 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/types/expected.h"
 #include "base/version.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/public/common/cdm_info.h"
 #include "content/public/test/browser_task_environment.h"
diff --git a/content/browser/media/media_browsertest.cc b/content/browser/media/media_browsertest.cc
index 006b0aa..39d6dd7 100644
--- a/content/browser/media/media_browsertest.cc
+++ b/content/browser/media/media_browsertest.cc
@@ -11,7 +11,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/public/browser/gpu_utils.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
diff --git a/content/browser/media/media_color_browsertest.cc b/content/browser/media/media_color_browsertest.cc
index a4fcee2..3885c28e 100644
--- a/content/browser/media/media_color_browsertest.cc
+++ b/content/browser/media/media_color_browsertest.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/media/media_browsertest.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
diff --git a/content/browser/media/media_interface_proxy.cc b/content/browser/media/media_interface_proxy.cc
index 2153e46..357d53a 100644
--- a/content/browser/media/media_interface_proxy.cc
+++ b/content/browser/media/media_interface_proxy.cc
@@ -18,7 +18,6 @@
 #include "base/time/time.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/media/cdm_storage_common.h"
 #include "content/browser/renderer_host/render_frame_host_delegate.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
diff --git a/content/browser/media/media_interface_proxy.h b/content/browser/media/media_interface_proxy.h
index 414cb62c..9e601d5 100644
--- a/content/browser/media/media_interface_proxy.h
+++ b/content/browser/media/media_interface_proxy.h
@@ -13,7 +13,6 @@
 #include "base/threading/thread_checker.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/media/media_interface_factory_holder.h"
 #include "content/public/browser/document_user_data.h"
 #include "content/public/common/cdm_info.h"
diff --git a/content/browser/media/media_keys_listener_manager_impl.cc b/content/browser/media/media_keys_listener_manager_impl.cc
index 96c0aa8..e87c180 100644
--- a/content/browser/media/media_keys_listener_manager_impl.cc
+++ b/content/browser/media/media_keys_listener_manager_impl.cc
@@ -10,7 +10,6 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/observer_list.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/system_media_controls/system_media_controls.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/media/active_media_session_controller.h"
diff --git a/content/browser/media/media_keys_listener_manager_impl_browsertest.cc b/content/browser/media/media_keys_listener_manager_impl_browsertest.cc
index dc9264a..3229ec2 100644
--- a/content/browser/media/media_keys_listener_manager_impl_browsertest.cc
+++ b/content/browser/media/media_keys_listener_manager_impl_browsertest.cc
@@ -7,7 +7,6 @@
 #include "base/containers/flat_set.h"
 #include "base/memory/raw_ptr.h"
 #include "base/test/scoped_feature_list.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/media/active_media_session_controller.h"
 #include "content/public/test/browser_test.h"
diff --git a/content/browser/media/session/media_session_browsertest.cc b/content/browser/media/session/media_session_browsertest.cc
index 8ca12ca..46edf62 100644
--- a/content/browser/media/session/media_session_browsertest.cc
+++ b/content/browser/media/session/media_session_browsertest.cc
@@ -14,7 +14,6 @@
 #include "base/synchronization/lock.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc
index 5941763..897773e6 100644
--- a/content/browser/media/session/media_session_impl.cc
+++ b/content/browser/media/session/media_session_impl.cc
@@ -836,6 +836,10 @@
                                              GetVolumeMultiplier());
   }
 
+  for (const auto& it : one_shot_players_) {
+    it.observer->OnSetVolumeMultiplier(it.player_id, GetVolumeMultiplier());
+  }
+
   for (const auto& it : pepper_players_)
     it.observer->OnSetVolumeMultiplier(it.player_id, GetVolumeMultiplier());
 }
diff --git a/content/browser/media/session/media_session_impl_browsertest.cc b/content/browser/media/session/media_session_impl_browsertest.cc
index 4d11caf2..d09f5c28 100644
--- a/content/browser/media/session/media_session_impl_browsertest.cc
+++ b/content/browser/media/session/media_session_impl_browsertest.cc
@@ -21,7 +21,6 @@
 #include "base/test/simple_test_tick_clock.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/media/session/audio_focus_delegate.h"
 #include "content/browser/media/session/mock_media_session_player_observer.h"
 #include "content/browser/media/session/mock_media_session_service_impl.h"
@@ -3041,7 +3040,7 @@
   }
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_ANDROID)
+#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
 // TODO(crbug.com/40097218): Re-enable this test.
 #define MAYBE_PositionStateRouteWithOnePlayer \
   DISABLED_PositionStateRouteWithOnePlayer
diff --git a/content/browser/media/stable_video_decoder_factory.cc b/content/browser/media/stable_video_decoder_factory.cc
index 8dee2eb..76298c00 100644
--- a/content/browser/media/stable_video_decoder_factory.cc
+++ b/content/browser/media/stable_video_decoder_factory.cc
@@ -10,7 +10,6 @@
 #include "content/public/browser/stable_video_decoder_factory.h"
 
 #include "base/containers/queue.h"
-#include "build/chromeos_buildflags.h"
 #include "components/viz/common/switches.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/public/browser/browser_task_traits.h"
diff --git a/content/browser/network/trust_token_browsertest.cc b/content/browser/network/trust_token_browsertest.cc
index a3fc4ade..c0eea90 100644
--- a/content/browser/network/trust_token_browsertest.cc
+++ b/content/browser/network/trust_token_browsertest.cc
@@ -11,7 +11,6 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/bind.h"
-#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/network_service_instance.h"
@@ -24,7 +23,6 @@
 #include "content/public/test/url_loader_monitor.h"
 #include "content/shell/browser/shell.h"
 #include "net/dns/mock_host_resolver.h"
-#include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/trust_token_http_headers.h"
@@ -93,15 +91,7 @@
 
 }  // namespace
 
-TrustTokenBrowsertest::TrustTokenBrowsertest() {
-  auto& field_trial_param =
-      network::features::kTrustTokenOperationsRequiringOriginTrial;
-  features_.InitAndEnableFeatureWithParameters(
-      network::features::kPrivateStateTokens,
-      {{field_trial_param.name,
-        field_trial_param.GetName(network::features::TrustTokenOriginTrialSpec::
-                                      kOriginTrialNotRequired)}});
-}
+TrustTokenBrowsertest::TrustTokenBrowsertest() = default;
 
 void TrustTokenBrowsertest::SetUpOnMainThread() {
   host_resolver()->AddRule("*", "127.0.0.1");
diff --git a/content/browser/network/trust_token_origin_trial_browsertest.cc b/content/browser/network/trust_token_origin_trial_browsertest.cc
deleted file mode 100644
index d025769..0000000
--- a/content/browser/network/trust_token_origin_trial_browsertest.cc
+++ /dev/null
@@ -1,394 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/strings/string_util.h"
-#include "base/test/bind.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/thread_annotations.h"
-#include "content/public/test/browser_test.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/content_browser_test.h"
-#include "content/public/test/content_browser_test_utils.h"
-#include "content/public/test/url_loader_monitor.h"
-#include "content/shell/browser/shell.h"
-#include "services/network/public/cpp/features.h"
-#include "services/network/public/cpp/resource_request.h"
-#include "services/network/public/mojom/trust_tokens.mojom.h"
-#include "services/network/test/trust_token_test_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-// These integration tests cover the interaction between the Trust Token API's
-// Fetch and iframe surfaces and various configuration requiring Origin Trial
-// tokens to execute some or all of the Trust Tokens operations (issuance,
-// redemption, and signing).
-//
-// There are two configuration modes:
-// - "third-party origin trial": all Trust Tokens operations require an origin
-// trial token to execute and, if a token is missing, the Trust Tokens interface
-// disppears so that attempts to execute operations will silently no-op. This is
-// because the Trust Tokens interface manifests itself as an additional argument
-// in fetch's RequestInit dictionary, which does not throw errors when
-// unexpected arguments are provided.
-// - "standard origin trial": only Trust Tokens issuance requires an origin
-// trial token to execute and, if a token is missing, issuance will fail.
-//
-// As an example, consider
-//
-//    fetch("https://chromium.org", {
-//        privateToken: {
-//            version: 1,
-//            operation: 'token-request'}})
-//
-// a representative fetch with an associated Trust Tokens issuance operation.
-// When Trust Tokens is completely disabled (e.g. "third-party origin trial"
-// mode with no token), the trustToken argument will be ignored. On the other
-// hand, when Trust Tokens is enabled but issuance is forbidden ("standard
-// origin trial" mode with no token), this will reject with an exception.
-
-namespace content {
-
-namespace {
-
-using ::testing::Combine;
-using ::testing::Values;
-using ::testing::ValuesIn;
-
-// Trust Tokens has three interfaces: fetch, XHR, and iframe. However, the XHR
-// and fetch interfaces use essentially identical code paths, so we exclude the
-// XHR interface in order to save some test duration.
-enum class Interface {
-  kFetch,
-  kIframe,
-};
-
-// Prints a string representation to use for generating test names.
-std::string ToString(Interface interface) {
-  switch (interface) {
-    case Interface::kFetch:
-      return "Fetch";
-    case Interface::kIframe:
-      return "Iframe";
-  }
-}
-
-using Op = network::mojom::TrustTokenOperationType;
-
-enum class Outcome {
-  // A request with Trust Tokens parameters should reach the network stack.
-  kSuccess,
-  // A request without Trust Tokens parameters should reach the network stack.
-  kSuccessWithoutTrustTokenParams,
-  // The Trust Tokens operation should error out. For the Fetch interface, this
-  // means an exception gets thrown; for the iframe interface, it means we
-  // continue the request with no Trust Tokens parameters (i.e., it's equivalent
-  // to kSuccessWithoutTrustTokenParams).
-  kFailure,
-};
-
-enum class TrialEnabled {
-  // The Trust Tokens operation at hand will be executed from a context with an
-  // origin trial token.
-  kEnabled,
-  // The Trust Tokens operation at hand will be executed from a context lacking
-  // an origin trial token.
-  kDisabled,
-};
-
-// Prints a string representation to use for generating test names.
-std::string ToString(TrialEnabled trial_enabled) {
-  switch (trial_enabled) {
-    case TrialEnabled::kEnabled:
-      return "TrialEnabled";
-    case TrialEnabled::kDisabled:
-      return "TrialDisabled";
-  }
-}
-
-using TrialType = network::features::TrustTokenOriginTrialSpec;
-
-// Prints a string representation to use for generating test names.
-std::string ToString(TrialType trial_type) {
-  switch (trial_type) {
-    case TrialType::kAllOperationsRequireOriginTrial:
-      return "AllOpsNeedTrial";
-    case TrialType::kOnlyIssuanceRequiresOriginTrial:
-      return "OnlyIssuanceNeedsTrial";
-    default:
-      NOTREACHED();
-  }
-}
-
-struct TestDescription {
-  Op op;
-  Outcome outcome;
-  TrialType trial_type;
-  TrialEnabled trial_enabled;
-};
-
-class TrustTokenOriginTrialBrowsertest
-    : public ContentBrowserTest,
-      public ::testing::WithParamInterface<
-          std::tuple<Interface, TestDescription>> {
- public:
-  TrustTokenOriginTrialBrowsertest() {
-    auto& field_trial_param =
-        network::features::kTrustTokenOperationsRequiringOriginTrial;
-    // kPrivateStateTokens ignores origin trial params
-    features_.InitWithFeaturesAndParameters(
-        {{network::features::kFledgePst,
-          {{field_trial_param.name,
-            field_trial_param.GetName(std::get<1>(GetParam()).trial_type)}}}},
-        {network::features::kPrivateStateTokens});
-  }
-
-  // kPageWithOriginTrialToken is a landing page from which we execute Trust
-  // Tokens operations in test cases that require an origin trial token to be
-  // present. We use a deterministic port and swap in the landing page with
-  // URLLoaderInterceptor, rather than serving the page from
-  // EmbeddedTestServer, because the token is generated offline and bound to a
-  // specific origin.
-  const GURL kPageWithOriginTrialToken{"http://localhost:5555"};
-
-  // kTrustTokenUrl is the destination URL of the executed Trust Tokens
-  // operations. It's arbitrary, since the tests just need to intercept
-  // requests en route to check if they bear Trust Tokens parameters.
-  const GURL kTrustTokenUrl{kPageWithOriginTrialToken.Resolve("/trust-token")};
-
- protected:
-  // OnRequest is a URLLoaderInterceptor callback. It:
-  // - serves the Origin Trials token when navigating to the landing page
-  // - quits the run loop, and stores the obtained request, when receiving a
-  // request to the Trust Tokens URL
-  // - declines to intercept otherwise (e.g. on favicon load)
-  //
-  // For the reasons discussed in |kPageWithOriginTrialToken|'s member comment,
-  // we need to use an interceptor to serve the landing page. Since we're
-  // already stuck with having an interceptor around, we use the same
-  // interceptor---instead of, say, registering an EmbeddedTestServer
-  // callback---to verify that requests sent to the Trust Tokens endpoint bear
-  // (or omit) Trust Tokens parameters. (This also lets us avoid having to set
-  // up all of the server-side logic necessary for executing a Trust Tokens
-  // operation end to end.)
-  bool OnRequest(URLLoaderInterceptor::RequestParams* params) {
-    if (params->url_request.url == kPageWithOriginTrialToken) {
-      // Origin Trials key generated with:
-      //
-      // tools/origin_trials/generate_token.py --expire-days 5000 --version 3 \
-      // http://localhost:5555 TrustTokens
-      //
-      // Note that you can't have an origin trial token with expiry more than
-      // 2^31-1 seconds past the epoch, so (for instance) --expire-days 10000
-      // would not have generated a valid token.
-      URLLoaderInterceptor::WriteResponse(
-          base::ReplaceStringPlaceholders(
-              "HTTP/1.1 200 OK\n"
-              "Content-type: text/html\n"
-              "Origin-Trial: $1\n\n",
-              {"A220DaFwmOb78vs8TojpryN1mfL9+zHjNDdo+rJTwRcaPkCIzU4/"
-               "vP9pnSHyI2ye8WsoxToBprvd7YH+"
-               "SdR0FgAAAABTeyJvcmlnaW4iOiAiaHR0cDovL2xvY2FsaG9zdDo1NTU1IiwgImZ"
-               "lYXR1cmUiOiAiVHJ1c3RUb2tlbnMiLCAiZXhwaXJ5IjogMjAyNTQ1OTI0MX0="},
-              /*offsets=*/nullptr),
-          /*body=*/"", params->client.get());
-      return true;
-    }
-
-    if (params->url_request.url == kTrustTokenUrl) {
-      {
-        base::AutoLock lock(mutex_);
-        CHECK(!trust_token_request_)
-            << "Unexpected second Trust Tokens request";
-        trust_token_request_ = params->url_request;
-      }
-
-      // Write a response here so that the request doesn't fail: this is
-      // necessary so that tests expecting kFailure do not erroneously pass in
-      // cases where the request does not error out.
-      URLLoaderInterceptor::WriteResponse(
-          "HTTP/1.1 200 OK\nContent-type: text/html\n\n", /*body=*/"",
-          params->client.get());
-
-      base::OnceClosure done;
-      {
-        base::AutoLock lock(mutex_);
-        done = std::move(on_received_request_);
-      }
-
-      std::move(done).Run();
-
-      return true;
-    }
-
-    return false;
-  }
-
-  base::test::ScopedFeatureList features_;
-
-  // The request data is written on the IO sequence and read on the main
-  // sequence.
-  base::Lock mutex_;
-
-  // |on_received_request_| is called once a request arrives at
-  // |kTrustTokenUrl|; the request is then placed in |trust_token_request_|.
-  base::OnceClosure on_received_request_ GUARDED_BY(mutex_);
-  std::optional<network::ResourceRequest> trust_token_request_
-      GUARDED_BY(mutex_);
-};
-
-const TestDescription kTestDescriptions[] = {
-    {Op::kIssuance, Outcome::kSuccess,
-     TrialType::kOnlyIssuanceRequiresOriginTrial, TrialEnabled::kEnabled},
-
-    {Op::kRedemption, Outcome::kSuccess,
-     TrialType::kOnlyIssuanceRequiresOriginTrial, TrialEnabled::kEnabled},
-
-    {Op::kRedemption, Outcome::kSuccess,
-     TrialType::kOnlyIssuanceRequiresOriginTrial, TrialEnabled::kDisabled},
-
-    {Op::kIssuance, Outcome::kSuccess,
-     TrialType::kAllOperationsRequireOriginTrial, TrialEnabled::kEnabled},
-
-    {Op::kIssuance, Outcome::kSuccessWithoutTrustTokenParams,
-     TrialType::kAllOperationsRequireOriginTrial, TrialEnabled::kDisabled},
-
-    {Op::kRedemption, Outcome::kSuccess,
-     TrialType::kAllOperationsRequireOriginTrial, TrialEnabled::kEnabled},
-
-    {Op::kRedemption, Outcome::kSuccessWithoutTrustTokenParams,
-     TrialType::kAllOperationsRequireOriginTrial, TrialEnabled::kDisabled},
-};
-
-// Prints a string representation to use for generating test names.
-std::string ToString(Op op) {
-  switch (op) {
-    case Op::kIssuance:
-      return "Issuance";
-    case Op::kRedemption:
-      return "Redemption";
-    default:
-      NOTREACHED();
-  }
-}
-
-std::string TestParamToString(
-    const ::testing::TestParamInfo<std::tuple<Interface, TestDescription>>&
-        info) {
-  Interface interface = std::get<0>(info.param);
-  const TestDescription& test_description = std::get<1>(info.param);
-
-  return base::ReplaceStringPlaceholders(
-      "$1_$2_$3_$4",
-      {ToString(interface), ToString(test_description.op),
-       ToString(test_description.trial_type),
-       ToString(test_description.trial_enabled)},
-      nullptr);
-}
-
-}  // namespace
-
-// Each parameter has to be a valid JSON encoding of a TrustToken JS object
-// *and* valid to directly substitute into JS: this is because the iframe API
-// requires a JSON encoding of the parameters object, while the Fetch and XHR
-// APIs require actual objects.
-INSTANTIATE_TEST_SUITE_P(ExecutingAllOperations,
-                         TrustTokenOriginTrialBrowsertest,
-                         Combine(Values(Interface::kFetch, Interface::kIframe),
-                                 ValuesIn(kTestDescriptions)),
-                         &TestParamToString);
-
-// Test that a Trust Tokens request passes parameters to the network stack
-// only when permitted by the origin trials framework (either because
-// configuration specifies that no origin trial token is required, or because an
-// origin trial token is present in the executing context).
-IN_PROC_BROWSER_TEST_P(TrustTokenOriginTrialBrowsertest,
-                       ProvidesParamsOnlyWhenAllowed) {
-  TestDescription test_description = std::get<1>(GetParam());
-  Interface interface = std::get<0>(GetParam());
-
-  URLLoaderInterceptor interceptor(base::BindLambdaForTesting(
-      [this](URLLoaderInterceptor::RequestParams* params) {
-        return OnRequest(params);
-      }));
-
-  switch (test_description.trial_enabled) {
-    case TrialEnabled::kEnabled:
-      ASSERT_TRUE(NavigateToURL(shell(), kPageWithOriginTrialToken));
-      break;
-    case TrialEnabled::kDisabled:
-      ASSERT_TRUE(embedded_test_server()->Start());
-      ASSERT_TRUE(NavigateToURL(
-          shell(), embedded_test_server()->GetURL("/title1.html")));
-      break;
-  }
-
-  base::RunLoop run_loop;
-
-  {
-    base::AutoLock lock(mutex_);
-    on_received_request_ = run_loop.QuitClosure();
-  }
-
-  network::TrustTokenTestParameters trust_token_params(
-      1, test_description.op, std::nullopt, std::nullopt);
-
-  network::TrustTokenParametersAndSerialization
-      expected_params_and_serialization =
-          network::SerializeTrustTokenParametersAndConstructExpectation(
-              trust_token_params);
-
-  std::string command;
-  switch (interface) {
-    case Interface::kFetch:
-      command = JsReplace("fetch($1, {privateToken: ", kTrustTokenUrl) +
-                expected_params_and_serialization.serialized_params + "});";
-      break;
-    case Interface::kIframe:
-      if (test_description.op != Op::kSigning) {
-        return;
-      }
-      command = JsReplace(
-          "let iframe = document.createElement('iframe');"
-          "iframe.src = $1;"
-          "iframe.trustToken = $2;"
-          "document.body.appendChild(iframe);",
-          kTrustTokenUrl, expected_params_and_serialization.serialized_params);
-
-      // When a Trust Tokens operation fails via the iframe interface, the
-      // request itself will still execute, just without an associated Trust
-      // Tokens operation.
-      if (test_description.outcome == Outcome::kFailure)
-        test_description.outcome = Outcome::kSuccessWithoutTrustTokenParams;
-      break;
-  }
-
-  if (test_description.outcome == Outcome::kFailure) {
-    // Use EvalJs here to wait for promises to resolve.
-    EXPECT_THAT(EvalJs(shell(), command), EvalJsResult::IsError());
-    return;
-  }
-
-  ASSERT_TRUE(ExecJs(shell(), command));
-
-  run_loop.Run();
-
-  // URLLoaderInterceptor writes to trust_token_request_ on the IO sequence.
-  base::AutoLock lock(mutex_);
-
-  ASSERT_TRUE(trust_token_request_);
-
-  switch (test_description.outcome) {
-    case Outcome::kSuccess:
-      EXPECT_TRUE(trust_token_request_->trust_token_params);
-      break;
-    case Outcome::kSuccessWithoutTrustTokenParams:
-      EXPECT_FALSE(trust_token_request_->trust_token_params);
-      break;
-    case Outcome::kFailure:
-      NOTREACHED();  // Handled earlier.
-  }
-}
-
-}  // namespace content
diff --git a/content/browser/network/trust_token_parameters_browsertest.cc b/content/browser/network/trust_token_parameters_browsertest.cc
index 6155efa..a570d7e 100644
--- a/content/browser/network/trust_token_parameters_browsertest.cc
+++ b/content/browser/network/trust_token_parameters_browsertest.cc
@@ -6,7 +6,6 @@
 #include "base/strings/escape.h"
 #include "base/strings/strcat.h"
 #include "base/test/bind.h"
-#include "base/test/scoped_feature_list.h"
 #include "content/public/browser/network_service_util.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
@@ -17,7 +16,6 @@
 #include "content/shell/browser/shell.h"
 #include "content/shell/browser/shell_content_browser_client.h"
 #include "net/dns/mock_host_resolver.h"
-#include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/trust_tokens.mojom.h"
@@ -25,7 +23,6 @@
 #include "services/network/test/trust_token_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/features.h"
 
 // These integration tests verify that calling the Fetch API with Trust Tokens
 // parameters results in the parameters' counterparts appearing downstream in
@@ -40,19 +37,7 @@
     : public ::testing::WithParamInterface<network::TrustTokenTestParameters>,
       public ContentBrowserTest {
  public:
-  TrustTokenParametersBrowsertest() {
-    auto& field_trial_param =
-        network::features::kTrustTokenOperationsRequiringOriginTrial;
-    features_.InitAndEnableFeatureWithParameters(
-        network::features::kFledgePst,
-        {{field_trial_param.name,
-          field_trial_param.GetName(
-              network::features::TrustTokenOriginTrialSpec::
-                  kOriginTrialNotRequired)}});
-  }
-
- protected:
-  base::test::ScopedFeatureList features_;
+  TrustTokenParametersBrowsertest() = default;
 };
 
 INSTANTIATE_TEST_SUITE_P(
@@ -175,16 +160,11 @@
 
 class TrustTokenPermissionsPolicyBrowsertest : public ContentBrowserTest {
  public:
-  TrustTokenPermissionsPolicyBrowsertest() {
-    features_.InitAndEnableFeature(network::features::kPrivateStateTokens);
-  }
+  TrustTokenPermissionsPolicyBrowsertest() = default;
 
   void SetUpOnMainThread() override {
     host_resolver()->AddRule("*", "127.0.0.1");
   }
-
- protected:
-  base::test::ScopedFeatureList features_;
 };
 
 IN_PROC_BROWSER_TEST_F(TrustTokenPermissionsPolicyBrowsertest,
@@ -453,7 +433,6 @@
 
  private:
   content::test::FencedFrameTestHelper fenced_frame_helper_;
-  base::test::ScopedFeatureList features_;
 };
 
 INSTANTIATE_TEST_SUITE_P(All,
diff --git a/content/browser/network_context_client_base_impl.cc b/content/browser/network_context_client_base_impl.cc
index 51ff367b..e4dca468 100644
--- a/content/browser/network_context_client_base_impl.cc
+++ b/content/browser/network_context_client_base_impl.cc
@@ -10,7 +10,6 @@
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/file_access/scoped_file_access.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/public/browser/content_browser_client.h"
diff --git a/content/browser/network_service_instance_impl.cc b/content/browser/network_service_instance_impl.cc
index 84fc35a..0466122 100644
--- a/content/browser/network_service_instance_impl.cc
+++ b/content/browser/network_service_instance_impl.cc
@@ -40,7 +40,6 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/first_party_sets/first_party_sets_handler_impl.h"
 #include "content/browser/network/http_cache_backend_file_operations_factory.h"
diff --git a/content/browser/payments/payment_app_browsertest.cc b/content/browser/payments/payment_app_browsertest.cc
index 442c50f..b44c4e7 100644
--- a/content/browser/payments/payment_app_browsertest.cc
+++ b/content/browser/payments/payment_app_browsertest.cc
@@ -7,7 +7,6 @@
 #include "base/command_line.h"
 #include "base/functional/bind.h"
 #include "base/run_loop.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/installed_payment_apps_finder.h"
diff --git a/content/browser/pointer_lock_browsertest.cc b/content/browser/pointer_lock_browsertest.cc
index 4381505..f15bb423 100644
--- a/content/browser/pointer_lock_browsertest.cc
+++ b/content/browser/pointer_lock_browsertest.cc
@@ -9,7 +9,6 @@
 #include "base/memory/raw_ptr.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/input/render_widget_host_input_event_router.h"
 #include "content/browser/renderer_host/frame_tree.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
@@ -833,7 +832,7 @@
 
 #if defined(USE_AURA)
 // TODO(crbug.com/40635377): Remove failure test when fully implemented
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
 #define MAYBE_ChangeUnadjustedMovementFailure \
   DISABLED_ChangeUnadjustedMovementFailure
 #else
diff --git a/content/browser/preloading/prefetch/prefetch_container.cc b/content/browser/preloading/prefetch/prefetch_container.cc
index 21a4be2..248597a4 100644
--- a/content/browser/preloading/prefetch/prefetch_container.cc
+++ b/content/browser/preloading/prefetch/prefetch_container.cc
@@ -1061,10 +1061,6 @@
 
 void PrefetchContainer::AddXClientDataHeader(
     network::ResourceRequest& request) {
-  if (!base::FeatureList::IsEnabled(features::kPrefetchXClientDataHeader)) {
-    return;
-  }
-
   if (browser_context_) {
     // Add X-Client-Data header with experiment IDs from field trials.
     variations::AppendVariationsHeader(request.url,
diff --git a/content/browser/preloading/prefetch/prefetch_container_unittest.cc b/content/browser/preloading/prefetch/prefetch_container_unittest.cc
index 07e72ab..c6de160 100644
--- a/content/browser/preloading/prefetch/prefetch_container_unittest.cc
+++ b/content/browser/preloading/prefetch/prefetch_container_unittest.cc
@@ -172,13 +172,10 @@
 
 class PrefetchContainerXClientDataHeaderTest
     : public PrefetchContainerTestBase,
-      // In incognito or not, is X-Client-Header prefetch support enabled or
-      // not.
-      public ::testing::WithParamInterface<std::tuple<bool, bool>> {
+      // In incognito or not.
+      public ::testing::WithParamInterface<bool> {
  private:
   void SetUp() override {
-    scoped_feature_list_.InitWithFeatureState(
-        features::kPrefetchXClientDataHeader, get<1>(GetParam()));
     PrefetchContainerTestBase::SetUp();
   }
 
@@ -188,7 +185,7 @@
  protected:
   std::unique_ptr<BrowserContext> CreateBrowserContext() override {
     auto browser_context = std::make_unique<TestBrowserContext>();
-    auto is_incognito = get<0>(GetParam());
+    auto is_incognito = GetParam();
     browser_context->set_is_off_the_record(is_incognito);
     return browser_context;
   }
@@ -205,12 +202,11 @@
 
   prefetch_container->MakeResourceRequest({});
   auto* request = prefetch_container->GetResourceRequest();
-  bool is_incognito, is_x_client_data_header_enabled;
-  std::tie(is_incognito, is_x_client_data_header_enabled) = GetParam();
+  bool is_incognito = GetParam();
   // Don't add the header when in incognito mode.
   EXPECT_EQ(
       request->cors_exempt_headers.HasHeader(variations::kClientDataHeader),
-      !is_incognito && is_x_client_data_header_enabled);
+      !is_incognito);
 }
 
 TEST_P(PrefetchContainerXClientDataHeaderTest,
@@ -246,11 +242,10 @@
       request->cors_exempt_headers.HasHeader(variations::kClientDataHeader));
 
   AddRedirectHop(prefetch_container.get(), kTestEligibleUrl);
-  bool is_incognito, is_x_client_data_header_enabled;
-  std::tie(is_incognito, is_x_client_data_header_enabled) = GetParam();
+  bool is_incognito = GetParam();
   EXPECT_EQ(
       request->cors_exempt_headers.HasHeader(variations::kClientDataHeader),
-      !is_incognito && is_x_client_data_header_enabled);
+      !is_incognito);
 }
 
 TEST_P(PrefetchContainerXClientDataHeaderTest,
@@ -276,8 +271,7 @@
 
 INSTANTIATE_TEST_SUITE_P(PrefetchContainerXClientDataTests,
                          PrefetchContainerXClientDataHeaderTest,
-                         ::testing::Combine(::testing::Bool(),
-                                            ::testing::Bool()));
+                         ::testing::Bool());
 
 TEST_P(PrefetchContainerTest, CreatePrefetchContainer) {
   blink::DocumentToken document_token;
diff --git a/content/browser/preloading/prefetch/prefetch_features.cc b/content/browser/preloading/prefetch/prefetch_features.cc
index af5c01ca..bce9d38 100644
--- a/content/browser/preloading/prefetch/prefetch_features.cc
+++ b/content/browser/preloading/prefetch/prefetch_features.cc
@@ -32,10 +32,6 @@
              "PrefetchClientHints",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-BASE_FEATURE(kPrefetchXClientDataHeader,
-             "PrefetchXClientDataHeader",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 constexpr base::FeatureParam<PrefetchClientHintsCrossSiteBehavior>::Option
     kPrefetchClientHintsCrossSiteBehaviorOptions[] = {
         {PrefetchClientHintsCrossSiteBehavior::kNone, "none"},
diff --git a/content/browser/preloading/prefetch/prefetch_features.h b/content/browser/preloading/prefetch/prefetch_features.h
index a989b14..fb24b3bb 100644
--- a/content/browser/preloading/prefetch/prefetch_features.h
+++ b/content/browser/preloading/prefetch/prefetch_features.h
@@ -54,9 +54,6 @@
     PrefetchClientHintsCrossSiteBehavior>
     kPrefetchClientHintsCrossSiteBehavior;
 
-// If enabled, prefetch requests may include X-Client-Data request header.
-CONTENT_EXPORT BASE_DECLARE_FEATURE(kPrefetchXClientDataHeader);
-
 // If enabled, then prefetch serving will apply mitigations if it may have been
 // contaminated by cross-partition state.
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kPrefetchStateContaminationMitigation);
diff --git a/content/browser/preloading/prefetch/prefetch_match_resolver.cc b/content/browser/preloading/prefetch/prefetch_match_resolver.cc
index af3b7c0b..7fed181a 100644
--- a/content/browser/preloading/prefetch/prefetch_match_resolver.cc
+++ b/content/browser/preloading/prefetch/prefetch_match_resolver.cc
@@ -9,6 +9,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
 #include "base/ranges/algorithm.h"
+#include "base/trace_event/trace_event.h"
 #include "content/browser/preloading/prefetch/prefetch_container.h"
 #include "content/browser/preloading/prefetch/prefetch_params.h"
 #include "content/browser/preloading/prefetch/prefetch_service.h"
@@ -200,6 +201,7 @@
     base::WeakPtr<PrefetchServingPageMetricsContainer>
         serving_page_metrics_container,
     Callback callback) {
+  TRACE_EVENT0("loading", "PrefetchMatchResolver2::FindPrefetch");
   // See the comment of `self_`.
   auto prefetch_match_resolver = base::WrapUnique(new PrefetchMatchResolver2(
       std::move(navigated_key), prefetch_service.GetWeakPtr(),
@@ -431,6 +433,8 @@
 
 void PrefetchMatchResolver2::UnblockForMatch(
     const PrefetchContainer::Key& prefetch_key) {
+  TRACE_EVENT0("loading", "PrefetchMatchResolver2::UnblockForMatch");
+
   // By #prefetch-key-availability
   CHECK(candidates_.contains(prefetch_key));
   auto& candidate_data = candidates_[prefetch_key];
@@ -472,6 +476,7 @@
 }
 
 void PrefetchMatchResolver2::UnblockForNoCandidates() {
+  TRACE_EVENT0("loading", "PrefetchMatchResolver2::UnblockForNoCandidates");
   UnblockInternal({});
 }
 
diff --git a/content/browser/preloading/prefetch/prefetch_network_context_client.cc b/content/browser/preloading/prefetch/prefetch_network_context_client.cc
index 5466aec..c787fcb 100644
--- a/content/browser/preloading/prefetch/prefetch_network_context_client.cc
+++ b/content/browser/preloading/prefetch/prefetch_network_context_client.cc
@@ -7,7 +7,6 @@
 #include <memory>
 
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "net/base/net_errors.h"
 #include "services/network/public/mojom/trust_tokens.mojom.h"
diff --git a/content/browser/preloading/prefetch/prefetch_network_context_client.h b/content/browser/preloading/prefetch/prefetch_network_context_client.h
index c0110ef..e30964de 100644
--- a/content/browser/preloading/prefetch/prefetch_network_context_client.h
+++ b/content/browser/preloading/prefetch/prefetch_network_context_client.h
@@ -6,7 +6,6 @@
 #define CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_NETWORK_CONTEXT_CLIENT_H_
 
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "services/network/public/cpp/network_service_buildflags.h"
 #include "services/network/public/mojom/network_context_client.mojom.h"
diff --git a/content/browser/preloading/prefetch/prefetch_url_loader_interceptor.cc b/content/browser/preloading/prefetch/prefetch_url_loader_interceptor.cc
index a9275bb3..95b85ec1 100644
--- a/content/browser/preloading/prefetch/prefetch_url_loader_interceptor.cc
+++ b/content/browser/preloading/prefetch/prefetch_url_loader_interceptor.cc
@@ -74,6 +74,7 @@
     BrowserContext* browser_context,
     NavigationLoaderInterceptor::LoaderCallback callback,
     NavigationLoaderInterceptor::FallbackCallback fallback_callback) {
+  TRACE_EVENT0("loading", "PrefetchURLLoaderInterceptor::MaybeCreateLoader");
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   CHECK(!loader_callback_);
@@ -163,6 +164,7 @@
     PrefetchMatchResolver& prefetch_match_resolver,
     base::OnceCallback<void(PrefetchContainer::Reader)> get_prefetch_callback)
     const {
+  TRACE_EVENT0("loading", "PrefetchURLLoaderInterceptor::GetPrefetch");
   PrefetchService* prefetch_service =
       PrefetchService::GetFromFrameTreeNodeId(frame_tree_node_id_);
   if (!prefetch_service) {
@@ -212,6 +214,8 @@
 
 void PrefetchURLLoaderInterceptor::OnGetPrefetchComplete(
     PrefetchContainer::Reader reader) {
+  TRACE_EVENT0("loading",
+               "PrefetchURLLoaderInterceptor::OnGetPrefetchComplete");
   PrefetchRequestHandler request_handler;
   if (!reader || !(request_handler = reader.CreateRequestHandler())) {
     // Do not intercept the request.
diff --git a/content/browser/preloading/prerender/prerender_browsertest.cc b/content/browser/preloading/prerender/prerender_browsertest.cc
index 2f35dd0..4fdcce7d 100644
--- a/content/browser/preloading/prerender/prerender_browsertest.cc
+++ b/content/browser/preloading/prerender/prerender_browsertest.cc
@@ -34,7 +34,6 @@
 #include "base/thread_annotations.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/base/features.h"
 #include "components/input/render_widget_host_input_event_router.h"
 #include "components/services/storage/public/mojom/storage_service.mojom.h"
@@ -653,6 +652,8 @@
                                                   expected_prediction_entry);
   }
 
+  void TestActivateOnWindowOpen(std::string_view window_features);
+
   void TestHostPrerenderingState(const GURL& prerender_url) {
     const GURL kInitialUrl = GetUrl("/empty.html");
 
@@ -3121,81 +3122,33 @@
           /*accurate=*/false)});
 }
 
-// Tests that window.open() annotated with "_blank" and "noopener" can activate
-// a prerender whose target_hint is "_blank".
-IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, ActivateOnWindowOpen_NewTab) {
-  const GURL kInitialUrl = GetUrl("/simple_links.html");
-  const GURL kPrerenderingUrl = GetUrl("/title2.html");
-
-  // Navigate to an initial page which has a link to `kPrerenderingUrl`.
-  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
-
-  // Start prerendering `kPrerenderingUrl`.
-  FrameTreeNodeId host_id = prerender_helper()->AddPrerender(
-      kPrerenderingUrl, /*eagerness=*/std::nullopt, "_blank");
-  auto* prerender_web_contents = WebContents::FromFrameTreeNodeId(host_id);
-  ASSERT_NE(prerender_web_contents, web_contents_impl());
-  ExpectWebContentsIsForNewTabPrerendering(*prerender_web_contents);
-
-  // Open a new window with "_blank" and "noopener". This should activate the
-  // prerendered page.
-  TestNavigationObserver activation_observer(kPrerenderingUrl);
-  activation_observer.WatchExistingWebContents();
-  test::PrerenderHostObserver prerender_observer(*prerender_web_contents,
-                                                 host_id);
-  const std::string kWindowOpenScript = R"(
-      window.open("title2.html", "_blank", "noopener");
-  )";
-  EXPECT_TRUE(ExecJs(web_contents(), kWindowOpenScript));
-  activation_observer.WaitForNavigationFinished();
-  EXPECT_EQ(prerender_web_contents->GetLastCommittedURL(), kPrerenderingUrl);
-  EXPECT_EQ(activation_observer.last_navigation_url(), kPrerenderingUrl);
-  EXPECT_TRUE(prerender_observer.was_activated());
-  EXPECT_FALSE(HasHostForUrl(*prerender_web_contents, kPrerenderingUrl));
-
-  ExpectFinalStatusForSpeculationRule(PrerenderFinalStatus::kActivated);
-
-  ukm::SourceId ukm_source_id = activation_observer.next_page_ukm_source_id();
-  ExpectPreloadingAttemptUkm({attempt_ukm_entry_builder().BuildEntry(
-      ukm_source_id, PreloadingType::kPrerender,
-      PreloadingEligibility::kEligible, PreloadingHoldbackStatus::kAllowed,
-      PreloadingTriggeringOutcome::kSuccess,
-      PreloadingFailureReason::kUnspecified,
-      /*accurate=*/true,
-      /*ready_time=*/kMockElapsedTime,
-      blink::mojom::SpeculationEagerness::kEager)});
-
-  // The navigation occurred in a new WebContents, so the original WebContents
-  // should still be showing the initial trigger page.
-  EXPECT_EQ(web_contents()->GetLastCommittedURL(), kInitialUrl);
-}
-
-// Tests that window.open() annotated with "_blank" and "noopener,popup" can
-// activate a prerender whose target_hint is "_blank".
-IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, ActivateOnWindowOpen_PopUp) {
+// `window_features` is passed to the 3rd argument of window.open().
+void PrerenderBrowserTest::TestActivateOnWindowOpen(
+    std::string_view window_features) {
   const GURL initial_url = GetUrl("/simple_links.html");
   const GURL prerendering_url = GetUrl("/title2.html");
 
-  // Navigate to an initial page which has a link to `kPrerenderingUrl`.
+  // Navigate to an initial page which has a link to `prerendering_url`.
   ASSERT_TRUE(NavigateToURL(shell(), initial_url));
 
-  // Start prerendering `kPrerenderingUrl`.
+  // Start prerendering `prerendering_url`.
   FrameTreeNodeId host_id = prerender_helper()->AddPrerender(
       prerendering_url, /*eagerness=*/std::nullopt, "_blank");
   auto* prerender_web_contents = WebContents::FromFrameTreeNodeId(host_id);
   ASSERT_NE(prerender_web_contents, web_contents_impl());
   ExpectWebContentsIsForNewTabPrerendering(*prerender_web_contents);
 
-  // Open a new window with "_blank" and "noopener,popup". This should activate
+  // Open a new window with "_blank" and `window_features`. This should activate
   // the prerendered page.
   TestNavigationObserver activation_observer(prerendering_url);
   activation_observer.WatchExistingWebContents();
   test::PrerenderHostObserver prerender_observer(*prerender_web_contents,
                                                  host_id);
-  const std::string kWindowOpenScript = R"(
-      window.open("title2.html", "_blank", "noopener,popup");
-  )";
-  EXPECT_TRUE(ExecJs(web_contents(), kWindowOpenScript));
+  const std::string script = base::StringPrintf(R"(
+      window.open("title2.html", "_blank", "%s");
+  )",
+                                                window_features);
+  EXPECT_TRUE(ExecJs(web_contents(), script));
   activation_observer.WaitForNavigationFinished();
   EXPECT_EQ(prerender_web_contents->GetLastCommittedURL(), prerendering_url);
   EXPECT_EQ(activation_observer.last_navigation_url(), prerendering_url);
@@ -3219,6 +3172,18 @@
   EXPECT_EQ(web_contents()->GetLastCommittedURL(), initial_url);
 }
 
+// Tests that window.open() annotated with "_blank" and "noopener" can activate
+// a prerender whose target_hint is "_blank".
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, ActivateOnWindowOpen_NewTab) {
+  TestActivateOnWindowOpen("noopener");
+}
+
+// Tests that window.open() annotated with "_blank" and "noopener,popup" can
+// activate a prerender whose target_hint is "_blank".
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, ActivateOnWindowOpen_PopUp) {
+  TestActivateOnWindowOpen("noopener,popup");
+}
+
 // TODO(crbug.com/40234240): Add more test cases for prerender-in-new-tab:
 // - Multiple prerendering requests with the same URL but different target hint.
 // - Navigation in a new tab to the prerendering URL multiple times. Only the
diff --git a/content/browser/renderer_host/clipboard_host_impl.cc b/content/browser/renderer_host/clipboard_host_impl.cc
index b5132979..47c36e0 100644
--- a/content/browser/renderer_host/clipboard_host_impl.cc
+++ b/content/browser/renderer_host/clipboard_host_impl.cc
@@ -53,9 +53,9 @@
 #include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
 #include "url/gurl.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "content/public/common/url_constants.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 namespace content {
 
@@ -223,14 +223,14 @@
       clipboard->IsFormatAvailable(ui::ClipboardFormatType::FilenamesType(),
                                    clipboard_buffer, data_endpoint.get());
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   // ChromeOS FilesApp must include the custom 'fs/sources', etc data for
   // paste that it put on the clipboard during copy (b/271078230).
   if (render_frame_host().GetMainFrame()->GetLastCommittedURL().SchemeIs(
           kChromeUIScheme)) {
     file_type_only = false;
   }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
   if (file_type_only) {
     types = {base::UTF8ToUTF16(ui::kMimeTypeURIList)};
diff --git a/content/browser/renderer_host/data_transfer_util.cc b/content/browser/renderer_host/data_transfer_util.cc
index 5198a51..27850b5a 100644
--- a/content/browser/renderer_host/data_transfer_util.cc
+++ b/content/browser/renderer_host/data_transfer_util.cc
@@ -13,7 +13,6 @@
 #include "base/files/file_path.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/uuid.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/file_system_access/file_system_access_manager_impl.h"
 #include "content/public/browser/browser_thread.h"
@@ -40,7 +39,7 @@
 // updates `entry_path` to the path that should be used by the File System
 // Access implementation.
 content::PathType MaybeRemapPath(base::FilePath* entry_path) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   base::FilePath virtual_path;
   auto* external_mount_points =
       storage::ExternalMountPoints::GetSystemInstance();
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc
index a5528d57..ad54a1a 100644
--- a/content/browser/renderer_host/delegated_frame_host.cc
+++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -17,7 +17,6 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/base/switches.h"
 #include "components/viz/common/features.h"
 #include "components/viz/common/frame_sinks/copy_output_request.h"
@@ -465,7 +464,7 @@
 
 // TODO(crbug.com/1227661): Revert https://crrev.com/c/3222541 to re-enable this
 // CHECK on CrOS.
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
+#if !BUILDFLAG(IS_CHROMEOS)
   CHECK_NE(frame_eviction_state_, FrameEvictionState::kNotStarted);
 #endif
   SetFrameEvictionStateAndNotifyObservers(FrameEvictionState::kNotStarted);
@@ -485,7 +484,7 @@
     client_->DelegatedFrameHostGetLayer()->Add(stale_content_layer_.get());
 
 // TODO(crbug.com/40812011): This DCHECK occasionally gets hit on Chrome OS.
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
+#if !BUILDFLAG(IS_CHROMEOS)
   CHECK(!stale_content_layer_->has_external_content());
 #endif
   stale_content_layer_->SetVisible(true);
diff --git a/content/browser/renderer_host/input/fling_browsertest.cc b/content/browser/renderer_host/input/fling_browsertest.cc
index 29ce2316..4234dff 100644
--- a/content/browser/renderer_host/input/fling_browsertest.cc
+++ b/content/browser/renderer_host/input/fling_browsertest.cc
@@ -9,7 +9,6 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/input/render_widget_host_input_event_router.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/input/synthetic_smooth_scroll_gesture.h"
@@ -425,7 +424,7 @@
 }
 
 // Touchpad fling only happens on ChromeOS.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 IN_PROC_BROWSER_TEST_F(BrowserSideFlingBrowserTest,
                        TouchpadInertialGSUsBubbleFromOOPIF) {
   LoadPageWithOOPIF();
@@ -443,7 +442,7 @@
   SimulateTouchpadFling(child_view_->host(), GetWidgetHost(), fling_velocity);
   WaitForFrameScroll(GetRootNode(), 15, true /* upward */);
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 // TODO(crbug.com/40230295): flaky.
 IN_PROC_BROWSER_TEST_F(BrowserSideFlingBrowserTest,
diff --git a/content/browser/renderer_host/input/main_thread_event_queue_browsertest.cc b/content/browser/renderer_host/input/main_thread_event_queue_browsertest.cc
index c37c578f..830e374b 100644
--- a/content/browser/renderer_host/input/main_thread_event_queue_browsertest.cc
+++ b/content/browser/renderer_host/input/main_thread_event_queue_browsertest.cc
@@ -12,7 +12,6 @@
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/input/render_widget_host_input_event_router.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc b/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
index 7fe5f9b..732833b4 100644
--- a/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
+++ b/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
@@ -16,7 +16,6 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_timeouts.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
 #include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
 #include "content/browser/renderer_host/render_widget_host_view_event_handler.h"
@@ -1290,7 +1289,7 @@
 }
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 // Tests that touch selection dragging records a histogram entry.
 IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
                        SelectionDraggingMetrics) {
@@ -1335,7 +1334,7 @@
   histogram_tester.ExpectUniqueSample(
       ui::kTouchSelectionSessionTouchDownCountHistogramName, 3, 1);
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 // Tests that the quick menu is hidden whenever a touch point is active.
 // Flaky: https://crbug.com/803576
diff --git a/content/browser/renderer_host/input/wheel_scroll_latching_browsertest.cc b/content/browser/renderer_host/input/wheel_scroll_latching_browsertest.cc
index a1411b4..b8f9329 100644
--- a/content/browser/renderer_host/input/wheel_scroll_latching_browsertest.cc
+++ b/content/browser/renderer_host/input/wheel_scroll_latching_browsertest.cc
@@ -5,7 +5,6 @@
 #include "base/run_loop.h"
 #include "base/task/single_thread_task_runner.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/input/render_widget_host_input_event_router.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
@@ -254,7 +253,7 @@
              EvalJs(shell(), "scrollableDiv.getBoundingClientRect().bottom")
                  .ExtractDouble()) /
             2;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   bool precise = true;
 #else
   bool precise = false;
diff --git a/content/browser/renderer_host/media/audio_input_device_manager.cc b/content/browser/renderer_host/media/audio_input_device_manager.cc
index 5a52e52f..eb3ec3a3 100644
--- a/content/browser/renderer_host/media/audio_input_device_manager.cc
+++ b/content/browser/renderer_host/media/audio_input_device_manager.cc
@@ -14,7 +14,6 @@
 #include "base/observer_list.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/content/browser/renderer_host/media/audio_input_device_manager.h b/content/browser/renderer_host/media/audio_input_device_manager.h
index 8f3203b..608f26d7 100644
--- a/content/browser/renderer_host/media/audio_input_device_manager.h
+++ b/content/browser/renderer_host/media/audio_input_device_manager.h
@@ -22,7 +22,6 @@
 #include "base/threading/thread.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/media/media_stream_provider.h"
 #include "content/common/content_export.h"
 #include "third_party/blink/public/common/mediastream/media_stream_request.h"
diff --git a/content/browser/renderer_host/media/fake_video_capture_device_launcher.cc b/content/browser/renderer_host/media/fake_video_capture_device_launcher.cc
index 9e6d0b8..cafecb1 100644
--- a/content/browser/renderer_host/media/fake_video_capture_device_launcher.cc
+++ b/content/browser/renderer_host/media/fake_video_capture_device_launcher.cc
@@ -11,7 +11,6 @@
 #include "base/functional/callback_forward.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/token.h"
-#include "build/chromeos_buildflags.h"
 #include "content/public/browser/browser_context.h"
 #include "media/capture/mojom/video_capture_types.mojom.h"
 #include "media/capture/video/video_capture_buffer_pool_impl.h"
@@ -19,9 +18,9 @@
 #include "media/capture/video/video_capture_device_client.h"
 #include "media/capture/video/video_frame_receiver_on_task_runner.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "media/capture/video/chromeos/video_capture_jpeg_decoder.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 namespace {
 
@@ -105,7 +104,7 @@
       new media::VideoCaptureBufferPoolImpl(
           media::VideoCaptureBufferType::kSharedMemory));
 #endif  // BUILDFLAG(IS_WIN)
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   auto device_client = std::make_unique<media::VideoCaptureDeviceClient>(
       std::make_unique<media::VideoFrameReceiverOnTaskRunner>(
           receiver, base::SingleThreadTaskRunner::GetCurrentDefault()),
@@ -117,7 +116,7 @@
       std::make_unique<media::VideoFrameReceiverOnTaskRunner>(
           receiver, base::SingleThreadTaskRunner::GetCurrentDefault()),
       std::move(buffer_pool), std::nullopt);
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
   device->AllocateAndStart(params, std::move(device_client));
   auto launched_device =
       std::make_unique<FakeLaunchedVideoCaptureDevice>(std::move(device));
diff --git a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
index e7db48a..68f0d2c 100644
--- a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
+++ b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
@@ -17,7 +17,6 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/media/capture/native_screen_capture_picker.h"
 #include "content/browser/renderer_host/media/in_process_launched_video_capture_device.h"
 #include "content/browser/renderer_host/media/video_capture_controller.h"
@@ -54,19 +53,19 @@
 #endif
 #endif  // BUILDFLAG(ENABLE_SCREEN_CAPTURE)
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "content/browser/gpu/chromeos/video_capture_dependencies.h"
 #include "media/capture/video/chromeos/scoped_video_capture_jpeg_decoder.h"
 #include "media/capture/video/chromeos/video_capture_jpeg_decoder_impl.h"
 #elif BUILDFLAG(IS_WIN)
 #include "media/capture/video/win/video_capture_device_factory_win.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 namespace content {
 
 namespace {
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 std::unique_ptr<media::VideoCaptureJpegDecoder> CreateGpuJpegDecoder(
     media::VideoCaptureJpegDecoder::DecodeDoneCB decode_done_cb,
     base::RepeatingCallback<void(const std::string&)> send_log_message_cb) {
@@ -79,7 +78,7 @@
           std::move(send_log_message_cb)),
       io_task_runner);
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 #if BUILDFLAG(ENABLE_SCREEN_CAPTURE)
 
@@ -401,7 +400,7 @@
           requested_buffer_type, buffer_pool_max_buffer_count);
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   return std::make_unique<media::VideoCaptureDeviceClient>(
       std::move(receiver), std::move(buffer_pool),
       base::BindRepeating(
@@ -413,7 +412,7 @@
 #else
   return std::make_unique<media::VideoCaptureDeviceClient>(
       std::move(receiver), std::move(buffer_pool), std::nullopt);
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 }
 
 void InProcessVideoCaptureDeviceLauncher::OnDeviceStarted(
diff --git a/content/browser/renderer_host/media/media_devices_manager.cc b/content/browser/renderer_host/media/media_devices_manager.cc
index af68814..bac62e8 100644
--- a/content/browser/renderer_host/media/media_devices_manager.cc
+++ b/content/browser/renderer_host/media/media_devices_manager.cc
@@ -25,7 +25,6 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/threading/thread_checker.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/media/media_devices_permission_checker.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/browser/renderer_host/media/video_capture_manager.h"
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
index 4388970..e84403ef 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
@@ -29,7 +29,6 @@
 #include "base/test/test_future.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/media/media_devices_util.h"
 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
@@ -61,7 +60,7 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "chromeos/ash/components/audio/cras_audio_handler.h"
 #include "chromeos/ash/components/dbus/audio/cras_audio_client.h"
 #endif
@@ -338,7 +337,7 @@
         base::BindRepeating(&MediaStreamDispatcherHostTest::MockOnBadMessage,
                             base::Unretained(this)));
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     ash::CrasAudioClient::InitializeFake();
     ash::CrasAudioHandler::InitializeForTesting();
 #endif
@@ -346,7 +345,7 @@
 
   ~MediaStreamDispatcherHostTest() override {
     audio_manager_->Shutdown();
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     ash::CrasAudioHandler::Shutdown();
     ash::CrasAudioClient::Shutdown();
 #endif
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 46c8f54f..55ae2600 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -30,7 +30,6 @@
 #include "base/threading/thread.h"
 #include "base/uuid.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/gpu/gpu_process_host.h"
 #include "content/browser/media/capture/desktop_capture_device_uma_types.h"
@@ -91,7 +90,7 @@
 #include "base/win/scoped_com_initializer.h"
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "chromeos/ash/components/audio/cras_audio_handler.h"
 #include "content/browser/gpu/chromeos/video_capture_dependencies.h"
 #include "content/browser/gpu/gpu_memory_buffer_manager_singleton.h"
@@ -138,7 +137,7 @@
 void EnableHotwordEffect(const StreamControls& controls, int* effects) {
   DCHECK(effects);
   if (controls.hotword_enabled) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     // Only enable if a hotword device exists.
     if (ash::CrasAudioHandler::Get()->HasHotwordDevice()) {
       *effects |= media::AudioParameters::HOTWORD;
@@ -1603,7 +1602,7 @@
     device_task_runner = video_capture_thread_->task_runner();
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     if (media::ShouldUseCrosCameraService()) {
       jpeg_accelerator_provider_ =
           std::make_unique<media::JpegAcceleratorProviderImpl>(
diff --git a/content/browser/renderer_host/media/media_stream_manager.h b/content/browser/renderer_host/media/media_stream_manager.h
index 2dc655f..3eeed15 100644
--- a/content/browser/renderer_host/media/media_stream_manager.h
+++ b/content/browser/renderer_host/media/media_stream_manager.h
@@ -55,7 +55,7 @@
 
 namespace media {
 class AudioSystem;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 class JpegAcceleratorProviderImpl;
 class SystemEventMonitorImpl;
 #endif
@@ -871,7 +871,7 @@
 
   GenerateStreamTestCallback generate_stream_test_callback_;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   std::unique_ptr<media::JpegAcceleratorProviderImpl>
       jpeg_accelerator_provider_;
 
diff --git a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc
index 1146ca6..89323bfa 100644
--- a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc
+++ b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/functional/callback_helpers.h"
 #include "base/run_loop.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/media/forwarding_audio_stream_factory.h"
 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
diff --git a/content/browser/renderer_host/media/service_video_capture_provider.cc b/content/browser/renderer_host/media/service_video_capture_provider.cc
index a64e66b..45f9585 100644
--- a/content/browser/renderer_host/media/service_video_capture_provider.cc
+++ b/content/browser/renderer_host/media/service_video_capture_provider.cc
@@ -11,7 +11,6 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/trace_event/common/trace_event_common.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/child_process_host_impl.h"
 #include "content/browser/renderer_host/media/service_video_capture_device_launcher.h"
 #include "content/browser/renderer_host/media/virtual_video_capture_devices_changed_observer.h"
@@ -28,22 +27,22 @@
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "services/video_capture/public/mojom/video_capture_service.mojom.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "content/public/browser/chromeos/delegate_to_browser_gpu_service_accelerator_factory.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 namespace {
 
 using GetSourceInfosResult =
     video_capture::mojom::VideoSourceProvider::GetSourceInfosResult;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 std::unique_ptr<video_capture::mojom::AcceleratorFactory>
 CreateAcceleratorFactory() {
   return std::make_unique<
       content::DelegateToBrowserGpuServiceAcceleratorFactory>();
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 // Do not reorder, used for UMA Media.VideoCapture.GetDeviceInfosResult
 enum class GetDeviceInfosResult {
@@ -119,7 +118,7 @@
   const base::RepeatingClosure stop_callback_;
 };
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 ServiceVideoCaptureProvider::ServiceVideoCaptureProvider(
     base::RepeatingCallback<void(const std::string&)> emit_log_message_cb)
     : ServiceVideoCaptureProvider(base::NullCallback(),
@@ -131,12 +130,12 @@
     : create_accelerator_factory_cb_(std::move(create_accelerator_factory_cb)),
       emit_log_message_cb_(std::move(emit_log_message_cb)),
       launcher_has_connected_to_source_provider_(false) {
-#else   // BUILDFLAG(IS_CHROMEOS_ASH)
+#else   // BUILDFLAG(IS_CHROMEOS)
 ServiceVideoCaptureProvider::ServiceVideoCaptureProvider(
     base::RepeatingCallback<void(const std::string&)> emit_log_message_cb)
     : emit_log_message_cb_(std::move(emit_log_message_cb)),
       launcher_has_connected_to_source_provider_(false) {
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
   if (features::IsVideoCaptureServiceEnabledForOutOfProcess()) {
     service_process_observer_.emplace(
         GetUIThreadTaskRunner({}),
@@ -251,7 +250,7 @@
   time_of_last_connect_ = base::TimeTicks::Now();
 
   auto ui_task_runner = GetUIThreadTaskRunner({});
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   mojo::PendingRemote<video_capture::mojom::AcceleratorFactory>
       accelerator_factory;
   if (!create_accelerator_factory_cb_)
@@ -262,7 +261,7 @@
       accelerator_factory.InitWithNewPipeAndPassReceiver());
   GetVideoCaptureService().InjectGpuDependencies(
       std::move(accelerator_factory));
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 #if BUILDFLAG(IS_WIN)
   // Pass active gpu info.
diff --git a/content/browser/renderer_host/media/service_video_capture_provider.h b/content/browser/renderer_host/media/service_video_capture_provider.h
index 4e29dd3..ef6e898 100644
--- a/content/browser/renderer_host/media/service_video_capture_provider.h
+++ b/content/browser/renderer_host/media/service_video_capture_provider.h
@@ -11,7 +11,6 @@
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/media/ref_counted_video_source_provider.h"
 #include "content/browser/renderer_host/media/video_capture_provider.h"
 #include "content/common/content_export.h"
@@ -36,7 +35,7 @@
   explicit ServiceVideoCaptureProvider(
       base::RepeatingCallback<void(const std::string&)> emit_log_message_cb);
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   using CreateAcceleratorFactoryCallback = base::RepeatingCallback<
       std::unique_ptr<video_capture::mojom::AcceleratorFactory>()>;
   // Lets clients provide a custom factory method for creating instances of
@@ -44,7 +43,7 @@
   ServiceVideoCaptureProvider(
       CreateAcceleratorFactoryCallback create_accelerator_factory_cb,
       base::RepeatingCallback<void(const std::string&)> emit_log_message_cb);
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
   ~ServiceVideoCaptureProvider() override;
 
@@ -88,9 +87,9 @@
   void OnLostConnectionToSourceProvider();
   void OnServiceConnectionClosed(ReasonForDisconnect reason);
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   CreateAcceleratorFactoryCallback create_accelerator_factory_cb_;
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
   base::RepeatingCallback<void(const std::string&)> emit_log_message_cb_;
 
   base::WeakPtr<RefCountedVideoSourceProvider> weak_service_connection_;
diff --git a/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc b/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc
index 9b00547..ac5d30f 100644
--- a/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc
+++ b/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc
@@ -13,7 +13,6 @@
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/thread.h"
-#include "build/chromeos_buildflags.h"
 #include "content/public/browser/video_capture_device_launcher.h"
 #include "content/public/browser/video_capture_service.h"
 #include "content/public/common/content_features.h"
@@ -81,7 +80,7 @@
     // macOS.
     scoped_feature_list_.InitAndDisableFeature(
         features::kRetryGetVideoCaptureDeviceInfos);
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     provider_ = std::make_unique<ServiceVideoCaptureProvider>(
         base::BindRepeating([]() {
           return std::unique_ptr<video_capture::mojom::AcceleratorFactory>();
@@ -90,7 +89,7 @@
 #else
     provider_ =
         std::make_unique<ServiceVideoCaptureProvider>(kIgnoreLogMessageCB);
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
     ON_CALL(mock_video_capture_service_, DoConnectToVideoSourceProvider(_))
         .WillByDefault(Invoke(
diff --git a/content/browser/renderer_host/media/video_capture_browsertest.cc b/content/browser/renderer_host/media/video_capture_browsertest.cc
index 8583442..9d7130fd 100644
--- a/content/browser/renderer_host/media/video_capture_browsertest.cc
+++ b/content/browser/renderer_host/media/video_capture_browsertest.cc
@@ -12,7 +12,6 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/browser/renderer_host/media/video_capture_controller.h"
@@ -298,7 +297,7 @@
                      std::move(quit_run_loop_on_current_thread_cb), true);
 
   bool must_wait_for_gpu_decode_to_start = false;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   if (params_.exercise_accelerated_jpeg_decoding) {
     // Since the GPU jpeg decoder is created asynchronously while decoding
     // in software is ongoing, we have to keep pushing frames until a message
@@ -311,7 +310,7 @@
           must_wait_for_gpu_decode_to_start = false;
         }));
   }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
   EXPECT_CALL(mock_controller_event_handler_, DoOnNewBuffer(_, _, _))
       .Times(AtLeast(1));
   EXPECT_CALL(mock_controller_event_handler_, OnBufferReady(_, _))
diff --git a/content/browser/renderer_host/media/video_capture_controller_unittest.cc b/content/browser/renderer_host/media/video_capture_controller_unittest.cc
index 857840b..c6887b0 100644
--- a/content/browser/renderer_host/media/video_capture_controller_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_controller_unittest.cc
@@ -21,7 +21,6 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/bind.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/media/media_stream_provider.h"
 #include "content/browser/renderer_host/media/mock_video_capture_provider.h"
 #include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
@@ -40,9 +39,9 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "media/capture/video/chromeos/video_capture_jpeg_decoder_impl.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 using ::testing::_;
 using ::testing::AnyNumber;
@@ -190,7 +189,7 @@
   void InitializeNewDeviceClientAndBufferPoolInstances() {
     buffer_pool_ = new media::VideoCaptureBufferPoolImpl(
         media::VideoCaptureBufferType::kSharedMemory, kPoolSize);
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     device_client_ = std::make_unique<media::VideoCaptureDeviceClient>(
         std::make_unique<media::VideoFrameReceiverOnTaskRunner>(
             controller_->GetWeakPtrForIOThread(), GetIOThreadTaskRunner({})),
@@ -200,7 +199,7 @@
         std::make_unique<media::VideoFrameReceiverOnTaskRunner>(
             controller_->GetWeakPtrForIOThread(), GetIOThreadTaskRunner({})),
         buffer_pool_, std::nullopt);
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
   }
 
   void SendStubFrameToDeviceClient(const media::VideoCaptureFormat format,
diff --git a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
index 5b81be69..da335c4 100644
--- a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
@@ -27,7 +27,6 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/process_lock.h"
 #include "content/browser/renderer_host/frame_navigation_entry.h"
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index d42bf5c..cc3a158 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -41,7 +41,6 @@
 #include "base/types/pass_key.h"
 #include "build/build_config.h"
 #include "build/buildflag.h"
-#include "build/chromeos_buildflags.h"
 #include "components/viz/host/host_frame_sink_manager.h"
 #include "content/browser/agent_cluster_key.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
diff --git a/content/browser/renderer_host/page_lifecycle_state_manager_browsertest.cc b/content/browser/renderer_host/page_lifecycle_state_manager_browsertest.cc
index 6cbc547..ec820ec2 100644
--- a/content/browser/renderer_host/page_lifecycle_state_manager_browsertest.cc
+++ b/content/browser/renderer_host/page_lifecycle_state_manager_browsertest.cc
@@ -6,7 +6,6 @@
 #include "base/location.h"
 #include "base/strings/string_number_conversions.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/frame_tree_node.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
diff --git a/content/browser/renderer_host/panel_rotation_browsertest.cc b/content/browser/renderer_host/panel_rotation_browsertest.cc
index 227d527..2435243 100644
--- a/content/browser/renderer_host/panel_rotation_browsertest.cc
+++ b/content/browser/renderer_host/panel_rotation_browsertest.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "build/chromeos_buildflags.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
@@ -13,7 +12,7 @@
 namespace content {
 
 // TODO(crbug.com/41478398): Add test coverage across all platforms.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 class PanelRotationBrowserTest : public ContentBrowserTest {
  protected:
   void SetPanelRotation(display::Display::Rotation rotation) {
@@ -40,6 +39,6 @@
   SetPanelRotation(display::Display::ROTATE_270);
   EXPECT_EQ(ReadScreenOrientationAngle(), 90);
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 }  // namespace content
diff --git a/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc b/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc
index 97f6e2e..301882846 100644
--- a/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc
+++ b/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc
@@ -6,7 +6,6 @@
 
 #include <stddef.h>
 #include <utility>
-#include "build/chromeos_buildflags.h"
 
 #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
 #include "content/browser/renderer_host/pepper/pepper_browser_font_singleton_host.h"
diff --git a/content/browser/renderer_host/pepper/pepper_socket_utils.cc b/content/browser/renderer_host/pepper/pepper_socket_utils.cc
index 3abbecd9..70a92ad 100644
--- a/content/browser/renderer_host/pepper/pepper_socket_utils.cc
+++ b/content/browser/renderer_host/pepper/pepper_socket_utils.cc
@@ -12,7 +12,6 @@
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_frame_host.h"
diff --git a/content/browser/renderer_host/pepper/pepper_socket_utils.h b/content/browser/renderer_host/pepper/pepper_socket_utils.h
index 3f9a2d7..7f3f8336 100644
--- a/content/browser/renderer_host/pepper/pepper_socket_utils.h
+++ b/content/browser/renderer_host/pepper/pepper_socket_utils.h
@@ -6,7 +6,6 @@
 #define CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_SOCKET_UTILS_H_
 
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/public/common/socket_permission_request.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "ppapi/c/pp_stdint.h"
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
index 7ee1f27..b288305 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
+++ b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
@@ -12,7 +12,6 @@
 #include "base/logging.h"
 #include "base/task/sequenced_task_runner.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
 #include "content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h"
 #include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h
index 6818c797..b71e25c 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h
+++ b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h
@@ -16,7 +16,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/task/sequenced_task_runner.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
index 9ac6319..984dfaf 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
+++ b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
@@ -17,7 +17,6 @@
 #include "base/strings/cstring_view.h"
 #include "base/task/sequenced_task_runner.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h"
 #include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
 #include "content/public/browser/browser_context.h"
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
index dd800689..ac731cb87 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
+++ b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
@@ -18,7 +18,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/task/sequenced_task_runner.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
diff --git a/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
index f5a4908..eba4ea1 100644
--- a/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
+++ b/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
@@ -15,7 +15,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/task/sequenced_task_runner.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
 #include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
 #include "content/public/browser/browser_context.h"
diff --git a/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h b/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h
index 206f89d..ad91ddb 100644
--- a/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h
+++ b/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h
@@ -18,7 +18,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/task/sequenced_task_runner.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/common/content_export.h"
 #include "content/public/common/process_type.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
diff --git a/content/browser/renderer_host/private_network_access_util.cc b/content/browser/renderer_host/private_network_access_util.cc
index 888d8be..8dc4130 100644
--- a/content/browser/renderer_host/private_network_access_util.cc
+++ b/content/browser/renderer_host/private_network_access_util.cc
@@ -6,7 +6,6 @@
 
 #include "base/command_line.h"
 #include "base/feature_list.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/policy_container_host.h"
 #include "content/common/features.h"
 #include "content/public/browser/content_browser_client.h"
@@ -203,11 +202,11 @@
   // This only handles schemes that are known to the content/ layer.
   // List here: content/public/common/url_constants.cc.
   const char* special_content_schemes[] = {
-    kChromeDevToolsScheme,
-    kChromeUIScheme,
-    kChromeUIUntrustedScheme,
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-    kExternalFileScheme,
+      kChromeDevToolsScheme,
+      kChromeUIScheme,
+      kChromeUIUntrustedScheme,
+#if BUILDFLAG(IS_CHROMEOS)
+      kExternalFileScheme,
 #endif
   };
 
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 97571cc..ad80b79 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -13561,17 +13561,6 @@
     return;
   }
 
-  // Both flags are enforced in benign renderers by the
-  // RuntimeEnabled=PrivateStateTokens IDL attribute (the base::Feature's value
-  // is tied to the RuntimeEnabledFeature's).
-  if (!base::FeatureList::IsEnabled(network::features::kPrivateStateTokens) &&
-      !base::FeatureList::IsEnabled(network::features::kFledgePst)) {
-    mojo::ReportBadMessage(
-        "Attempted to get a TrustTokenQueryAnswerer with Private State Tokens "
-        "disabled.");
-    return;
-  }
-
   // TODO(crbug.com/40729410): Document.hasPrivateToken is restricted to
   // secure contexts, so we could additionally add a check verifying that the
   // bind request "is coming from a secure context"---but there's currently no
diff --git a/content/browser/renderer_host/render_frame_host_manager_browsertest.cc b/content/browser/renderer_host/render_frame_host_manager_browsertest.cc
index 98c72d3..f68c5623 100644
--- a/content/browser/renderer_host/render_frame_host_manager_browsertest.cc
+++ b/content/browser/renderer_host/render_frame_host_manager_browsertest.cc
@@ -32,7 +32,6 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/process_lock.h"
 #include "content/browser/renderer_host/frame_tree_node.h"
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index c8c0c2c..bc2e3f9 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -69,7 +69,6 @@
 #include "base/trace_event/typed_macros.h"
 #include "base/tracing/protos/chrome_track_event.pbzero.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/base/switches.h"
 #include "components/metrics/histogram_controller.h"
 #include "components/metrics/single_sample_metrics.h"
@@ -2138,7 +2137,7 @@
       std::move(receiver));
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 void RenderProcessHostImpl::ReinitializeLogging(
     uint32_t logging_dest,
     base::ScopedFD log_file_descriptor) {
@@ -2148,7 +2147,7 @@
       mojo::PlatformHandle(std::move(log_file_descriptor));
   child_process_->ReinitializeLogging(std::move(logging_settings));
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 void RenderProcessHostImpl::SetBatterySaverMode(
     bool battery_saver_mode_enabled) {
@@ -3283,7 +3282,7 @@
       switches::kDisableInProcessStackTraces,
       sandbox::policy::switches::kDisableSeccompFilterSandbox,
       sandbox::policy::switches::kNoSandbox,
-#if BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS)
       switches::kDisableDevShmUsage,
 #endif
 #if BUILDFLAG(IS_MAC)
@@ -3489,7 +3488,7 @@
   if (browser_cmd.HasSwitch(switches::kDisableGpuCompositing)) {
     renderer_cmd->AppendSwitch(switches::kDisableGpuCompositing);
   }
-#elif !BUILDFLAG(IS_CHROMEOS_ASH)
+#elif !BUILDFLAG(IS_CHROMEOS)
   // If gpu compositing is not being used, tell the renderer at startup. This
   // is inherently racey, as it may change while the renderer is being
   // launched, but the renderer will hear about the correct state eventually.
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index f938e8d6..e818b03 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -29,7 +29,6 @@
 #include "base/threading/sequence_bound.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/metrics/histogram_child_process.h"
 #include "components/services/storage/public/cpp/buckets/bucket_id.h"
 #include "components/services/storage/public/cpp/buckets/bucket_info.h"
@@ -354,7 +353,7 @@
 #if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX)
   void DumpProfilingData(base::OnceClosure callback) override;
 #endif
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   void ReinitializeLogging(uint32_t logging_dest,
                            base::ScopedFD log_file_descriptor) override;
 #endif
diff --git a/content/browser/renderer_host/render_process_host_unittest.cc b/content/browser/renderer_host/render_process_host_unittest.cc
index 72d5b77..61fcca0 100644
--- a/content/browser/renderer_host/render_process_host_unittest.cc
+++ b/content/browser/renderer_host/render_process_host_unittest.cc
@@ -13,7 +13,6 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/renderer_host/spare_render_process_host_manager_impl.h"
@@ -77,7 +76,7 @@
             RenderProcessHostImpl::GetExistingProcessHost(site_instance.get()));
 }
 
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
 TEST_F(RenderProcessHostUnitTest, RendererProcessLimit) {
   // This test shouldn't run with --site-per-process mode, which prohibits
   // the renderer process reuse this test explicitly exercises.
@@ -105,7 +104,7 @@
 }
 #endif
 
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
 TEST_F(RenderProcessHostUnitTest, NoRendererProcessLimitOnAndroidOrChromeOS) {
   // Add a few dummy process hosts.
   static constexpr size_t kMaxRendererProcessCountForTesting = 82;
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 2889577..1dc9195 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -954,11 +954,7 @@
     // <webview>, and PDF. These may have a compositor surface as well,
     // in which case we need to explore not the outer node only, but the inner
     // ones as well.
-    FrameTree::NodeRange node_range =
-        base::FeatureList::IsEnabled(
-            features::kInnerFrameCompositorSurfaceEviction)
-            ? tree.NodesIncludingInnerTreeNodes()
-            : tree.SubtreeNodes(root);
+    FrameTree::NodeRange node_range = tree.NodesIncludingInnerTreeNodes();
     CollectSurfaceIdsForEvictionForFrameTreeNodeRange(node_range, ids);
   } else if (is_in_back_forward_cache_) {
     // `FrameTree::SubtreeAndInnerTreeNodes` starts with the children of `rfh`
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 4ab0948..de62d87 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -22,7 +22,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/layers/layer.h"
 #include "cc/trees/layer_tree_settings.h"
 #include "components/input/cursor_manager.h"
@@ -129,7 +128,7 @@
 #include "ui/linux/linux_ui.h"
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "ui/wm/core/ime_util_chromeos.h"
 #endif
 
@@ -736,10 +735,10 @@
   if (!window || window->GetRootWindow() != root_window) {
     return true;
   }
-#elif !BUILDFLAG(IS_CHROMEOS_ASH)
+#elif !BUILDFLAG(IS_CHROMEOS)
   if (!screen->IsWindowUnderCursor(root_window))
     return true;
-#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // !BUILDFLAG(IS_CHROMEOS)
   return false;
 }
 
@@ -1817,7 +1816,7 @@
   }
 
   aura::Window* top_level_window = window_->GetToplevelWindow();
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   wm::EnsureWindowNotInRect(top_level_window, keyboard_occluded_bounds_);
 #endif
 
@@ -2029,7 +2028,7 @@
 }
 #endif
 
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
 ui::TextInputClient::EditingContext
 RenderWidgetHostViewAura::GetTextEditingContext() {
   ui::TextInputClient::EditingContext editing_context;
@@ -2976,9 +2975,9 @@
   ui::InputMethod* input_method = GetInputMethod();
   if (input_method) {
     input_method->DetachTextInputClient(this);
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     wm::RestoreWindowBoundsOnClientFocusLost(window_->GetToplevelWindow());
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
   }
 
 #if BUILDFLAG(IS_WIN)
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 2042f979..75519fa 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -22,7 +22,6 @@
 #include "base/scoped_observation.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/layers/deadline_policy.h"
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
@@ -312,7 +311,7 @@
       bool is_composition_committed) override;
 #endif
 
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
   // Returns the editing context of the active web content.
   // This is currently used by TSF and ChromeOS to fetch the URL of the active
   // web content.
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_aura_browsertest.cc
index 02296de..1d741f0 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_browsertest.cc
@@ -10,7 +10,6 @@
 #include "base/test/run_until.h"
 #include "base/test/test_timeouts.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/devtools/protocol/devtools_protocol_test_support.h"
 #include "content/browser/renderer_host/delegated_frame_host.h"
 #include "content/browser/renderer_host/frame_tree_node.h"
@@ -44,7 +43,7 @@
 namespace content {
 namespace {
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 const char kMinimalPageDataURL[] =
     "data:text/html,<html><head></head><body>Hello, world</body></html>";
 
@@ -56,7 +55,7 @@
       FROM_HERE, run_loop.QuitClosure(), base::Milliseconds(250));
   run_loop.Run();
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 class FakeWebContentsDelegate : public WebContentsDelegate {
  public:
@@ -123,7 +122,7 @@
 }
 #endif  // BUILDFLAG(IS_WIN)
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewAuraBrowserTest,
                        // TODO(crbug.com/40874148): Re-enable this test
                        // TODO(crbug.com/40873813): Re-enable this test
@@ -243,7 +242,7 @@
   EXPECT_FALSE(
       GetDelegatedFrameHost()->stale_content_layer_->has_external_content());
 }
-#endif  // #if BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // #if BUILDFLAG(IS_CHROMEOS)
 
 IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewAuraBrowserTest,
                        SetKeyboardFocusOnTapAfterDismissingPopup) {
@@ -689,7 +688,7 @@
   EXPECT_FALSE(FrameIsFocused(iframe));
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 // Verifies that getting active input control accounts for iframe positioning.
 // Flaky: crbug.com/1293700
 IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewAuraActiveWidgetTest,
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 832dc66..bdb00be 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -28,7 +28,6 @@
 #include "base/test/with_feature_override.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/trees/render_frame_metadata.h"
 #include "components/input/input_router.h"
 #include "components/input/mouse_wheel_event_queue.h"
@@ -1211,7 +1210,7 @@
             widget_host_->screen_rects().at(0).second);
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 // Checks that a popup view is destroyed when a user clicks outside of the popup
 // view and focus does not change. This is the case when the user clicks on the
 // desktop background on Chrome OS.
@@ -4948,7 +4947,7 @@
   ReleaseAndResetDispatchedMessages();
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 // Check that when accessibility virtual keyboard is enabled, windows are
 // shifted up when focused and restored when focus is lost.
 TEST_F(RenderWidgetHostViewAuraTest, VirtualKeyboardFocusEnsureCaretInRect) {
@@ -5041,7 +5040,7 @@
   EXPECT_EQ(view_->insets_, resized_view_insets);
 }
 
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 // Tests that invalid touch events are consumed and handled
 // synchronously.
diff --git a/content/browser/renderer_host/render_widget_host_view_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
index 79c4bc8..9b2da394 100644
--- a/content/browser/renderer_host/render_widget_host_view_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
@@ -23,7 +23,6 @@
 #include "base/test/test_timeouts.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/slim/layer_tree.h"
 #include "cc/slim/surface_layer.h"
 #include "components/viz/common/features.h"
@@ -1480,7 +1479,7 @@
   PerformTestWithLeftRightRects(html_rect_size, copy_rect, output_size);
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 // On ChromeOS there is no software compositing.
 static const auto kTestCompositingModes = testing::Values(GL_COMPOSITING);
 #else
diff --git a/content/browser/scheduler/responsiveness/jank_monitor_impl.cc b/content/browser/scheduler/responsiveness/jank_monitor_impl.cc
index 6047c4c..300a7cf 100644
--- a/content/browser/scheduler/responsiveness/jank_monitor_impl.cc
+++ b/content/browser/scheduler/responsiveness/jank_monitor_impl.cc
@@ -8,7 +8,6 @@
 #include "base/observer_list.h"
 #include "base/task/thread_pool.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/base/ui_base_features.h"
diff --git a/content/browser/screen_orientation/screen_orientation_browsertest.cc b/content/browser/screen_orientation/screen_orientation_browsertest.cc
index 6237747..de8fde5 100644
--- a/content/browser/screen_orientation/screen_orientation_browsertest.cc
+++ b/content/browser/screen_orientation/screen_orientation_browsertest.cc
@@ -10,7 +10,6 @@
 #include "base/command_line.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/preloading/prerender/prerender_final_status.h"
 #include "content/browser/preloading/prerender/prerender_host_registry.h"
 #include "content/browser/renderer_host/frame_tree.h"
@@ -135,7 +134,7 @@
 // actually support MacOS X if and when it switches to Aura.
 #if defined(USE_AURA) || BUILDFLAG(IS_ANDROID)
 // Flaky on Chrome OS: http://crbug.com/468259
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #define MAYBE_ScreenOrientationChange DISABLED_ScreenOrientationChange
 #else
 #define MAYBE_ScreenOrientationChange ScreenOrientationChange
@@ -170,7 +169,7 @@
 #endif  // defined(USE_AURA) || BUILDFLAG(IS_ANDROID)
 
 // Flaky on Chrome OS: http://crbug.com/468259
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #define MAYBE_WindowOrientationChange DISABLED_WindowOrientationChange
 #else
 #define MAYBE_WindowOrientationChange WindowOrientationChange
@@ -326,7 +325,7 @@
 // blink::mojom::FrameWidget::EnableDeviceEmulation, which calls
 // RenderWidget::Resize on the renderer side.  The test fakes this by directly
 // sending the resize message to the widget.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #define MAYBE_ScreenOrientationInPendingMainFrame \
   DISABLED_ScreenOrientationInPendingMainFrame
 #else
diff --git a/content/browser/screenlock_monitor/screenlock_monitor_device_source.h b/content/browser/screenlock_monitor/screenlock_monitor_device_source.h
index cc460e2..ce7c518 100644
--- a/content/browser/screenlock_monitor/screenlock_monitor_device_source.h
+++ b/content/browser/screenlock_monitor/screenlock_monitor_device_source.h
@@ -8,7 +8,6 @@
 #include <memory>
 
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/screenlock_monitor/screenlock_monitor_source.h"
 #include "content/common/content_export.h"
 
@@ -18,11 +17,11 @@
 #include <wtsapi32.h>
 #endif  // BUILDFLAG(IS_WIN)
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include <optional>
 
 #include "components/session_manager/core/session_manager_observer.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 #if BUILDFLAG(IS_WIN)
 namespace gfx {
@@ -93,7 +92,7 @@
   void StopListeningForScreenlock();
 #endif  // BUILDFLAG(IS_MAC)
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   class ScreenLockListener : public session_manager::SessionManagerObserver {
    public:
     ScreenLockListener();
@@ -111,7 +110,7 @@
   };
 
   ScreenLockListener screenlock_listener_;
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 };
 
 }  // namespace content
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index fb0e8a8..d617b5e 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -88,7 +88,6 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/network_switches.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/mojom/fetch_api.mojom.h"
@@ -1923,12 +1922,7 @@
 class SecurityExploitBrowserTestWithTrustTokensEnabled
     : public SecurityExploitBrowserTest {
  public:
-  SecurityExploitBrowserTestWithTrustTokensEnabled() {
-    feature_list_.InitAndEnableFeature(network::features::kPrivateStateTokens);
-  }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
+  SecurityExploitBrowserTestWithTrustTokensEnabled() = default;
 };
 
 // Test that the browser correctly reports a bad message when a child frame
diff --git a/content/browser/service_worker/service_worker_internals_ui_browsertest.cc b/content/browser/service_worker/service_worker_internals_ui_browsertest.cc
index 5b14f415..8c7bfae9 100644
--- a/content/browser/service_worker/service_worker_internals_ui_browsertest.cc
+++ b/content/browser/service_worker/service_worker_internals_ui_browsertest.cc
@@ -12,7 +12,6 @@
 #include "base/strings/string_util.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/browser/service_worker/service_worker_test_utils.h"
diff --git a/content/browser/service_worker/service_worker_main_resource_loader_interceptor.cc b/content/browser/service_worker/service_worker_main_resource_loader_interceptor.cc
index fc0bc31d..689d6f69 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader_interceptor.cc
+++ b/content/browser/service_worker/service_worker_main_resource_loader_interceptor.cc
@@ -10,7 +10,6 @@
 
 #include "base/functional/bind.h"
 #include "base/memory/ptr_util.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/navigation_request.h"
 #include "content/browser/renderer_host/navigation_request_info.h"
 #include "content/browser/service_worker/service_worker_client.h"
@@ -44,11 +43,11 @@
                                                             url.scheme()))
     return true;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   return url.SchemeIs(kExternalFileScheme);
-#else   // BUILDFLAG(IS_CHROMEOS_ASH)
+#else   // BUILDFLAG(IS_CHROMEOS)
   return false;
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 }
 
 // Returns true if a ServiceWorkerMainResourceLoaderInterceptor should be
diff --git a/content/browser/service_worker/service_worker_main_resource_loader_interceptor_unittest.cc b/content/browser/service_worker/service_worker_main_resource_loader_interceptor_unittest.cc
index 5b7824e..5ad518d 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader_interceptor_unittest.cc
+++ b/content/browser/service_worker/service_worker_main_resource_loader_interceptor_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "content/browser/service_worker/service_worker_main_resource_loader_interceptor.h"
 
-#include "build/chromeos_buildflags.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_browser_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -89,9 +88,9 @@
 TEST_F(ServiceWorkerMainResourceLoaderInterceptorTest,
        ShouldCreateForNavigation_ExternalFileScheme) {
   bool expected_handler_created = false;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   expected_handler_created = true;
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
   EXPECT_EQ(
       expected_handler_created,
       ShouldCreateForNavigation(GURL("externalfile:drive/doc"),
diff --git a/content/browser/session_history_browsertest.cc b/content/browser/session_history_browsertest.cc
index f25a755..e73298a3 100644
--- a/content/browser/session_history_browsertest.cc
+++ b/content/browser/session_history_browsertest.cc
@@ -9,7 +9,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/content_navigation_policy.h"
 #include "content/public/browser/navigation_controller.h"
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index bb97f3e..6cda8dc0 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -49,7 +49,6 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/base/math_util.h"
 #include "cc/input/touch_action.h"
 #include "components/input/input_router.h"
@@ -10859,7 +10858,7 @@
 //
 // TODO(crbug.com/40561636): Disabled on Android, Mac, and ChromeOS due to
 // flakiness.
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
 #define MAYBE_OOPIFDetachDuringAnimation DISABLED_OOPIFDetachDuringAnimation
 #else
 #define MAYBE_OOPIFDetachDuringAnimation OOPIFDetachDuringAnimation
@@ -12550,7 +12549,7 @@
 }
 
 // Touchscreen DoubleTapZoom is only supported on Android & ChromeOS at present.
-#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_ANDROID)
+#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
 // A test ContentBrowserClient implementation which enforces
 // WebPreferences' |double_tap_to_zoom_enabled| to be true.
 class DoubleTapZoomContentBrowserClient
@@ -12651,7 +12650,7 @@
     new_page_scale = observer_a.LastRenderFrameMetadata().page_scale_factor;
   } while (new_page_scale < target_scale);
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_ANDROID)
+#endif  // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
 
 class CrossProcessNavigationObjectElementTest
     : public SitePerProcessBrowserTestBase,
diff --git a/content/browser/site_per_process_layout_browsertest.cc b/content/browser/site_per_process_layout_browsertest.cc
index 0d5b370..ec54fb5 100644
--- a/content/browser/site_per_process_layout_browsertest.cc
+++ b/content/browser/site_per_process_layout_browsertest.cc
@@ -8,7 +8,6 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/gmock_expected_support.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/base/math_util.h"
 #include "content/browser/renderer_host/cross_process_frame_connector.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
@@ -39,7 +38,7 @@
 #include "ui/base/test/scoped_preferred_scroller_style_mac.h"
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "ui/aura/test/test_screen.h"
 #endif
 
@@ -406,7 +405,7 @@
                          testing::Values(1.0, 1.5, 2.0));
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
                        SubframeUpdateToCorrectDeviceScaleFactor) {
   GURL main_url(embedded_test_server()->GetURL(
diff --git a/content/browser/snapshot_browsertest.cc b/content/browser/snapshot_browsertest.cc
index 2f4d0aee9..b06ca09b 100644
--- a/content/browser/snapshot_browsertest.cc
+++ b/content/browser/snapshot_browsertest.cc
@@ -16,7 +16,6 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
@@ -259,10 +258,8 @@
 //   Linux TSAN Tests
 // See crbug.com/771119
 // TODO(crbug.com/40834774): Fix and enable on Fuchsia.
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) ||  \
-    ((BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && \
-     defined(THREAD_SANITIZER)) ||                      \
-    BUILDFLAG(IS_FUCHSIA)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA) || \
+    (BUILDFLAG(IS_LINUX) && defined(THREAD_SANITIZER))
 #define MAYBE_SyncMultiWindowTest DISABLED_SyncMultiWindowTest
 #else
 #define MAYBE_SyncMultiWindowTest SyncMultiWindowTest
@@ -325,8 +322,7 @@
 // TODO(crbug.com/40740836): recently crashes flakily on
 // linux_chromium_asan_rel_ng and linux-rel.
 // TODO(crbug.com/40834774): Fix and enable on Fuchsia.
-#if (BUILDFLAG(IS_WIN) && !defined(NDEBUG)) || BUILDFLAG(IS_CHROMEOS_ASH) || \
-    (BUILDFLAG(IS_CHROMEOS) && defined(THREAD_SANITIZER)) ||                 \
+#if (BUILDFLAG(IS_WIN) && !defined(NDEBUG)) || BUILDFLAG(IS_CHROMEOS) || \
     BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_FUCHSIA)
 #define MAYBE_AsyncMultiWindowTest DISABLED_AsyncMultiWindowTest
 #else
diff --git a/content/browser/speech/speech_recognition_browsertest.cc b/content/browser/speech/speech_recognition_browsertest.cc
index 39fa9b9..0eb76ab 100644
--- a/content/browser/speech/speech_recognition_browsertest.cc
+++ b/content/browser/speech/speech_recognition_browsertest.cc
@@ -50,13 +50,12 @@
 #include "content/browser/speech/soda_speech_recognition_engine_impl.h"
 #include "media/base/media_switches.h"
 #include "media/mojo/mojom/audio_data.mojom.h"
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "ash/constants/ash_features.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
 #endif  // !BUILDFLAG(IS_FUCHSIA)
 
+#if BUILDFLAG(IS_CHROMEOS)
+#include "ash/constants/ash_features.h"
+#endif  // BUILDFLAG(IS_CHROMEOS)
+
 using base::RunLoop;
 using CaptureCallback = media::AudioCapturerSource::CaptureCallback;
 
@@ -198,9 +197,9 @@
         /*enabled_features=*/
         {
             media::kOnDeviceWebSpeech,
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
             ash::features::kOnDeviceSpeechRecognition,
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
         },
         /*disabled_features=*/{});
   }
diff --git a/content/browser/speech/speech_recognition_manager_impl_unittest.cc b/content/browser/speech/speech_recognition_manager_impl_unittest.cc
index 98dac49..700baae2 100644
--- a/content/browser/speech/speech_recognition_manager_impl_unittest.cc
+++ b/content/browser/speech/speech_recognition_manager_impl_unittest.cc
@@ -11,9 +11,9 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "ash/constants/ash_features.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 namespace content {
 
@@ -44,9 +44,9 @@
       /*enabled_features=*/
       {
           media::kOnDeviceWebSpeech,
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
           ash::features::kOnDeviceSpeechRecognition,
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
       },
       /*disabled_features=*/{});
 }
diff --git a/content/browser/speech/tts_controller_impl.cc b/content/browser/speech/tts_controller_impl.cc
index 399f6dd..e16d147 100644
--- a/content/browser/speech/tts_controller_impl.cc
+++ b/content/browser/speech/tts_controller_impl.cc
@@ -20,7 +20,6 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/speech/tts_utterance_impl.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/tts_utterance.h"
@@ -32,7 +31,7 @@
 #include "third_party/blink/public/mojom/speech/speech_synthesis.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "content/public/browser/tts_controller_delegate.h"
 #endif
 
@@ -44,7 +43,7 @@
 // A value to be used to indicate that there is no length available.
 const int kInvalidLength = -1;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 bool VoiceIdMatches(
     const std::optional<TtsControllerDelegate::PreferredVoiceId>& id,
     const content::VoiceData& voice) {
@@ -55,7 +54,7 @@
     return id->name == voice.name && id->id.empty();
   return id->name == voice.name && id->id == voice.engine_id;
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 TtsUtteranceImpl* AsUtteranceImpl(TtsUtterance* utterance) {
   return static_cast<TtsUtteranceImpl*>(utterance);
@@ -380,7 +379,7 @@
 }
 
 void TtsControllerImpl::OnTtsUtteranceBecameInvalid(int utterance_id) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   // This handles the case that the utterance originated from the standalone
   // browser becomes invalid, we need to stop
   RemoveUtteranceAndStopIfNeeded(utterance_id);
@@ -720,7 +719,7 @@
   double rate = utterance->GetContinuousParameters().rate;
   double pitch = utterance->GetContinuousParameters().pitch;
   double volume = utterance->GetContinuousParameters().volume;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   if (GetTtsControllerDelegate())
     GetTtsControllerDelegate()->UpdateUtteranceDefaultsFromPrefs(
         utterance, &rate, &pitch, &volume);
@@ -733,7 +732,7 @@
     pitch = blink::mojom::kSpeechSynthesisDefaultPitch;
   if (volume == blink::mojom::kSpeechSynthesisDoublePrefNotSet)
     volume = blink::mojom::kSpeechSynthesisDefaultVolume;
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
   utterance->SetContinuousParameters(rate, pitch, volume);
 }
 
@@ -818,12 +817,12 @@
   // match, something will be returned if there are any voices.
   int best_score = -1;
   int best_score_index = -1;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   TtsControllerDelegate* delegate = GetTtsControllerDelegate();
   std::unique_ptr<TtsControllerDelegate::PreferredVoiceIds> preferred_ids =
       delegate ? delegate->GetPreferredVoiceIdsForUtterance(utterance)
                : nullptr;
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
   for (size_t i = 0; i < voices.size(); ++i) {
     const content::VoiceData& voice = voices[i];
     int score = 0;
@@ -877,7 +876,7 @@
         score += 32;
     }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     if (preferred_ids) {
       // First prefer the user's preference voice for the utterance language,
       // if the utterance language is specified.
@@ -897,7 +896,7 @@
       if (VoiceIdMatches(preferred_ids->any_locale_voice_id, voice))
         score += 4;
     }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
     // Finally, prefer system language.
     if (!voice.lang.empty()) {
@@ -1036,7 +1035,7 @@
   }
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 TtsControllerDelegate* TtsControllerImpl::GetTtsControllerDelegate() {
   if (delegate_)
     return delegate_;
@@ -1051,6 +1050,6 @@
     TtsControllerDelegate* delegate) {
   delegate_ = delegate;
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 }  // namespace content
diff --git a/content/browser/speech/tts_controller_impl.h b/content/browser/speech/tts_controller_impl.h
index eda452a..7492a73 100644
--- a/content/browser/speech/tts_controller_impl.h
+++ b/content/browser/speech/tts_controller_impl.h
@@ -18,7 +18,6 @@
 #include "base/observer_list.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/tts_controller.h"
 #include "content/public/browser/tts_platform.h"
@@ -30,7 +29,7 @@
 namespace content {
 class BrowserContext;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 class TtsControllerDelegate;
 #endif
 
@@ -202,7 +201,7 @@
   void OnNetworkChanged(
       net::NetworkChangeNotifier::ConnectionType type) override;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   TtsControllerDelegate* GetTtsControllerDelegate();
   void SetTtsControllerDelegateForTesting(TtsControllerDelegate* delegate);
   raw_ptr<TtsControllerDelegate, DanglingUntriaged> delegate_ = nullptr;
diff --git a/content/browser/speech/tts_controller_unittest.cc b/content/browser/speech/tts_controller_unittest.cc
index 6ca91a2..9cffe4d 100644
--- a/content/browser/speech/tts_controller_unittest.cc
+++ b/content/browser/speech/tts_controller_unittest.cc
@@ -10,7 +10,6 @@
 #include "base/memory/raw_ptr.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/speech/tts_utterance_impl.h"
 #include "content/public/browser/tts_platform.h"
 #include "content/public/browser/visibility.h"
@@ -22,7 +21,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/speech/speech_synthesis.mojom.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "content/public/browser/tts_controller_delegate.h"
 #endif
 
@@ -180,7 +179,7 @@
   int stop_called_ = 0;
 };
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 class MockTtsControllerDelegate : public TtsControllerDelegate {
  public:
   MockTtsControllerDelegate() = default;
@@ -228,7 +227,7 @@
   using TtsControllerImpl::GetMatchingVoice;
   using TtsControllerImpl::SpeakNextUtterance;
   using TtsControllerImpl::UpdateUtteranceDefaults;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   using TtsControllerImpl::SetTtsControllerDelegateForTesting;
 #endif
   using TtsControllerImpl::IsPausedForTesting;
@@ -253,7 +252,7 @@
     // since it has no extensions.
     controller()->SetTtsEngineDelegate(&engine_delegate_);
 #endif  // !BUILDFLAG(IS_ANDROID)
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     controller()->SetTtsControllerDelegateForTesting(&delegate_);
 #endif
     controller()->AddVoicesChangedDelegate(&voices_changed_);
@@ -269,7 +268,7 @@
   TestBrowserContext* browser_context() { return browser_context_.get(); }
   MockTtsEngineDelegate* engine_delegate() { return &engine_delegate_; }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   MockTtsControllerDelegate* delegate() { return &delegate_; }
 #endif
   void ReleaseTtsController() {
@@ -311,13 +310,13 @@
   std::unique_ptr<MockTtsPlatformImpl> platform_impl_;
   std::unique_ptr<TestBrowserContext> browser_context_;
   MockTtsEngineDelegate engine_delegate_;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   MockTtsControllerDelegate delegate_;
 #endif
   MockVoicesChangedDelegate voices_changed_;
 };
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 TEST_F(TtsControllerTest, TestBrowserContextRemoved) {
   std::vector<VoiceData> voices;
   VoiceData voice_data;
@@ -470,7 +469,7 @@
     utterance->SetEngineId("id5");
     EXPECT_EQ(5, controller()->GetMatchingVoice(utterance.get(), voices));
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     TtsControllerDelegate::PreferredVoiceIds preferred_voice_ids;
     preferred_voice_ids.locale_voice_id.emplace("Voice7", "id7");
     preferred_voice_ids.any_locale_voice_id.emplace("Android", "");
@@ -537,7 +536,7 @@
     utterance->SetLang("");
     EXPECT_EQ(1, controller()->GetMatchingVoice(utterance.get(), voices));
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     // voice0 is matched against the system language which has no region piece.
     TestContentBrowserClient::GetInstance()->set_application_locale("en");
     EXPECT_EQ(0, controller()->GetMatchingVoice(utterance.get(), voices));
@@ -575,7 +574,7 @@
     utterance->SetLang("EN-US");
     EXPECT_EQ(0, controller()->GetMatchingVoice(utterance.get(), voices));
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     // Add another English voice.
     VoiceData voice2;
     voice2.engine_id = "id1";
diff --git a/content/browser/speech/tts_platform_impl.cc b/content/browser/speech/tts_platform_impl.cc
index 01d8de7..2a2c8922 100644
--- a/content/browser/speech/tts_platform_impl.cc
+++ b/content/browser/speech/tts_platform_impl.cc
@@ -10,7 +10,6 @@
 
 #include <string>
 
-#include "build/chromeos_buildflags.h"
 
 namespace content {
 
diff --git a/content/browser/speech/tts_utterance_impl.h b/content/browser/speech/tts_utterance_impl.h
index 4fd59943..2666293 100644
--- a/content/browser/speech/tts_utterance_impl.h
+++ b/content/browser/speech/tts_utterance_impl.h
@@ -13,7 +13,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/unguessable_token.h"
 #include "base/values.h"
-#include "build/chromeos_buildflags.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/tts_utterance.h"
 
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 0d9c53cc..07c4665 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -37,7 +37,6 @@
 #include "base/threading/sequence_local_storage_slot.h"
 #include "base/types/optional_util.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/attribution_reporting/features.h"
 #include "components/leveldb_proto/public/proto_database_provider.h"
 #include "components/services/storage/privileged/cpp/bucket_client_info.h"
diff --git a/content/browser/tracing/tracing_controller_browsertest.cc b/content/browser/tracing/tracing_controller_browsertest.cc
index f7b2f6a9..e0082f4 100644
--- a/content/browser/tracing/tracing_controller_browsertest.cc
+++ b/content/browser/tracing/tracing_controller_browsertest.cc
@@ -20,7 +20,6 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "build/chromecast_buildflags.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/tracing/tracing_controller_impl.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -35,7 +34,7 @@
 #include "services/tracing/public/cpp/trace_event_agent.h"
 #include "services/tracing/public/cpp/tracing_features.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.h"
 #include "chromeos/ash/components/system/fake_statistics_provider.h"
 #include "chromeos/ash/components/system/statistics_provider.h"
@@ -104,7 +103,7 @@
     enable_recording_done_callback_count_ = 0;
     disable_recording_done_callback_count_ = 0;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     ash::DebugDaemonClient::InitializeFake();
     // Set statistic provider for hardware class tests.
     ash::system::StatisticsProvider::SetTestProvider(
@@ -117,7 +116,7 @@
 
   void TearDown() override {
     ContentBrowserTest::TearDown();
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     ash::DebugDaemonClient::Shutdown();
 #endif
   }
@@ -321,7 +320,7 @@
     }
   }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
  protected:
   ash::system::ScopedFakeStatisticsProvider fake_statistics_provider_;
 #endif
@@ -412,7 +411,7 @@
   ASSERT_TRUE(trace_config);
   EXPECT_EQ(TraceConfig().ToString(), *trace_config);
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   std::string* hardware_class = metadata_json->FindString("hardware-class");
   ASSERT_TRUE(hardware_class);
   EXPECT_EQ(*hardware_class, "test-hardware-class");
@@ -433,7 +432,7 @@
   EXPECT_TRUE(KeyNotEquals(*metadata_json, "network-type", "__stripped__"));
   EXPECT_TRUE(KeyNotEquals(*metadata_json, "os-name", "__stripped__"));
   EXPECT_TRUE(KeyNotEquals(*metadata_json, "user-agent", "__stripped__"));
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   EXPECT_TRUE(KeyNotEquals(*metadata_json, "hardware-class", "__stripped__"));
 #endif
 
@@ -495,7 +494,7 @@
 }
 
 // Only CrOS and Cast support system tracing.
-#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CASTOS)
+#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_CASTOS)
 #define MAYBE_SystemTraceEvents SystemTraceEvents
 #else
 #define MAYBE_SystemTraceEvents DISABLED_SystemTraceEvents
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc
index 65b2d7f..266f7da 100644
--- a/content/browser/tracing/tracing_controller_impl.cc
+++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -34,7 +34,6 @@
 #include "base/values.h"
 #include "base/version_info/version_info.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/tracing/common/trace_to_console.h"
 #include "components/tracing/common/tracing_switches.h"
 #include "components/variations/active_field_trials.h"
@@ -63,7 +62,7 @@
 #include "third_party/perfetto/protos/perfetto/trace/trace_packet.pbzero.h"
 #include "v8/include/v8-version-string.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "chromeos/ash/components/system/statistics_provider.h"
 #include "content/browser/tracing/cros_tracing_agent.h"
 #endif
@@ -191,7 +190,7 @@
   AddAgents();
   g_tracing_controller = this;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   // Bind hwclass once the statistics are available.
   ash::system::StatisticsProvider::GetInstance()
       ->ScheduleOnMachineStatisticsLoaded(
@@ -209,7 +208,7 @@
   tracing::TracedProcessImpl::GetInstance()->SetTaskRunner(
       base::SequencedTaskRunner::GetCurrentDefault());
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   agents_.push_back(std::make_unique<CrOSTracingAgent>());
 #elif defined(CAST_TRACING_AGENT)
   agents_.push_back(std::make_unique<CastTracingAgent>());
@@ -302,13 +301,13 @@
 #endif
 
   // OS
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   metadata_dict.Set("os-name", "CrOS");
   if (are_statistics_loaded_)
     metadata_dict.Set("hardware-class", hardware_class_);
 #else
   metadata_dict.Set("os-name", base::SysInfo::OperatingSystemName());
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
   metadata_dict.Set("os-version", base::SysInfo::OperatingSystemVersion());
 #if BUILDFLAG(IS_WIN)
   if (base::win::OSInfo::GetArchitecture() ==
@@ -587,7 +586,7 @@
     CompleteFlush();
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 void TracingControllerImpl::OnMachineStatisticsLoaded() {
   if (const std::optional<std::string_view> hardware_class =
           ash::system::StatisticsProvider::GetInstance()->GetMachineStatistic(
diff --git a/content/browser/tracing/tracing_controller_impl.h b/content/browser/tracing/tracing_controller_impl.h
index 2845e931..1b4c2c3 100644
--- a/content/browser/tracing/tracing_controller_impl.h
+++ b/content/browser/tracing/tracing_controller_impl.h
@@ -16,7 +16,6 @@
 #include "base/task/task_traits.h"
 #include "base/timer/timer.h"
 #include "base/values.h"
-#include "build/chromeos_buildflags.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/tracing_controller.h"
 #include "mojo/public/cpp/bindings/receiver.h"
@@ -99,7 +98,7 @@
 
   void InitStartupTracingForDuration();
   void EndStartupTracing();
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   void OnMachineStatisticsLoaded();
 #endif
 
@@ -115,7 +114,7 @@
   bool is_data_complete_ = false;
   bool read_buffers_complete_ = false;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   bool are_statistics_loaded_ = false;
   std::string hardware_class_;
   base::WeakPtrFactory<TracingControllerImpl> weak_ptr_factory_{this};
diff --git a/content/browser/utility_process_sandbox_browsertest.cc b/content/browser/utility_process_sandbox_browsertest.cc
index 5c3d43528..2d0027e 100644
--- a/content/browser/utility_process_sandbox_browsertest.cc
+++ b/content/browser/utility_process_sandbox_browsertest.cc
@@ -11,7 +11,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/utility_process_host.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -28,9 +27,9 @@
 #include "sandbox/policy/sandbox_type.h"
 #include "sandbox/policy/switches.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "chromeos/ash/components/assistant/buildflags.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 using sandbox::mojom::Sandbox;
 using sandbox::policy::SandboxLinux;
@@ -121,17 +120,17 @@
       }
 
       case Sandbox::kAudio:
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
       case Sandbox::kHardwareVideoDecoding:
-#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_ASH)
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
       case Sandbox::kIme:
       case Sandbox::kTts:
       case Sandbox::kNearby:
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
       case Sandbox::kLibassistant:
 #endif  // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 #if BUILDFLAG(IS_LINUX)
       case Sandbox::kVideoEffects:
       case Sandbox::kOnDeviceTranslation:
@@ -168,9 +167,8 @@
 };
 
 IN_PROC_BROWSER_TEST_P(UtilityProcessSandboxBrowserTest, VerifySandboxType) {
-#if BUILDFLAG(IS_LINUX) ||                                  \
-    (BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(USE_VAAPI) && \
-     !BUILDFLAG(USE_V4L2_CODEC))
+#if BUILDFLAG(IS_LINUX) || (BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(USE_VAAPI) && \
+                            !BUILDFLAG(USE_V4L2_CODEC))
   if (GetParam() == Sandbox::kHardwareVideoDecoding) {
     // TODO(b/195769334): On Linux, this test fails with
     // Sandbox::kHardwareVideoDecoding because the pre-sandbox hook needs Ozone
diff --git a/content/browser/utility_sandbox_delegate.cc b/content/browser/utility_sandbox_delegate.cc
index d8ef151..ab7c6ee 100644
--- a/content/browser/utility_sandbox_delegate.cc
+++ b/content/browser/utility_sandbox_delegate.cc
@@ -8,7 +8,6 @@
 
 #include "base/check.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/common/features.h"
 #include "content/public/common/sandboxed_process_launcher_delegate.h"
 #include "content/public/common/zygote/zygote_buildflags.h"
@@ -25,9 +24,9 @@
 #include "sandbox/policy/sandbox_type.h"
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "chromeos/ash/components/assistant/buildflags.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 #if BUILDFLAG(IS_MAC)
 #include "base/mac/process_requirement.h"
@@ -78,20 +77,18 @@
 #if BUILDFLAG(IS_FUCHSIA)
       sandbox_type_ == sandbox::mojom::Sandbox::kVideoCapture ||
 #endif
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_ASH)
-      sandbox_type_ == sandbox::mojom::Sandbox::kHardwareVideoDecoding ||
-#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_ASH)
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+      sandbox_type_ == sandbox::mojom::Sandbox::kHardwareVideoDecoding ||
       sandbox_type_ == sandbox::mojom::Sandbox::kHardwareVideoEncoding ||
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
       sandbox_type_ == sandbox::mojom::Sandbox::kIme ||
       sandbox_type_ == sandbox::mojom::Sandbox::kTts ||
       sandbox_type_ == sandbox::mojom::Sandbox::kNearby ||
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
       sandbox_type_ == sandbox::mojom::Sandbox::kLibassistant ||
 #endif  // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
     BUILDFLAG(IS_WIN)
       sandbox_type_ == sandbox::mojom::Sandbox::kScreenAI ||
@@ -146,20 +143,18 @@
   // process upon startup.
   if (sandbox_type_ == sandbox::mojom::Sandbox::kNetwork ||
       sandbox_type_ == sandbox::mojom::Sandbox::kOnDeviceModelExecution ||
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_ASH)
-      sandbox_type_ == sandbox::mojom::Sandbox::kHardwareVideoDecoding ||
-#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_ASH)
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+      sandbox_type_ == sandbox::mojom::Sandbox::kHardwareVideoDecoding ||
       sandbox_type_ == sandbox::mojom::Sandbox::kHardwareVideoEncoding ||
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
       sandbox_type_ == sandbox::mojom::Sandbox::kIme ||
       sandbox_type_ == sandbox::mojom::Sandbox::kTts ||
       sandbox_type_ == sandbox::mojom::Sandbox::kNearby ||
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
       sandbox_type_ == sandbox::mojom::Sandbox::kLibassistant ||
 #endif  // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
       sandbox_type_ == sandbox::mojom::Sandbox::kAudio ||
 #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
     BUILDFLAG(IS_WIN)
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index c2f0752..ed31bcc 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -49,7 +49,6 @@
 #include "base/trace_event/optional_trace_event.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "cc/input/browser_controls_offset_tags_info.h"
 #include "components/attribution_reporting/features.h"
 #include "components/download/public/common/download_stats.h"
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index ad94b8f..2534ebe9 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -22,7 +22,6 @@
 #include "base/test/test_future.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/download/public/common/download_url_parameters.h"
 #include "components/input/native_web_keyboard_event.h"
 #include "content/browser/child_process_security_policy_impl.h"
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc
index e6e75281..2d0345e 100644
--- a/content/browser/web_contents/web_contents_view_aura.cc
+++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -698,7 +698,7 @@
 void WebContentsViewAura::PrepareDropData(
     DropData* drop_data,
     const ui::OSExchangeData& data) const {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   // TODO(b/256022714): Using `IsRendererTainted()` breaks the Files app. Always
   // setting this to false is currently believed to be safe-ish because ChromeOS
   // separates URL and filename metadata and does not implement the DownloadURL
diff --git a/content/browser/web_contents/web_contents_view_aura_browsertest.cc b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
index dcfc9d6..ecb635fe 100644
--- a/content/browser/web_contents/web_contents_view_aura_browsertest.cc
+++ b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
@@ -21,7 +21,6 @@
 #include "base/test/test_timeouts.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/renderer_host/navigation_controller_impl.h"
 #include "content/browser/renderer_host/navigation_entry_impl.h"
 #include "content/browser/renderer_host/overscroll_controller.h"
@@ -480,7 +479,7 @@
 // Disabled because the test always fails the first time it runs on the Win Aura
 // bots, and usually but not always passes second-try (See crbug.com/179532).
 // Flaky on CrOS, Linux, and Fuchsia as well: https://crbug.com/856079
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_LINUX) || \
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || \
     BUILDFLAG(IS_FUCHSIA)
 #define MAYBE_QuickOverscrollDirectionChange \
   DISABLED_QuickOverscrollDirectionChange
diff --git a/content/browser/web_contents/web_contents_view_aura_unittest.cc b/content/browser/web_contents/web_contents_view_aura_unittest.cc
index c9b1669..3ebe2328 100644
--- a/content/browser/web_contents/web_contents_view_aura_unittest.cc
+++ b/content/browser/web_contents/web_contents_view_aura_unittest.cc
@@ -15,7 +15,6 @@
 #include "base/test/scoped_command_line.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/content_features.h"
@@ -385,7 +384,7 @@
 
   // Simulate the drag originating in the renderer process, in which case
   // any file data should be filtered out (anchor drag scenario) except in
-  // CHROMEOS_ASH.
+  // CHROMEOS.
   data->MarkRendererTaintedFromOrigin(url::Origin());
 
   ui::DropTargetEvent event(*data.get(), kClientPt, kScreenPt,
@@ -405,7 +404,7 @@
   EXPECT_EQ(string_data, view->current_drag_data_->text);
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   ASSERT_FALSE(view->current_drag_data_->filenames.empty());
 #else
   ASSERT_TRUE(view->current_drag_data_->filenames.empty());
@@ -437,8 +436,8 @@
   EXPECT_EQ(string_data, drop_complete_data_->drop_data.text);
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  // CHROMEOS_ASH never filters out files from a drop, even if the drag
+#if BUILDFLAG(IS_CHROMEOS)
+  // CHROMEOS never filters out files from a drop, even if the drag
   // originated from a renderer, because otherwise, it breaks the Files app.
   ASSERT_FALSE(drop_complete_data_->drop_data.filenames.empty());
 #else
@@ -768,7 +767,7 @@
 }
 #endif  // BUILDFLAG(IS_WIN)
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 
 TEST_F(WebContentsViewAuraTest, StartDragging) {
   const char kGmailUrl[] = "http://mail.google.com/";
@@ -799,7 +798,7 @@
   EXPECT_EQ(*(exchange_data->GetSource()->GetURL()), GURL(kGmailUrl));
 }
 
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 TEST_F(WebContentsViewAuraTest,
        RejectDragFromPrivilegedWebContentsToNonPrivilegedWebContents) {
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index b91c8044..e5e4fe82 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -53,7 +53,6 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "components/cbor/reader.h"
 #include "components/cbor/values.h"
 #include "components/ukm/test_ukm_recorder.h"
diff --git a/content/browser/webauth/is_uvpaa.cc b/content/browser/webauth/is_uvpaa.cc
index 10cdbb66..5329b51 100644
--- a/content/browser/webauth/is_uvpaa.cc
+++ b/content/browser/webauth/is_uvpaa.cc
@@ -6,7 +6,6 @@
 
 #include "base/feature_list.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/public/browser/authenticator_request_client_delegate.h"
 #include "content/public/common/content_client.h"
 #include "device/fido/features.h"
diff --git a/content/browser/webauth/is_uvpaa.h b/content/browser/webauth/is_uvpaa.h
index 09907f0..95748acd 100644
--- a/content/browser/webauth/is_uvpaa.h
+++ b/content/browser/webauth/is_uvpaa.h
@@ -7,7 +7,6 @@
 
 #include "base/functional/callback.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/common/content_export.h"
 
 #if BUILDFLAG(IS_MAC)
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc
index dc1d0acf..a2035fd 100644
--- a/content/browser/webid/federated_auth_request_impl.cc
+++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -1266,7 +1266,7 @@
     if (get_info_it->second.provider->format) {
       // If a token format was specified, make sure that the configURL
       // supports it as well as the feature is enabled.
-      if (!IsFedCmIdPRegistrationEnabled() ||
+      if (!IsFedCmDelegationEnabled() ||
           !base::Contains(fetch_result.metadata->formats, kVcSdJwt)) {
         OnFetchDataForIdpFailed(
             std::move(idp_info),
@@ -2307,7 +2307,7 @@
   std::string query;
   if (idp_blindness) {
     // Checked previously.
-    DCHECK(IsFedCmIdPRegistrationEnabled());
+    DCHECK(IsFedCmDelegationEnabled());
 
     // Creates a throw away private key for a one-time use for
     // a single presentation. The public key gets sent to the
@@ -2743,7 +2743,7 @@
 void FederatedAuthRequestImpl::ProcessSdJwt(const GURL& config_url,
                                             const std::string& token) {
   // Checked previously.
-  DCHECK(IsFedCmIdPRegistrationEnabled());
+  DCHECK(IsFedCmDelegationEnabled());
 
   auto value = sdjwt::SdJwt::Parse(token);
   if (!value) {
diff --git a/content/browser/webid/flags.cc b/content/browser/webid/flags.cc
index d274c426..fd60d46f 100644
--- a/content/browser/webid/flags.cc
+++ b/content/browser/webid/flags.cc
@@ -42,6 +42,10 @@
   return base::FeatureList::IsEnabled(features::kFedCmSelectiveDisclosure);
 }
 
+bool IsFedCmDelegationEnabled() {
+  return base::FeatureList::IsEnabled(features::kFedCmDelegation);
+}
+
 bool IsFedCmIdPRegistrationEnabled() {
   return base::FeatureList::IsEnabled(features::kFedCmIdPRegistration);
 }
diff --git a/content/browser/webid/flags.h b/content/browser/webid/flags.h
index 34a80119..5784993 100644
--- a/content/browser/webid/flags.h
+++ b/content/browser/webid/flags.h
@@ -35,6 +35,9 @@
 // Whether the Selective Disclosure API is enabled.
 bool IsFedCmSelectiveDisclosureEnabled();
 
+// Whether the Delegation API is enabled.
+bool IsFedCmDelegationEnabled();
+
 // Whether the IdP Registration API is enabled.
 bool IsFedCmIdPRegistrationEnabled();
 
diff --git a/content/browser/webid/webid_browsertest.cc b/content/browser/webid/webid_browsertest.cc
index b81271b..265cd3c 100644
--- a/content/browser/webid/webid_browsertest.cc
+++ b/content/browser/webid/webid_browsertest.cc
@@ -1823,6 +1823,7 @@
 
     std::vector<base::test::FeatureRef> features;
     features.push_back(features::kFedCm);
+    features.push_back(features::kFedCmDelegation);
     // Needs the fields API
     features.push_back(features::kFedCmAuthz);
     // Intended to be used in Active mode
diff --git a/content/browser/webrtc/webrtc_browsertest.cc b/content/browser/webrtc/webrtc_browsertest.cc
index c2d4acee..3ca230d 100644
--- a/content/browser/webrtc/webrtc_browsertest.cc
+++ b/content/browser/webrtc/webrtc_browsertest.cc
@@ -8,7 +8,6 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/platform_thread.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/browser/webrtc/webrtc_content_browsertest_base.h"
 #include "content/public/browser/network_service_util.h"
diff --git a/content/browser/webrtc/webrtc_content_browsertest_base.cc b/content/browser/webrtc/webrtc_content_browsertest_base.cc
index cfd161ef..f74dcb3 100644
--- a/content/browser/webrtc/webrtc_content_browsertest_base.cc
+++ b/content/browser/webrtc/webrtc_content_browsertest_base.cc
@@ -10,7 +10,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/audio_service.h"
 #include "content/public/common/content_switches.h"
@@ -21,7 +20,7 @@
 #include "media/base/media_switches.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "chromeos/ash/components/audio/cras_audio_handler.h"
 #include "chromeos/ash/components/dbus/audio/cras_audio_client.h"
 #endif
@@ -39,7 +38,7 @@
 void WebRtcContentBrowserTestBase::SetUp() {
   // We need pixel output when we dig pixels out of video tags for verification.
   EnablePixelOutput();
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   ash::CrasAudioClient::InitializeFake();
   ash::CrasAudioHandler::InitializeForTesting();
 #endif
@@ -50,7 +49,7 @@
 
 void WebRtcContentBrowserTestBase::TearDown() {
   ContentBrowserTest::TearDown();
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   ash::CrasAudioHandler::Shutdown();
   ash::CrasAudioClient::Shutdown();
 #endif
diff --git a/content/browser/webrtc/webrtc_getusermedia_browsertest.cc b/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
index fac490b6..28c5c29 100644
--- a/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
+++ b/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
@@ -14,7 +14,6 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/browser/web_contents/web_contents_impl.h"
diff --git a/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc b/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc
index 64ac366..e000588 100644
--- a/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc
+++ b/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc
@@ -6,7 +6,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/video_capture_service.h"
 #include "content/public/common/content_features.h"
diff --git a/content/browser/webui/shared_resources_data_source.cc b/content/browser/webui/shared_resources_data_source.cc
index 20b4b20..e7f7f086 100644
--- a/content/browser/webui/shared_resources_data_source.cc
+++ b/content/browser/webui/shared_resources_data_source.cc
@@ -11,14 +11,13 @@
 
 #include <set>
 
-#include "build/chromeos_buildflags.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
 #include "ui/base/webui/web_ui_util.h"
 #include "ui/resources/grit/webui_resources.h"
 #include "ui/resources/grit/webui_resources_map.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "ash/webui/grit/ash_webui_common_resources_map.h"
 #include "chromeos/ash/grit/ash_resources.h"
 #include "chromeos/ash/grit/ash_resources_map.h"
@@ -34,7 +33,7 @@
 
 namespace {
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 const std::set<int> GetContentResourceIds() {
   return std::set<int>{
       IDR_UNGUESSABLE_TOKEN_MOJO_JS,
@@ -71,7 +70,7 @@
     source->AddResourcePath(resource.path, resource.id);
   }
 }
-#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 }  // namespace
 
@@ -84,7 +83,7 @@
   // they are only used by one UI) or in //ui/webui/resources/mojo:build_ts
   // (if used by multiple UIs).
   source->AddResourcePaths(kWebuiResources);
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   source->AddResourcePaths(kAshWebuiCommonResources);
   // Deprecated -lite style mojo bindings.
   source->AddResourcePaths(kMojoBindingsResources);
@@ -94,7 +93,7 @@
                kChromeosResourcesSize, source);
   AddResources(GetAshMojoResourceIds(), kAshResources, kAshResourcesSize,
                source);
-#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 }
 
 }  // namespace content
diff --git a/content/browser/webui/web_ui_mojo_browsertest.cc b/content/browser/webui/web_ui_mojo_browsertest.cc
index b7e6632..9b9c7c8 100644
--- a/content/browser/webui/web_ui_mojo_browsertest.cc
+++ b/content/browser/webui/web_ui_mojo_browsertest.cc
@@ -50,7 +50,7 @@
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "third_party/blink/public/common/chrome_debug_urls.h"
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "content/test/data/web_ui_test.test-mojom.h"
 #include "content/test/data/web_ui_test_types.test-mojom.h"
 #endif
@@ -62,7 +62,7 @@
 const char kMojoWebUiTsHost[] = "mojo-web-ui-ts";
 const char kDummyWebUiHost[] = "dummy-web-ui";
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 class WebUIMojoTestCacheImpl : public mojom::WebUIMojoTestCache {
  public:
   explicit WebUIMojoTestCacheImpl(
@@ -161,7 +161,7 @@
                                    {BindingsPolicyValue::kMojoWebUi}))
       : WebUIController(web_ui) {
     web_ui->SetBindings(bindings);
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     {
       WebUIDataSource* data_source = WebUIDataSource::CreateAndAdd(
           web_ui->GetWebContents()->GetBrowserContext(), kMojoWebUiHost);
@@ -199,7 +199,7 @@
   TestWebUIController& operator=(const TestWebUIController&) = delete;
 
  protected:
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   std::unique_ptr<WebUIMojoTestCacheImpl> cache_;
 #endif
   std::unique_ptr<WebUITsMojoTestCacheImpl> ts_cache_;
@@ -214,7 +214,7 @@
       : TestWebUIController(web_ui) {}
   ~CacheTestWebUIController() override = default;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
   void BindInterface(
       mojo::PendingReceiver<mojom::WebUIMojoTestCache> receiver) {
     cache_ = std::make_unique<WebUIMojoTestCacheImpl>(std::move(receiver));
@@ -225,7 +225,7 @@
   void BindInterface(
       mojo::PendingReceiver<mojom::WebUITsMojoTestCache> receiver) {
     ts_cache_ = std::make_unique<WebUITsMojoTestCacheImpl>(std::move(receiver));
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     ASSERT_FALSE(cache_);
 #endif
   }
@@ -317,7 +317,7 @@
   void RegisterBrowserInterfaceBindersForFrame(
       RenderFrameHost* render_frame_host,
       mojo::BinderMapWithContext<content::RenderFrameHost*>* map) override {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     RegisterWebUIControllerInterfaceBinder<mojom::WebUIMojoTestCache,
                                            CacheTestWebUIController>(map);
 #endif
@@ -369,7 +369,7 @@
 
 // Test both JS and TS on Ash, since Ash widely uses both types of WebUI
 // bindings. Test TS only on other platforms.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
 INSTANTIATE_TEST_SUITE_P(All, WebUIMojoTest, testing::Bool());
 #else
 INSTANTIATE_TEST_SUITE_P(All, WebUIMojoTest, testing::Values(true));
diff --git a/content/browser/zygote_host/zygote_host_impl_linux.cc b/content/browser/zygote_host/zygote_host_impl_linux.cc
index 8eca918..bd1013c 100644
--- a/content/browser/zygote_host/zygote_host_impl_linux.cc
+++ b/content/browser/zygote_host/zygote_host_impl_linux.cc
@@ -16,7 +16,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/types/fixed_array.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/common/zygote/zygote_commands_linux.h"
 #include "content/common/zygote/zygote_communication_linux.h"
 #include "content/common/zygote/zygote_handle_impl_linux.h"
diff --git a/content/browser/zygote_host/zygote_host_impl_linux.h b/content/browser/zygote_host/zygote_host_impl_linux.h
index 720d823..8ef884a 100644
--- a/content/browser/zygote_host/zygote_host_impl_linux.h
+++ b/content/browser/zygote_host/zygote_host_impl_linux.h
@@ -15,7 +15,6 @@
 #include "base/process/launch.h"
 #include "base/process/process_handle.h"
 #include "base/synchronization/lock.h"
-#include "build/chromeos_buildflags.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/zygote_host/zygote_host_linux.h"
 
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 93e49ca..341947d 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -214,6 +214,8 @@
            kSetOnlyIfOverridden},
           {wf::EnableFedCmAuthz, raw_ref(features::kFedCmAuthz),
            kSetOnlyIfOverridden},
+          {wf::EnableFedCmDelegation, raw_ref(features::kFedCmDelegation),
+           kDefault},
           {wf::EnableFedCmIdPRegistration,
            raw_ref(features::kFedCmIdPRegistration), kDefault},
           {wf::EnableFedCmIdpSigninStatus,
@@ -542,37 +544,6 @@
 
   WebRuntimeFeatures::EnableBackForwardCache(
       content::IsBackForwardCacheEnabled());
-
-  if (base::FeatureList::IsEnabled(network::features::kPrivateStateTokens)) {
-    WebRuntimeFeatures::EnablePrivateStateTokens(true);
-    WebRuntimeFeatures::EnablePrivateStateTokensAlwaysAllowIssuance(true);
-  } else if (base::FeatureList::IsEnabled(network::features::kFledgePst)) {
-    // See https://bit.ly/configuring-trust-tokens.
-    using network::features::TrustTokenOriginTrialSpec;
-    switch (
-        network::features::kTrustTokenOperationsRequiringOriginTrial.Get()) {
-      case TrustTokenOriginTrialSpec::kOriginTrialNotRequired:
-        // Setting PrivateStateTokens=true enables the Trust Tokens interface;
-        // PrivateStateTokensAlwaysAllowIssuance disables a runtime check
-        // during issuance that the origin trial is active (see
-        // blink/.../trust_token_issuance_authorization.h).
-        WebRuntimeFeatures::EnablePrivateStateTokens(true);
-        WebRuntimeFeatures::EnablePrivateStateTokensAlwaysAllowIssuance(true);
-        break;
-      case TrustTokenOriginTrialSpec::kAllOperationsRequireOriginTrial:
-        // The origin trial itself will be responsible for enabling the
-        // PrivateStateTokens RuntimeEnabledFeature.
-        WebRuntimeFeatures::EnablePrivateStateTokens(false);
-        WebRuntimeFeatures::EnablePrivateStateTokensAlwaysAllowIssuance(false);
-        break;
-      case TrustTokenOriginTrialSpec::kOnlyIssuanceRequiresOriginTrial:
-        // At issuance, a runtime check will be responsible for checking that
-        // the origin trial is present.
-        WebRuntimeFeatures::EnablePrivateStateTokens(true);
-        WebRuntimeFeatures::EnablePrivateStateTokensAlwaysAllowIssuance(false);
-        break;
-    }
-  }
 }
 
 // Ensures that the various ways of enabling/disabling features do not produce
diff --git a/content/common/features.cc b/content/common/features.cc
index e3298ec..ffd508e0 100644
--- a/content/common/features.cc
+++ b/content/common/features.cc
@@ -261,14 +261,6 @@
              "InMemoryCodeCache",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// During compositor frame eviction, collect not only the surfaces that are
-// reachable from the main frame tree, but also recurse into inner
-// frames. Otherwise only toplevel frames and OOPIF are handled, and other
-// cases, e.g. PDF tiles are ignored. See https://crbug.com/1360351 for details.
-BASE_FEATURE(kInnerFrameCompositorSurfaceEviction,
-             "InnerFrameCompositorSurfaceEviction",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 // Enables the ability to use the updateIfOlderThanMs field in the trusted
 // bidding response to trigger a post-auction update if the group has been
 // updated more recently than updateIfOlderThanMs milliseconds, bypassing the
diff --git a/content/common/features.h b/content/common/features.h
index 2db9b65..fce93d23 100644
--- a/content/common/features.h
+++ b/content/common/features.h
@@ -70,7 +70,6 @@
 #endif
 
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kInMemoryCodeCache);
-CONTENT_EXPORT BASE_DECLARE_FEATURE(kInnerFrameCompositorSurfaceEviction);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kInterestGroupUpdateIfOlderThan);
 #if BUILDFLAG(IS_MAC)
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kIOSurfaceCapturer);
diff --git a/content/common/service_worker/race_network_request_url_loader_client.cc b/content/common/service_worker/race_network_request_url_loader_client.cc
index fef5441..188ba92 100644
--- a/content/common/service_worker/race_network_request_url_loader_client.cc
+++ b/content/common/service_worker/race_network_request_url_loader_client.cc
@@ -29,6 +29,10 @@
     "ServiceWorker.LoadTiming.MainFrame.MainResource";
 const char kSubresourceHistogramLoadTiming[] =
     "ServiceWorker.LoadTiming.Subresource";
+const char kMainResourceHistogramForRaceNetworkFetchEvent[] =
+    "ServiceWorker.FetchEvent.MainResource.RaceNetworkRequest";
+const char kSubresourceHistogramForRaceNetworkFetchEvent[] =
+    "ServiceWorker.FetchEvent.Subresource.RaceNetworkRequest";
 }  // namespace
 
 ServiceWorkerRaceNetworkRequestURLLoaderClient::
@@ -206,15 +210,12 @@
       TRACE_ID_LOCAL(this),
       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "url", request_.url,
       "state", state_);
-  if (owner_->IsMainResourceLoader()) {
-    base::UmaHistogramBoolean(
-        "ServiceWorker.FetchEvent.MainResource.RaceNetworkRequest.Redirect",
-        redirected_);
-  } else {
-    base::UmaHistogramBoolean(
-        "ServiceWorker.FetchEvent.Subresource.RaceNetworkRequest.Redirect",
-        redirected_);
-  }
+  base::UmaHistogramBoolean(
+      base::StrCat({owner_->IsMainResourceLoader()
+                        ? kMainResourceHistogramForRaceNetworkFetchEvent
+                        : kSubresourceHistogramForRaceNetworkFetchEvent,
+                    ".Redirect"}),
+      redirected_);
 
   switch (data_consume_policy_) {
     case DataConsumePolicy::kTeeResponse:
@@ -370,6 +371,17 @@
         read_buffer_manager_->IsWatching()) {
       read_buffer_manager_->CancelWatching();
     }
+  } else if (clone_response_for_fetch_handler_completed_) {
+    // In some scenario, there is a case that data clonings for both network and
+    // fetch handler were finished, but still waiting for `OnComplete()` from
+    // the original resource loading. We need to call `OnComplete()` to complete
+    // the fetch handler if it's not called yet. crbug.com/384414080 for more
+    // contexts.
+    //
+    // Note: This is needed only when the
+    // ServiceWorkerStaticRouterRaceNetworkRequestPerformanceImprovement feature
+    // is enabled.
+    forwarding_client_->OnComplete(completion_status_.value());
   }
 }
 
@@ -691,9 +703,14 @@
 
 void ServiceWorkerRaceNetworkRequestURLLoaderClient::
     OnCloneCompletedForFetchHandler() {
-  CHECK(completion_status_.has_value());
-  forwarding_client_->OnComplete(completion_status_.value());
-  write_buffer_manager_for_fetch_handler_.ResetProducer();
+  clone_response_for_fetch_handler_completed_ = true;
+  if (completion_status_.has_value()) {
+    // If `completion_status_` already exists, which means the resource load was
+    // already completed. Then the resource load for fetch handler should be
+    // completed as well.
+    forwarding_client_->OnComplete(completion_status_.value());
+    write_buffer_manager_for_fetch_handler_.ResetProducer();
+  }
 }
 
 void ServiceWorkerRaceNetworkRequestURLLoaderClient::TransitionState(
diff --git a/content/common/service_worker/race_network_request_url_loader_client.h b/content/common/service_worker/race_network_request_url_loader_client.h
index 9024cde9..a1979d30 100644
--- a/content/common/service_worker/race_network_request_url_loader_client.h
+++ b/content/common/service_worker/race_network_request_url_loader_client.h
@@ -249,6 +249,7 @@
   std::optional<base::TimeTicks> fetch_handler_end_time_;
   std::optional<bool> is_fetch_handler_fallback_;
   bool is_main_resource_;
+  bool clone_response_for_fetch_handler_completed_ = false;
 
   base::TimeTicks request_start_;
   base::Time request_start_time_;
diff --git a/content/common/skia_utils.cc b/content/common/skia_utils.cc
index ee8b8d1..2b145db 100644
--- a/content/common/skia_utils.cc
+++ b/content/common/skia_utils.cc
@@ -24,11 +24,6 @@
 // allocation that exceeds this limit.
 const size_t kImageCacheSingleAllocationByteLimit = 64 * 1024 * 1024;
 
-// Decreases the size of the font cache to 1MiB.
-BASE_FEATURE(kSmallerFontCache,
-             "SmallerFontCache",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 }  // namespace
 
 void InitializeSkia() {
@@ -40,12 +35,13 @@
   }
 
   const int kMB = 1024 * 1024;
+
+  // Could also reduce the maximum number of cached strikes, but the intent
+  // being to reduce memory usage, only control cache memory usage.
+  SkGraphics::SetFontCacheLimit(kMB);
+
+#if !BUILDFLAG(IS_ANDROID)
   size_t font_cache_limit;
-#if BUILDFLAG(IS_ANDROID)
-  font_cache_limit =
-      base::SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled() ? kMB : 8 * kMB;
-  SkGraphics::SetFontCacheLimit(font_cache_limit);
-#else
   if (cmd.HasSwitch(switches::kSkiaFontCacheLimitMb)) {
     if (base::StringToSizeT(
             cmd.GetSwitchValueASCII(switches::kSkiaFontCacheLimitMb),
@@ -64,12 +60,6 @@
   }
 #endif
 
-  if (base::FeatureList::IsEnabled(kSmallerFontCache)) {
-    // Could also reduce the maximum number of cached strikes, but the intent
-    // being to reduce memory usage, only control cache memory usage.
-    SkGraphics::SetFontCacheLimit(kMB);
-  }
-
   InitSkiaEventTracer();
   base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
       skia::SkiaMemoryDumpProvider::GetInstance(), "Skia", nullptr);
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 76fd051..c1995d3 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -450,6 +450,11 @@
              "FedCmButtonMode",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+// Enables usage of the FedCM Delegation API.
+BASE_FEATURE(kFedCmDelegation,
+             "FedCmDelegation",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Enables usage of the FedCM IdP Registration API.
 BASE_FEATURE(kFedCmIdPRegistration,
              "FedCmIdPregistration",
@@ -537,11 +542,6 @@
              "NetworkQualityEstimatorWebHoldback",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Determines if an extra brand version pair containing possibly escaped double
-// quotes and escaped backslashed should be added to the Sec-CH-UA header
-// (activated by kUserAgentClientHint)
-BASE_FEATURE(kGreaseUACH, "GreaseUACH", base::FEATURE_ENABLED_BY_DEFAULT);
-
 // Whether GuestViews (see components/guest_view/README.md) are implemented
 // using MPArch inner pages. See https://crbug.com/40202416
 BASE_FEATURE(kGuestViewMPArch,
@@ -1370,12 +1370,6 @@
              base::FEATURE_DISABLED_BY_DEFAULT
 #endif
 );
-
-// Kill switch for allowing webview to suppress tap immediately after fling,
-// matching chrome behavior.
-BASE_FEATURE(kWebViewSuppressTapDuringFling,
-             "WebViewSuppressTapDuringFling",
-             base::FEATURE_ENABLED_BY_DEFAULT);
 #endif  // BUILDFLAG(IS_ANDROID)
 
 #if BUILDFLAG(IS_MAC)
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index c257f9f..23c1ed2 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -113,6 +113,7 @@
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFedCm);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFedCmAuthz);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFedCmButtonMode);
+CONTENT_EXPORT BASE_DECLARE_FEATURE(kFedCmDelegation);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFedCmIdPRegistration);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFedCmIdpSigninStatusEnabled);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFedCmMetricsEndpoint);
@@ -130,7 +131,6 @@
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kWebIdentityDigitalCredentials);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kWebIdentityDigitalCredentialsCreation);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFractionalScrollOffsets);
-CONTENT_EXPORT BASE_DECLARE_FEATURE(kGreaseUACH);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kGuestViewMPArch);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kIdbPrioritizeForegroundClients);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kIgnoreDuplicateNavs);
@@ -303,7 +303,6 @@
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kReduceGpuPriorityOnBackground);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kSmartZoom);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kUserMediaScreenCapturing);
-CONTENT_EXPORT BASE_DECLARE_FEATURE(kWebViewSuppressTapDuringFling);
 #endif  // BUILDFLAG(IS_ANDROID)
 
 #if BUILDFLAG(IS_MAC)
diff --git a/content/services/auction_worklet/register_ad_beacon_bindings.cc b/content/services/auction_worklet/register_ad_beacon_bindings.cc
index df0e711..20b2fb2 100644
--- a/content/services/auction_worklet/register_ad_beacon_bindings.cc
+++ b/content/services/auction_worklet/register_ad_beacon_bindings.cc
@@ -14,6 +14,7 @@
 #include "base/functional/callback.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "content/services/auction_worklet/auction_v8_helper.h"
 #include "content/services/auction_worklet/auction_v8_logger.h"
 #include "content/services/auction_worklet/webidl_compat.h"
diff --git a/content/services/auction_worklet/report_bindings.cc b/content/services/auction_worklet/report_bindings.cc
index 56630fb..60b1567 100644
--- a/content/services/auction_worklet/report_bindings.cc
+++ b/content/services/auction_worklet/report_bindings.cc
@@ -11,6 +11,7 @@
 #include "base/format_macros.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
+#include "base/strings/stringprintf.h"
 #include "content/services/auction_worklet/auction_v8_helper.h"
 #include "content/services/auction_worklet/auction_v8_logger.h"
 #include "content/services/auction_worklet/webidl_compat.h"
diff --git a/content/services/auction_worklet/trusted_signals_kvv2_manager.cc b/content/services/auction_worklet/trusted_signals_kvv2_manager.cc
index 1c91c87..6bca728 100644
--- a/content/services/auction_worklet/trusted_signals_kvv2_manager.cc
+++ b/content/services/auction_worklet/trusted_signals_kvv2_manager.cc
@@ -17,6 +17,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/notreached.h"
+#include "base/strings/stringprintf.h"
 #include "base/types/expected.h"
 #include "base/types/optional_ref.h"
 #include "components/cbor/reader.h"
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index d67b63f..99b4112 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1579,7 +1579,6 @@
     "../browser/network/transferable_socket_browsertest.cc",
     "../browser/network/trust_token_browsertest.cc",
     "../browser/network/trust_token_browsertest.h",
-    "../browser/network/trust_token_origin_trial_browsertest.cc",
     "../browser/network/trust_token_parameters_browsertest.cc",
     "../browser/network_service_browsertest.cc",
     "../browser/network_service_restart_browsertest.cc",
diff --git a/docs/website b/docs/website
index ffa936b..31a2f43 160000
--- a/docs/website
+++ b/docs/website
@@ -1 +1 @@
-Subproject commit ffa936be041b042d683f68b68ec4f141133530e2
+Subproject commit 31a2f432dc14e60054e2a361f4fa16ffff65e01b
diff --git a/extensions/browser/api/user_scripts/user_scripts_api.cc b/extensions/browser/api/user_scripts/user_scripts_api.cc
index eeadc02c..3ae798f 100644
--- a/extensions/browser/api/user_scripts/user_scripts_api.cc
+++ b/extensions/browser/api/user_scripts/user_scripts_api.cc
@@ -588,9 +588,6 @@
   EXTENSION_FUNCTION_VALIDATE(params);
   EXTENSION_FUNCTION_VALIDATE(extension());
 
-  std::optional<std::string> csp = std::move(params->properties.csp);
-  bool enable_messaging = params->properties.messaging.value_or(false);
-
   std::optional<std::string> world_id;
   if (base::FeatureList::IsEnabled(
           extensions_features::kApiUserScriptsMultipleWorlds)) {
@@ -613,8 +610,25 @@
                                  kMaxNumberOfRegisteredWorlds)));
   }
 
-  config_manager->SetUserScriptWorldInfo(*extension(), world_id, csp,
-                                         enable_messaging);
+  mojom::UserScriptWorldInfoPtr world_info =
+      config_manager->GetUserScriptWorldInfo(extension()->id(), world_id);
+  bool changed = false;
+
+  std::optional<std::string> csp = std::move(params->properties.csp);
+  if (csp && csp != world_info->csp) {
+    changed = true;
+    world_info->csp = std::move(csp);
+  }
+
+  std::optional<bool> enable_messaging = params->properties.messaging;
+  if (enable_messaging && *enable_messaging != world_info->enable_messaging) {
+    changed = true;
+    world_info->enable_messaging = *enable_messaging;
+  }
+
+  if (changed) {
+    config_manager->SetUserScriptWorldInfo(*extension(), std::move(world_info));
+  }
 
   return RespondNow(NoArguments());
 }
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index d3618efc..8f7f624a 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -431,8 +431,6 @@
     if (extensions::kExtensionScheme == request_scheme &&
         ExtensionsBrowserClient::Get()->IsExtensionTelemetryServiceEnabled(
             browser_context) &&
-        base::FeatureList::IsEnabled(
-            safe_browsing::kExtensionTelemetryReportContactedHosts) &&
         !base::FeatureList::IsEnabled(
             safe_browsing::
                 kExtensionTelemetryInterceptRemoteHostsContactedInRenderer)) {
@@ -591,8 +589,6 @@
   // launched.
   return ExtensionsBrowserClient::Get()->IsExtensionTelemetryServiceEnabled(
              browser_context_) &&
-         base::FeatureList::IsEnabled(
-             safe_browsing::kExtensionTelemetryReportContactedHosts) &&
          !base::FeatureList::IsEnabled(
              safe_browsing::
                  kExtensionTelemetryInterceptRemoteHostsContactedInRenderer);
diff --git a/extensions/browser/extension_protocols.cc b/extensions/browser/extension_protocols.cc
index c001e4a..18e3921 100644
--- a/extensions/browser/extension_protocols.cc
+++ b/extensions/browser/extension_protocols.cc
@@ -350,10 +350,8 @@
 }
 
 bool IsFaviconURL(const GURL& url) {
-  return base::FeatureList::IsEnabled(
-             extensions_features::kNewExtensionFaviconHandling) &&
-         (IsPathEqualTo(url, kFaviconSourcePath) ||
-          IsPathEqualTo(url, base::StrCat({kFaviconSourcePath, "/"})));
+  return IsPathEqualTo(url, kFaviconSourcePath) ||
+         IsPathEqualTo(url, base::StrCat({kFaviconSourcePath, "/"}));
 }
 
 bool IsBackgroundPageURL(const GURL& url) {
diff --git a/extensions/browser/extension_registrar_unittest.cc b/extensions/browser/extension_registrar_unittest.cc
index 5ad46315..d3ffec3c 100644
--- a/extensions/browser/extension_registrar_unittest.cc
+++ b/extensions/browser/extension_registrar_unittest.cc
@@ -543,26 +543,4 @@
   TryDisablingNotAshKeeplistedExtension(/* expect_extension_disabled= */ true);
 }
 
-#if BUILDFLAG(IS_CHROMEOS)
-// Test that a controlled extension that is not on the ash keep-list cannot be
-// disabled if ash is still enabled.
-TEST_F(ExtensionRegistrarTest,
-       NotDisableNotAshKeeplistedForceInstalledExtensionIfAshEnabled) {
-  static_cast<TestingPrefServiceSimple*>(pref_service())
-      ->registry()
-      ->RegisterIntegerPref(
-          prefs::kLacrosLaunchSwitch,
-          static_cast<int>(
-              ash::standalone_browser::LacrosAvailability::kLacrosOnly));
-  EXPECT_TRUE(crosapi::browser_util::IsAshWebBrowserEnabled());
-
-  // Prevent the extension from being disabled (by the user).
-  ON_CALL(*delegate(), CanDisableExtension(extension().get()))
-      .WillByDefault(Return(false));
-  AddEnabledExtension();
-
-  TryDisablingNotAshKeeplistedExtension(/* expect_extension_disabled= */ false);
-}
-#endif  // BUILDFLAG(IS_CHROMEOS)
-
 }  // namespace extensions
diff --git a/extensions/browser/user_script_world_configuration_manager.cc b/extensions/browser/user_script_world_configuration_manager.cc
index 36164f22..d88766d 100644
--- a/extensions/browser/user_script_world_configuration_manager.cc
+++ b/extensions/browser/user_script_world_configuration_manager.cc
@@ -103,10 +103,8 @@
 
 void UserScriptWorldConfigurationManager::SetUserScriptWorldInfo(
     const Extension& extension,
-    const std::optional<std::string>& world_id,
-    std::optional<std::string> csp,
-    bool enable_messaging) {
-  CHECK(!world_id || !world_id->empty());
+    mojom::UserScriptWorldInfoPtr world_info) {
+  CHECK(!world_info->world_id || !world_info->world_id->empty());
   // Persist world configuratation in ExtensionPrefs.
   ExtensionPrefs::ScopedDictionaryUpdate update(
       extension_prefs_, extension.id(), kUserScriptsWorldsConfiguration.name);
@@ -115,17 +113,21 @@
     update_dict = update.Create();
   }
 
-  base::Value::Dict world_info;
-  world_info.Set(kUserScriptWorldMessagingKey, enable_messaging);
-  if (csp.has_value()) {
-    world_info.Set(kUserScriptWorldCspKey, *csp);
+  base::Value::Dict world_info_dict;
+  world_info_dict.Set(kUserScriptWorldMessagingKey,
+                      world_info->enable_messaging);
+  if (world_info->csp.has_value()) {
+    world_info_dict.Set(kUserScriptWorldCspKey, *world_info->csp);
   }
 
-  update_dict->SetKey(GetUserScriptWorldKeyForWorldId(world_id),
-                      base::Value(std::move(world_info)));
+  update_dict->SetKey(GetUserScriptWorldKeyForWorldId(world_info->world_id),
+                      base::Value(std::move(world_info_dict)));
 
-  renderer_helper_->SetUserScriptWorldProperties(extension, world_id, csp,
-                                                 enable_messaging);
+  // TODO(devlin): Have RendererStartupHelper::SetUserScriptWorldProperties()
+  // take a mojom::UserScriptWorldInfoPtr.
+  renderer_helper_->SetUserScriptWorldProperties(
+      extension, world_info->world_id, world_info->csp,
+      world_info->enable_messaging);
 }
 
 void UserScriptWorldConfigurationManager::ClearUserScriptWorldInfo(
diff --git a/extensions/browser/user_script_world_configuration_manager.h b/extensions/browser/user_script_world_configuration_manager.h
index 3a80c22..8c3bda1 100644
--- a/extensions/browser/user_script_world_configuration_manager.h
+++ b/extensions/browser/user_script_world_configuration_manager.h
@@ -48,9 +48,7 @@
   // `world_id` is omitted, sets the configuration for the default user script
   // world.
   void SetUserScriptWorldInfo(const Extension& extension,
-                              const std::optional<std::string>& world_id,
-                              std::optional<std::string> csp,
-                              bool enable_messaging);
+                              mojom::UserScriptWorldInfoPtr world_info);
 
   // Clears any stored configuration for a user script world indicated by
   // `world_id`. If `world_id` is omitted, removes the configuration for the
diff --git a/extensions/common/api/virtual_keyboard_private.json b/extensions/common/api/virtual_keyboard_private.json
index 8a2957ea..b9279c03 100644
--- a/extensions/common/api/virtual_keyboard_private.json
+++ b/extensions/common/api/virtual_keyboard_private.json
@@ -225,7 +225,7 @@
       {
         "name": "openSettings",
         "type": "function",
-        "description": "Opens chrome://os-settings/osLanguages page.",
+        "description": "Opens chrome://os-settings/osLanguages/input page.",
         "parameters": []
       },
       {
diff --git a/extensions/common/extension_features.cc b/extensions/common/extension_features.cc
index 5bb85cd..92eacbb 100644
--- a/extensions/common/extension_features.cc
+++ b/extensions/common/extension_features.cc
@@ -134,10 +134,6 @@
              "LaunchWindowsNativeHostsDirectly",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kNewExtensionFaviconHandling,
-             "ExtensionsNewFaviconHandling",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 // To investigate signal beacon loss in crrev.com/c/2262402.
 BASE_FEATURE(kReportKeepaliveUkm,
              "ReportKeepaliveUkm",
diff --git a/extensions/common/extension_features.h b/extensions/common/extension_features.h
index 30facb3..e6ea6e2 100644
--- a/extensions/common/extension_features.h
+++ b/extensions/common/extension_features.h
@@ -160,9 +160,6 @@
 // cmd.exe process as a proxy.
 BASE_DECLARE_FEATURE(kLaunchWindowsNativeHostsDirectly);
 
-// Controls whether extensions can use the new favicon fetching in Manifest V3.
-BASE_DECLARE_FEATURE(kNewExtensionFaviconHandling);
-
 // Controls whether omnibox extensions can use the new capability to intercept
 // input without needing keyword mode.
 BASE_DECLARE_FEATURE(kExperimentalOmniboxLabs);
diff --git a/gpu/command_buffer/service/shared_memory_region_wrapper.cc b/gpu/command_buffer/service/shared_memory_region_wrapper.cc
index 1cd0eef..29c13d55 100644
--- a/gpu/command_buffer/service/shared_memory_region_wrapper.cc
+++ b/gpu/command_buffer/service/shared_memory_region_wrapper.cc
@@ -122,9 +122,9 @@
   return mapping_.IsValid();
 }
 
-uint8_t* SharedMemoryRegionWrapper::GetMemory(int plane_index) const {
+const uint8_t* SharedMemoryRegionWrapper::GetMemory(int plane_index) const {
   DCHECK(IsValid());
-  return mapping_.GetMemoryAs<uint8_t>() + planes_[plane_index].offset;
+  return mapping_.GetMemoryAs<const uint8_t>() + planes_[plane_index].offset;
 }
 
 size_t SharedMemoryRegionWrapper::GetStride(int plane_index) const {
diff --git a/gpu/command_buffer/service/shared_memory_region_wrapper.h b/gpu/command_buffer/service/shared_memory_region_wrapper.h
index ae1bcd6..12ef9e0 100644
--- a/gpu/command_buffer/service/shared_memory_region_wrapper.h
+++ b/gpu/command_buffer/service/shared_memory_region_wrapper.h
@@ -5,6 +5,9 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_SHARED_MEMORY_REGION_WRAPPER_H_
 #define GPU_COMMAND_BUFFER_SERVICE_SHARED_MEMORY_REGION_WRAPPER_H_
 
+#include <utility>
+#include <vector>
+
 #include "base/containers/span.h"
 #include "base/memory/shared_memory_mapping.h"
 #include "base/unguessable_token.h"
@@ -36,7 +39,10 @@
                   gfx::BufferFormat format);
 
   bool IsValid() const;
-  uint8_t* GetMemory(int plane_index) const;
+  uint8_t* GetMemory(int plane_index) {
+    return const_cast<uint8_t*>(std::as_const(*this).GetMemory(plane_index));
+  }
+  const uint8_t* GetMemory(int plane_index) const;
   size_t GetStride(int plane_index) const;
 
   // Returns SkPixmap pointing to memory for offset.
diff --git a/gpu/ipc/client/shared_image_interface_proxy.cc b/gpu/ipc/client/shared_image_interface_proxy.cc
index e2e1075..beb290d 100644
--- a/gpu/ipc/client/shared_image_interface_proxy.cc
+++ b/gpu/ipc/client/shared_image_interface_proxy.cc
@@ -48,7 +48,7 @@
   return region.mapping.size() - offset;
 }
 
-void* GetDataAddress(const base::MappedReadOnlyRegion& region,
+void* GetDataAddress(base::MappedReadOnlyRegion& region,
                      size_t offset,
                      size_t size) {
   base::CheckedNumeric<size_t> safe_end = offset;
diff --git a/headless/lib/browser/headless_browser_impl.cc b/headless/lib/browser/headless_browser_impl.cc
index 0bb6ff6..560bdba3 100644
--- a/headless/lib/browser/headless_browser_impl.cc
+++ b/headless/lib/browser/headless_browser_impl.cc
@@ -102,12 +102,12 @@
 
   // Rengenerate the brand version lists with kHeadlessProductName.
   metadata.brand_version_list = embedder_support::GenerateBrandVersionList(
-      seed, kHeadlessProductName, significant_version, std::nullopt,
-      std::nullopt, kEnableUpdatedGreaseByPolicy,
+      seed, kHeadlessProductName, significant_version,
+      kEnableUpdatedGreaseByPolicy,
       blink::UserAgentBrandVersionType::kMajorVersion);
   metadata.brand_full_version_list = embedder_support::GenerateBrandVersionList(
-      seed, kHeadlessProductName, metadata.full_version, std::nullopt,
-      std::nullopt, kEnableUpdatedGreaseByPolicy,
+      seed, kHeadlessProductName, metadata.full_version,
+      kEnableUpdatedGreaseByPolicy,
       blink::UserAgentBrandVersionType::kFullVersion);
   return metadata;
 }
diff --git a/infra/config/generated/testing/test_suites.pyl b/infra/config/generated/testing/test_suites.pyl
index 737459b..c73a0e6 100644
--- a/infra/config/generated/testing/test_suites.pyl
+++ b/infra/config/generated/testing/test_suites.pyl
@@ -2578,14 +2578,6 @@
     },
 
     'optimization_guide_android_gtests': {
-      'optimization_guide_components_unittests': {
-        'test_common': {
-          'args': [
-            '--gtest_filter=*OptimizationGuide*:*PageEntities*:*EntityAnnotator*',
-          ],
-        },
-        'test': 'components_unittests',
-      },
     },
 
     'optimization_guide_cros_gtests': {
@@ -2597,14 +2589,6 @@
         },
         'test': 'browser_tests',
       },
-      'optimization_guide_components_unittests': {
-        'test_common': {
-          'args': [
-            '--gtest_filter=*OptimizationGuide*:*PageEntities*:*EntityAnnotator*',
-          ],
-        },
-        'test': 'components_unittests',
-      },
     },
 
     'optimization_guide_gpu_gtests': {
@@ -2644,17 +2628,6 @@
           '--use-xvfb',
         ],
       },
-      'optimization_guide_components_unittests': {
-        'test_common': {
-          'args': [
-            '--gtest_filter=*OptimizationGuide*:*PageEntities*:*EntityAnnotator*',
-          ],
-        },
-        'test': 'components_unittests',
-        'linux_args': [
-          '--use-xvfb',
-        ],
-      },
       'optimization_guide_unittests': {
         'linux_args': [
           '--use-xvfb',
diff --git a/infra/config/targets/basic_suites.star b/infra/config/targets/basic_suites.star
index 3d25d9da..14e5659 100644
--- a/infra/config/targets/basic_suites.star
+++ b/infra/config/targets/basic_suites.star
@@ -1911,7 +1911,6 @@
 targets.legacy_basic_suite(
     name = "optimization_guide_android_gtests",
     tests = {
-        "optimization_guide_components_unittests": targets.legacy_test_config(),
         # TODO(mgeorgaklis): Add optimization_guide_unittests when they become Android compatible.
     },
 )
@@ -1920,7 +1919,6 @@
     name = "optimization_guide_cros_gtests",
     tests = {
         "optimization_guide_browser_tests": targets.legacy_test_config(),
-        "optimization_guide_components_unittests": targets.legacy_test_config(),
     },
 )
 
@@ -1949,11 +1947,6 @@
                 "--use-xvfb",
             ],
         ),
-        "optimization_guide_components_unittests": targets.legacy_test_config(
-            linux_args = [
-                "--use-xvfb",
-            ],
-        ),
         "optimization_guide_unittests": targets.legacy_test_config(
             linux_args = [
                 "--use-xvfb",
diff --git a/infra/config/targets/tests.star b/infra/config/targets/tests.star
index 672619f..f4008ed 100644
--- a/infra/config/targets/tests.star
+++ b/infra/config/targets/tests.star
@@ -1797,14 +1797,6 @@
 )
 
 targets.tests.gtest_test(
-    name = "optimization_guide_components_unittests",
-    args = [
-        "--gtest_filter=*OptimizationGuide*:*PageEntities*:*EntityAnnotator*",
-    ],
-    binary = "components_unittests",
-)
-
-targets.tests.gtest_test(
     name = "optimization_guide_gpu_unittests",
 )
 
diff --git a/internal b/internal
index ef593be..f367c8fb 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit ef593bebcf9e5a9d111c4f12d0732bf1366ca4b7
+Subproject commit f367c8fba0bcc44119ac34aa2e11dd2326780db6
diff --git a/ios/chrome/browser/collaboration/model/messaging/messaging_backend_service_factory.mm b/ios/chrome/browser/collaboration/model/messaging/messaging_backend_service_factory.mm
index 989fb61c..6b6a87f2 100644
--- a/ios/chrome/browser/collaboration/model/messaging/messaging_backend_service_factory.mm
+++ b/ios/chrome/browser/collaboration/model/messaging/messaging_backend_service_factory.mm
@@ -11,6 +11,7 @@
 #import "components/collaboration/internal/messaging/messaging_backend_service_impl.h"
 #import "components/collaboration/internal/messaging/storage/messaging_backend_store_impl.h"
 #import "components/collaboration/internal/messaging/tab_group_change_notifier_impl.h"
+#import "components/collaboration/public/features.h"
 #import "components/data_sharing/public/features.h"
 #import "ios/chrome/browser/collaboration/model/features.h"
 #import "ios/chrome/browser/data_sharing/model/data_sharing_service_factory.h"
@@ -49,7 +50,8 @@
 
   if (!base::FeatureList::IsEnabled(
           data_sharing::features::kDataSharingFeature) ||
-      !IsSharedTabGroupsJoinEnabled(profile)) {
+      !IsSharedTabGroupsJoinEnabled(profile) ||
+      !base::FeatureList::IsEnabled(kCollaborationMessaging)) {
     return std::make_unique<EmptyMessagingBackendService>();
   }
 
diff --git a/ios/chrome/browser/prefs/model/BUILD.gn b/ios/chrome/browser/prefs/model/BUILD.gn
index 3e09807a0..2840cdd 100644
--- a/ios/chrome/browser/prefs/model/BUILD.gn
+++ b/ios/chrome/browser/prefs/model/BUILD.gn
@@ -23,3 +23,16 @@
     "//ios/chrome/browser/sync/model/prefs",
   ]
 }
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [ "ios_chrome_pref_service_factory_unittest.cc" ]
+  deps = [
+    ":model",
+    "//base/test:test_support",
+    "//components/pref_registry",
+    "//components/sync/base:features",
+    "//components/sync_preferences",
+    "//testing/gtest",
+  ]
+}
diff --git a/ios/chrome/browser/prefs/model/ios_chrome_pref_service_factory.h b/ios/chrome/browser/prefs/model/ios_chrome_pref_service_factory.h
index e70526f..01a9ae3 100644
--- a/ios/chrome/browser/prefs/model/ios_chrome_pref_service_factory.h
+++ b/ios/chrome/browser/prefs/model/ios_chrome_pref_service_factory.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 
 class PrefRegistry;
@@ -31,6 +32,9 @@
 class PrefRegistrySyncable;
 }
 
+extern const base::FilePath::CharType kPreferencesFilename[];
+extern const base::FilePath::CharType kAccountPreferencesFilename[];
+
 // Factory methods that create and initialize a new instance of a PrefService
 // for Chrome on iOS with the applicable PrefStores. The `pref_filename` points
 // to the user preference file. This is the usual way to create a new
diff --git a/ios/chrome/browser/prefs/model/ios_chrome_pref_service_factory.mm b/ios/chrome/browser/prefs/model/ios_chrome_pref_service_factory.mm
index 32a9c86..702b544 100644
--- a/ios/chrome/browser/prefs/model/ios_chrome_pref_service_factory.mm
+++ b/ios/chrome/browser/prefs/model/ios_chrome_pref_service_factory.mm
@@ -8,6 +8,7 @@
 
 #import "base/check.h"
 #import "base/feature_list.h"
+#import "base/files/file_util.h"
 #import "base/functional/bind.h"
 #import "base/memory/ptr_util.h"
 #import "base/metrics/histogram_macros.h"
@@ -20,6 +21,7 @@
 #import "components/prefs/pref_service.h"
 #import "components/prefs/pref_store.h"
 #import "components/prefs/pref_value_store.h"
+#import "components/prefs/wrap_with_prefix_pref_store.h"
 #import "components/proxy_config/proxy_config_pref_names.h"
 #import "components/supervised_user/core/browser/supervised_user_pref_store.h"
 #import "components/supervised_user/core/common/features.h"
@@ -30,12 +32,10 @@
 
 namespace {
 
-const char kPreferencesFilename[] = "Preferences";
-const char kAccountPreferencesFilename[] = "AccountPreferences";
+const char kAccountPreferencesPrefix[] = "account_values";
 
 void PrepareFactory(sync_preferences::PrefServiceSyncableFactory* factory,
-                    const base::FilePath& pref_filename,
-                    base::SequencedTaskRunner* pref_io_task_runner,
+                    scoped_refptr<JsonPrefStore> user_pref_store,
                     policy::PolicyService* policy_service,
                     policy::BrowserPolicyConnector* policy_connector,
                     const scoped_refptr<PrefStore>& supervised_user_prefs) {
@@ -49,8 +49,7 @@
     factory->set_supervised_user_prefs(supervised_user_prefs);
   }
 
-  factory->set_user_prefs(base::MakeRefCounted<JsonPrefStore>(
-      pref_filename, std::unique_ptr<PrefFilter>(), pref_io_task_runner));
+  factory->set_user_prefs(std::move(user_pref_store));
 
   factory->SetPrefModelAssociatorClient(
       base::MakeRefCounted<IOSChromePrefModelAssociatorClient>());
@@ -58,6 +57,11 @@
 
 }  // namespace
 
+const base::FilePath::CharType kPreferencesFilename[] =
+    FILE_PATH_LITERAL("Preferences");
+const base::FilePath::CharType kAccountPreferencesFilename[] =
+    FILE_PATH_LITERAL("AccountPreferences");
+
 std::unique_ptr<PrefService> CreateLocalState(
     const base::FilePath& pref_filename,
     base::SequencedTaskRunner* pref_io_task_runner,
@@ -65,8 +69,11 @@
     policy::PolicyService* policy_service,
     policy::BrowserPolicyConnector* policy_connector) {
   sync_preferences::PrefServiceSyncableFactory factory;
-  PrepareFactory(&factory, pref_filename, pref_io_task_runner, policy_service,
-                 policy_connector, /*supervised_user_prefs=*/nullptr);
+  PrepareFactory(
+      &factory,
+      base::MakeRefCounted<JsonPrefStore>(
+          pref_filename, std::unique_ptr<PrefFilter>(), pref_io_task_runner),
+      policy_service, policy_connector, /*supervised_user_prefs=*/nullptr);
   return factory.Create(pref_registry.get());
 }
 
@@ -83,14 +90,28 @@
   // preference modifications (as applications are sand-boxed), it can use a
   // simple JsonPrefStore to store them (which is what PrefStoreManager uses
   // on platforms that do not track preference modifications).
+  scoped_refptr<JsonPrefStore> local_pref_store =
+      base::MakeRefCounted<JsonPrefStore>(
+          profile_path.Append(kPreferencesFilename),
+          std::unique_ptr<PrefFilter>(), pref_io_task_runner);
   sync_preferences::PrefServiceSyncableFactory factory;
-  PrepareFactory(&factory, profile_path.Append(kPreferencesFilename),
-                 pref_io_task_runner, policy_service, policy_connector,
+  PrepareFactory(&factory, local_pref_store, policy_service, policy_connector,
                  supervised_user_prefs);
   if (base::FeatureList::IsEnabled(syncer::kEnablePreferencesAccountStorage)) {
-    factory.SetAccountPrefStore(base::MakeRefCounted<JsonPrefStore>(
-        profile_path.Append(kAccountPreferencesFilename), nullptr,
-        pref_io_task_runner));
+    base::FilePath account_prefs_filepath =
+        profile_path.Append(kAccountPreferencesFilename);
+    if (base::FeatureList::IsEnabled(syncer::kMigrateAccountPrefs)) {
+      // Post task to remove the account preferences file. This is done on the
+      // IO thread.
+      pref_io_task_runner->PostTask(
+          FROM_HERE, base::BindOnce(IgnoreResult(&base::DeleteFile),
+                                    account_prefs_filepath));
+      factory.SetAccountPrefStore(base::MakeRefCounted<WrapWithPrefixPrefStore>(
+          local_pref_store, kAccountPreferencesPrefix));
+    } else {
+      factory.SetAccountPrefStore(base::MakeRefCounted<JsonPrefStore>(
+          account_prefs_filepath, nullptr, pref_io_task_runner));
+    }
   }
   factory.set_async(async);
   std::unique_ptr<sync_preferences::PrefServiceSyncable> pref_service =
diff --git a/ios/chrome/browser/prefs/model/ios_chrome_pref_service_factory_unittest.cc b/ios/chrome/browser/prefs/model/ios_chrome_pref_service_factory_unittest.cc
new file mode 100644
index 0000000..11e2105
--- /dev/null
+++ b/ios/chrome/browser/prefs/model/ios_chrome_pref_service_factory_unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/prefs/model/ios_chrome_pref_service_factory.h"
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/sync/base/features.h"
+#include "components/sync_preferences/pref_service_syncable.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class CreateProfilePrefsTestBase : public PlatformTest {
+ public:
+  CreateProfilePrefsTestBase()
+      : pref_registry_(
+            base::MakeRefCounted<user_prefs::PrefRegistrySyncable>()) {
+    EXPECT_TRUE(data_dir_.CreateUniqueTempDir());
+  }
+
+  std::unique_ptr<sync_preferences::PrefServiceSyncable> BuildPrefService() {
+    return CreateProfilePrefs(
+        data_dir_.GetPath(), task_environment_.GetMainThreadTaskRunner().get(),
+        pref_registry_, /*policy_service=*/nullptr,
+        /*policy_connector=*/nullptr, /*supervised_user_prefs=*/nullptr,
+        /*async=*/true);
+  }
+
+  base::FilePath AccountPreferencesFilePath() const {
+    return data_dir_.GetPath().Append(kAccountPreferencesFilename);
+  }
+
+ protected:
+  base::test::SingleThreadTaskEnvironment task_environment_;
+  base::ScopedTempDir data_dir_;
+  scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry_;
+};
+
+class CreateProfilePrefsTestWithMigrateAccountPrefsEnabled
+    : public CreateProfilePrefsTestBase {
+ public:
+  CreateProfilePrefsTestWithMigrateAccountPrefsEnabled()
+      : feature_list_(syncer::kMigrateAccountPrefs) {}
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_F(CreateProfilePrefsTestWithMigrateAccountPrefsEnabled,
+       ShouldRemoveAccountPrefsFile) {
+  // Simulate a pre-existing account preferences file.
+  ASSERT_TRUE(base::WriteFile(AccountPreferencesFilePath(), ""));
+
+  BuildPrefService();
+  // Wait for the posted task to delete the file finish.
+  base::RunLoop run_loop;
+  task_environment_.GetMainThreadTaskRunner()->PostTask(FROM_HERE,
+                                                        run_loop.QuitClosure());
+  run_loop.Run();
+
+  // Account prefs file should have been removed.
+  EXPECT_FALSE(base::PathExists(AccountPreferencesFilePath()));
+}
+
+}  // namespace
diff --git a/ios/chrome/browser/saved_tab_groups/model/ios_tab_group_sync_util.h b/ios/chrome/browser/saved_tab_groups/model/ios_tab_group_sync_util.h
index 3020e911..1c84447b 100644
--- a/ios/chrome/browser/saved_tab_groups/model/ios_tab_group_sync_util.h
+++ b/ios/chrome/browser/saved_tab_groups/model/ios_tab_group_sync_util.h
@@ -85,9 +85,9 @@
                       TabGroupSyncService* sync_service);
 
 // Returns the collabID of the given `tab_group` if it's shared.
-// Otherwise returns nil.
-NSString* GetTabGroupCollabID(const TabGroup* tab_group,
-                              TabGroupSyncService* sync_service);
+// Otherwise returns an empty collabID.
+CollaborationId GetTabGroupCollabID(const TabGroup* tab_group,
+                                    TabGroupSyncService* sync_service);
 
 }  // namespace utils
 }  // namespace tab_groups
diff --git a/ios/chrome/browser/saved_tab_groups/model/ios_tab_group_sync_util.mm b/ios/chrome/browser/saved_tab_groups/model/ios_tab_group_sync_util.mm
index 8490c06..90b8c85 100644
--- a/ios/chrome/browser/saved_tab_groups/model/ios_tab_group_sync_util.mm
+++ b/ios/chrome/browser/saved_tab_groups/model/ios_tab_group_sync_util.mm
@@ -301,17 +301,17 @@
   return shared;
 }
 
-NSString* GetTabGroupCollabID(const TabGroup* tab_group,
-                              TabGroupSyncService* sync_service) {
+CollaborationId GetTabGroupCollabID(const TabGroup* tab_group,
+                                    TabGroupSyncService* sync_service) {
   if (sync_service && tab_group) {
     std::optional<tab_groups::SavedTabGroup> saved_group =
         sync_service->GetGroup(tab_group->tab_group_id());
     if (saved_group.has_value() &&
         saved_group->collaboration_id().has_value()) {
-      return base::SysUTF8ToNSString(saved_group->collaboration_id()->value());
+      return saved_group->collaboration_id().value();
     }
   }
-  return nil;
+  return CollaborationId();
 }
 
 }  // namespace utils
diff --git a/ios/chrome/browser/saved_tab_groups/model/ios_tab_group_sync_util_unittest.mm b/ios/chrome/browser/saved_tab_groups/model/ios_tab_group_sync_util_unittest.mm
index 1bec4ff3..5870617 100644
--- a/ios/chrome/browser/saved_tab_groups/model/ios_tab_group_sync_util_unittest.mm
+++ b/ios/chrome/browser/saved_tab_groups/model/ios_tab_group_sync_util_unittest.mm
@@ -546,9 +546,9 @@
   EXPECT_CALL(*mock_service_, GetGroup(tab_group_id))
       .WillOnce(testing::Return(saved_group));
 
-  EXPECT_NSEQ(GetTabGroupCollabID(local_group, mock_service_),
-              @"collaboration");
-  EXPECT_NSEQ(GetTabGroupCollabID(local_group, nullptr), nil);
+  EXPECT_EQ(GetTabGroupCollabID(local_group, mock_service_).value(),
+            "collaboration");
+  EXPECT_EQ(GetTabGroupCollabID(local_group, nullptr).value(), "");
 }
 
 // Tests the `GetTabGroupCollabID` method with a non shared group.
@@ -564,9 +564,9 @@
   EXPECT_CALL(*mock_service_, GetGroup(tab_group_id))
       .WillOnce(testing::Return(saved_group));
 
-  EXPECT_NSNE(GetTabGroupCollabID(local_group, mock_service_),
-              @"collaboration");
-  EXPECT_NSEQ(GetTabGroupCollabID(local_group, nullptr), nil);
+  EXPECT_NE(GetTabGroupCollabID(local_group, mock_service_).value(),
+            "collaboration");
+  EXPECT_EQ(GetTabGroupCollabID(local_group, nullptr).value(), "");
 }
 
 }  // namespace utils
diff --git a/ios/chrome/browser/settings/ui_bundled/google_services/manage_sync_settings_egtest.mm b/ios/chrome/browser/settings/ui_bundled/google_services/manage_sync_settings_egtest.mm
index 5a0df05a..b5877c1 100644
--- a/ios/chrome/browser/settings/ui_bundled/google_services/manage_sync_settings_egtest.mm
+++ b/ios/chrome/browser/settings/ui_bundled/google_services/manage_sync_settings_egtest.mm
@@ -1569,7 +1569,13 @@
 
 // Tests the custom passphrase is remembered per account, kept across signout,
 // and cleared when account is removed from device.
-- (void)testRememberCustomPassphraseAfterSignout {
+// TODO(crbug.com/384646508): This test is flaky on the iPad simulator.
+#if TARGET_IPHONE_SIMULATOR
+#define MAYBE_testRememberCustomPassphraseAfterSignout FLAKY_testRememberCustomPassphraseAfterSignout
+#else
+#define MAYBE_testRememberCustomPassphraseAfterSignout testRememberCustomPassphraseAfterSignout
+#endif  // TARGET_IPHONE_SIMULATOR
+- (void)MAYBE_testRememberCustomPassphraseAfterSignout {
   // Enable custom passphrase.
   [ChromeEarlGrey addSyncPassphrase:kPassphrase];
   FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];
diff --git a/ios/chrome/browser/settings/ui_bundled/settings_egtest.mm b/ios/chrome/browser/settings/ui_bundled/settings_egtest.mm
index 0dbff5f..57f0548 100644
--- a/ios/chrome/browser/settings/ui_bundled/settings_egtest.mm
+++ b/ios/chrome/browser/settings/ui_bundled/settings_egtest.mm
@@ -340,14 +340,26 @@
 
 // Verifies that metrics reporting works properly under possible settings of the
 // preference kMetricsReportingEnabled.
-- (void)testMetricsReporting {
+// TODO(crbug.com/382632442): This test is failing on official builds.
+#if defined(OFFICIAL_BUILD)
+#define MAYBE_testMetricsReporting DISABLED_testMetricsReporting
+#else
+#define MAYBE_testMetricsReporting testMetricsReporting
+#endif
+- (void)MAYBE_testMetricsReporting {
   [self assertsMetricsPrefsForService:kMetrics];
 }
 
 // Verifies that crashpad reporting works properly under possible settings of
 // the preference `kMetricsReportingEnabled`.
 // NOTE: crashpad only allows uploading for non-first-launch runs.
-- (void)testCrashpadReporting {
+// TODO(crbug.com/382632442): This test is failing on official builds.
+#if defined(OFFICIAL_BUILD)
+#define MAYBE_testCrashpadReporting DISABLED_testCrashpadReporting
+#else
+#define MAYBE_testCrashpadReporting testCrashpadReporting
+#endif
+- (void)MAYBE_testCrashpadReporting {
   [self assertsMetricsPrefsForService:kCrashpad];
 }
 
diff --git a/ios/chrome/browser/shared/model/prefs/browser_prefs.mm b/ios/chrome/browser/shared/model/prefs/browser_prefs.mm
index 29a1689..83ce6240 100644
--- a/ios/chrome/browser/shared/model/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/shared/model/prefs/browser_prefs.mm
@@ -129,10 +129,6 @@
 
 namespace {
 
-// Deprecated 12/2023.
-const char kSigninLastAccounts[] = "ios.signin.last_accounts";
-const char kSigninLastAccountsMigrated[] = "ios.signin.last_accounts_migrated";
-
 // Deprecated 01/2024.
 const char kAppStoreRatingTotalDaysOnChromeKey[] =
     "AppStoreRatingTotalDaysOnChrome";
@@ -195,6 +191,10 @@
 // Deprecated 11/2024
 constexpr char kEnableDoNotTrackIos[] = "enable_do_not_track";
 
+// Deprecated 12/2024.
+inline constexpr char kPageContentCollectionEnabled[] =
+    "page_content_collection.enabled";
+
 // Helper function migrating the preference `pref_name` of type "int" from
 // `defaults` to `pref_service`.
 void MigrateIntegerPreferenceFromUserDefaults(std::string_view pref_name,
@@ -967,8 +967,6 @@
   registry->RegisterBooleanPref(prefs::kDetectUnitsEnabled, true);
 
   registry->RegisterTimePref(prefs::kLastSigninTimestamp, base::Time());
-  registry->RegisterListPref(kSigninLastAccounts);
-  registry->RegisterBooleanPref(kSigninLastAccountsMigrated, false);
 
   // Preferences related to Content Notifications.
   registry->RegisterTimePref(prefs::kNotificationsPromoLastDismissed,
@@ -1087,6 +1085,9 @@
   registry->RegisterBooleanPref(kEnableDoNotTrackIos, false);
 
   registry->RegisterIntegerPref(prefs::kChromeDataRegionSetting, 0);
+
+  // Deprecated 12/2024.
+  registry->RegisterBooleanPref(kPageContentCollectionEnabled, false);
 }
 
 // This method should be periodically pruned of year+ old migrations.
@@ -1151,10 +1152,6 @@
   NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
 
   // Added 12/2023.
-  prefs->ClearPref(kSigninLastAccounts);
-  prefs->ClearPref(kSigninLastAccountsMigrated);
-
-  // Added 12/2023.
   MigrateIntegerToTimePreferenceFromUserDefaults(kLastCookieDeletionDate, prefs,
                                                  defaults);
 
@@ -1280,6 +1277,9 @@
 
   // Added 11/2024
   prefs->ClearPref(kEnableDoNotTrackIos);
+
+  // Added 12/2024.
+  prefs->ClearPref(kPageContentCollectionEnabled);
 }
 
 void MigrateObsoleteUserDefault() {
diff --git a/ios/chrome/browser/snapshots/model/BUILD.gn b/ios/chrome/browser/snapshots/model/BUILD.gn
index cec46c9..19857376 100644
--- a/ios/chrome/browser/snapshots/model/BUILD.gn
+++ b/ios/chrome/browser/snapshots/model/BUILD.gn
@@ -154,4 +154,5 @@
     "features.mm",
   ]
   public_deps = [ "//base" ]
+  deps = [ "//ios/chrome/browser/shared/public/features" ]
 }
diff --git a/ios/chrome/browser/snapshots/model/features.h b/ios/chrome/browser/snapshots/model/features.h
index fde9c8d8..e2fe6a7 100644
--- a/ios/chrome/browser/snapshots/model/features.h
+++ b/ios/chrome/browser/snapshots/model/features.h
@@ -5,9 +5,24 @@
 #ifndef IOS_CHROME_BROWSER_SNAPSHOTS_MODEL_FEATURES_H_
 #define IOS_CHROME_BROWSER_SNAPSHOTS_MODEL_FEATURES_H_
 
+#ifdef __cplusplus
 #import "base/feature_list.h"
 
 // Feature flag to enable new snapshot system written in Swift.
 BASE_DECLARE_FEATURE(kSnapshotInSwift);
 
+// Feature flag to allow more elements that the LRU cache can hold.
+BASE_DECLARE_FEATURE(kLargeCapacityInSnapshotLRUCache);
+
+extern "C" {
+#endif  // extern "C"
+
+// Returns true if the kLargeCapacityInSnapshotLRUCache feature and the tab
+// group feature are enabled.
+bool IsLargeCapacityInSnapshotLRUCacheEnabled();
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
 #endif  // IOS_CHROME_BROWSER_SNAPSHOTS_MODEL_FEATURES_H_
diff --git a/ios/chrome/browser/snapshots/model/features.mm b/ios/chrome/browser/snapshots/model/features.mm
index 10908159..545e527c 100644
--- a/ios/chrome/browser/snapshots/model/features.mm
+++ b/ios/chrome/browser/snapshots/model/features.mm
@@ -4,6 +4,17 @@
 
 #import "ios/chrome/browser/snapshots/model/features.h"
 
+#import "ios/chrome/browser/shared/public/features/features.h"
+
 BASE_FEATURE(kSnapshotInSwift,
              "SnapshotInSwift",
              base::FEATURE_DISABLED_BY_DEFAULT);
+
+BASE_FEATURE(kLargeCapacityInSnapshotLRUCache,
+             "LargeCapacityInSnapshotLRUCache",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+bool IsLargeCapacityInSnapshotLRUCacheEnabled() {
+  return IsTabGroupInGridEnabled() &&
+         base::FeatureList::IsEnabled(kLargeCapacityInSnapshotLRUCache);
+}
diff --git a/ios/chrome/browser/snapshots/model/legacy_snapshot_storage.mm b/ios/chrome/browser/snapshots/model/legacy_snapshot_storage.mm
index e60939e..1944b51 100644
--- a/ios/chrome/browser/snapshots/model/legacy_snapshot_storage.mm
+++ b/ios/chrome/browser/snapshots/model/legacy_snapshot_storage.mm
@@ -27,12 +27,12 @@
 
 namespace {
 
-// Maximum size in number of elements that the LRU cache can hold before
+// Base size in number of elements that the LRU cache can hold before
 // starting to evict elements.
-const NSUInteger kLRUCacheMaxCapacity = 6;
+const NSUInteger kLRUCacheBaseCapacity = 6;
 
-// Maximum size in number of elements that the LRU cache can hold before
-// starting to evict elements when PinnedTabs feature is enabled.
+// Additional capacity of elements that the LRU cache can hold before starting
+// to evict elements when PinnedTabs feature is enabled.
 //
 // To calculate the cache size number we'll start with the assumption that
 // currently snapshot preloading feature "works fine". In the reality it might
@@ -41,7 +41,13 @@
 // used. Based on that kLRUCacheMaxCapacityForPinnedTabsEnabled is
 // kLRUCacheMaxCapacity which "works fine" + on average 4 more snapshots needed
 // for pinned tabs feature.
-const NSUInteger kLRUCacheMaxCapacityForPinnedTabsEnabled = 10;
+const NSUInteger kLRUCacheAdditionalCapacityForPinnedTabsEnabled = 4;
+
+// Additional capacity of elements that the LRU cache can hold before starting
+// to evict elements when the Tab Group feature is enabled.
+//
+// A tab group cell requests up to 7 snapshots from the first item.
+const NSUInteger kLRUCacheAdditionalCapacityForTabGroupEnabled = 7;
 
 }  // namespace
 
@@ -75,9 +81,13 @@
 - (instancetype)initWithStoragePath:(const base::FilePath&)storagePath
                          legacyPath:(const base::FilePath&)legacyPath {
   if ((self = [super init])) {
-    NSUInteger cacheSize = IsPinnedTabsEnabled()
-                               ? kLRUCacheMaxCapacityForPinnedTabsEnabled
-                               : kLRUCacheMaxCapacity;
+    NSUInteger cacheSize = kLRUCacheBaseCapacity;
+    if (IsPinnedTabsEnabled()) {
+      cacheSize += kLRUCacheAdditionalCapacityForPinnedTabsEnabled;
+    }
+    if (IsLargeCapacityInSnapshotLRUCacheEnabled()) {
+      cacheSize += kLRUCacheAdditionalCapacityForTabGroupEnabled;
+    }
     _lruCache = [[LegacySnapshotLRUCache alloc] initWithCacheSize:cacheSize];
 
     _fileManager =
diff --git a/ios/chrome/browser/snapshots/model/snapshot_storage.swift b/ios/chrome/browser/snapshots/model/snapshot_storage.swift
index 5efe829..3f35268 100644
--- a/ios/chrome/browser/snapshots/model/snapshot_storage.swift
+++ b/ios/chrome/browser/snapshots/model/snapshot_storage.swift
@@ -4,10 +4,10 @@
 
 import UIKit
 
-// Maximum size in number of elements that the LRU cache can hold before starting to evict elements.
-let kLRUCacheMaxCapacity = 6
+// Base size in number of elements that the LRU cache can hold before starting to evict elements.
+let kLRUCacheBaseCapacity = 6
 
-// Maximum size in number of elements that the LRU cache can hold before starting to evict elements
+// Additional capacity of elements that the LRU cache can hold before starting to evict elements
 // when PinnedTabs feature is enabled.
 //
 // To calculate the cache size number we'll start with the assumption that currently snapshot
@@ -16,7 +16,13 @@
 // snapshots to be used. Based on that kLRUCacheMaxCapacityForPinnedTabsEnabled is
 // kLRUCacheMaxCapacity which "works fine" + on average 4 more snapshots needed for pinned tabs
 // feature.
-let kLRUCacheMaxCapacityForPinnedTabsEnabled = 10
+let kLRUCacheAdditionalCapacityForPinnedTabsEnabled = 4
+
+// Additional capacity of elements that the LRU cache can hold before starting to evict elements
+// when the Tab Group feature is enabled.
+//
+// A tab group cell requests up to 7 snapshots from the first item.
+let kLRUCacheAdditionalCapacityForTabGroupEnabled = 7
 
 // A class providing an in-memory and on-disk storage of tab snapshots.
 // A snapshot is a full-screen image of the contents of the page at the current scroll offset and
@@ -48,13 +54,19 @@
   // TODO(crbug.com/40942167): Remove `legacyDirectoryUrl` when the storage for all users has been
   // migrated.
   init(storageDirectoryUrl: URL, legacyDirectoryUrl: URL?) {
-    // Use the different size of LRUCache when the pinned tabs feature is enabled.
-    // The pinned tabs feature is fully enabled on iPhone and disabled on iPad. The condition to
-    // determine the cache size should sync with IsPinnedTabsEnabled() in
-    // ios/chrome/browser/tabs/model/features.h.
-    self.lruCache = SnapshotLRUCache(
-      size: UIDevice.current.userInterfaceIdiom != .pad
-        ? kLRUCacheMaxCapacityForPinnedTabsEnabled : kLRUCacheMaxCapacity)
+    var cacheSize = kLRUCacheBaseCapacity
+    if UIDevice.current.userInterfaceIdiom != .pad {
+      // Add more capacity to LRUCache when the pinned tabs feature is enabled.
+      // The pinned tabs feature is fully enabled on iPhone and disabled on iPad. The condition to
+      // determine the cache size should sync with IsPinnedTabsEnabled() in
+      // ios/chrome/browser/tabs/model/features.h.
+      cacheSize += kLRUCacheAdditionalCapacityForPinnedTabsEnabled
+    }
+    if IsLargeCapacityInSnapshotLRUCacheEnabled() {
+      // Add more capacity to LRUCache when the feature flag is enabled. The feature depends on the tab group feature.
+      cacheSize += kLRUCacheAdditionalCapacityForTabGroupEnabled
+    }
+    self.lruCache = SnapshotLRUCache(size: cacheSize)
     self.fileManager = ImageFileManager(
       storageDirectoryUrl: storageDirectoryUrl, legacyDirectoryUrl: legacyDirectoryUrl)
     self.observers = []
diff --git a/ios/chrome/browser/snapshots/model/snapshot_swift_bridge.h b/ios/chrome/browser/snapshots/model/snapshot_swift_bridge.h
index 822bf717..2408506 100644
--- a/ios/chrome/browser/snapshots/model/snapshot_swift_bridge.h
+++ b/ios/chrome/browser/snapshots/model/snapshot_swift_bridge.h
@@ -10,6 +10,7 @@
 
 #import "ios/chrome/browser/shared/public/metrics/histogram_functions_bridge.h"
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util_bridge.h"
+#import "ios/chrome/browser/snapshots/model/features.h"
 #import "ios/chrome/browser/snapshots/model/snapshot_id_wrapper.h"
 #import "ios/chrome/browser/snapshots/model/snapshot_scale.h"
 #import "ios/chrome/browser/snapshots/model/web_state_snapshot_info.h"
diff --git a/ios/chrome/browser/sync/model/prefs/BUILD.gn b/ios/chrome/browser/sync/model/prefs/BUILD.gn
index fdb9bc27..73cde767 100644
--- a/ios/chrome/browser/sync/model/prefs/BUILD.gn
+++ b/ios/chrome/browser/sync/model/prefs/BUILD.gn
@@ -31,6 +31,7 @@
     "//ios/chrome/browser/signin/model:fake_system_identity",
     "//ios/chrome/browser/ui/authentication:eg_test_support+eg2",
     "//ios/chrome/test/earl_grey:eg_test_support+eg2",
+    "//ios/chrome/test/earl_grey:switches",
     "//ios/testing/earl_grey:eg_test_support+eg2",
     "//ios/web/public/test/http_server",
     "//net:test_support",
diff --git a/ios/chrome/browser/sync/model/prefs/sync_preferences_egtest.mm b/ios/chrome/browser/sync/model/prefs/sync_preferences_egtest.mm
index dd78166e..745ab0e 100644
--- a/ios/chrome/browser/sync/model/prefs/sync_preferences_egtest.mm
+++ b/ios/chrome/browser/sync/model/prefs/sync_preferences_egtest.mm
@@ -4,6 +4,7 @@
 
 #import <XCTest/XCTest.h>
 
+#import "base/files/file_util.h"
 #import "base/ios/ios_util.h"
 #import "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
@@ -17,7 +18,9 @@
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
+#import "ios/chrome/test/earl_grey/test_switches.h"
 #import "ios/chrome/test/earl_grey/web_http_server_chrome_test_case.h"
+#import "ios/testing/earl_grey/app_launch_manager.h"
 #import "ios/testing/earl_grey/earl_grey_test.h"
 #import "net/test/embedded_test_server/embedded_test_server.h"
 
@@ -171,3 +174,202 @@
 }
 
 @end
+
+@interface SyncPreferencesWithMigrateAccountPrefsBaseTestCase
+    : WebHttpServerChromeTestCase
+@end
+
+@implementation SyncPreferencesWithMigrateAccountPrefsBaseTestCase
+
+- (void)setUp {
+  [super setUp];
+  GREYAssertTrue(self.testServer->Start(), @"Server did not start.");
+  [ChromeEarlGrey clearFakeSyncServerData];
+}
+
+- (void)tearDownHelper {
+  [ChromeEarlGrey clearUserPrefWithName:kTestSyncablePref];
+  [ChromeEarlGrey clearFakeSyncServerData];
+  [super tearDownHelper];
+}
+
+- (void)restartWithMigrateAccountPrefsEnabled:(FakeSystemIdentity*)identity {
+  // Before restarting, ensure that the FakeServer has written all its pending
+  // state to disk.
+  [ChromeEarlGrey flushFakeSyncServerToDisk];
+  // Also make sure any pending prefs changes are written to disk.
+  [ChromeEarlGrey commitPendingUserPrefsWrite];
+
+  AppLaunchConfiguration config = [self appConfigurationForTestCase];
+  config.relaunch_policy = ForceRelaunchByCleanShutdown;
+  config.features_enabled.push_back(syncer::kMigrateAccountPrefs);
+  config.additional_args.push_back(base::StrCat({
+    "-", test_switches::kAddFakeIdentitiesAtStartup, "=",
+        [FakeSystemIdentity encodeIdentitiesToBase64:@[ identity ]]
+  }));
+  [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
+}
+
+- (void)restartWithMigrateAccountPrefsDisabled:(FakeSystemIdentity*)identity {
+  // Before restarting, ensure that the FakeServer has written all its pending
+  // state to disk.
+  [ChromeEarlGrey flushFakeSyncServerToDisk];
+  // Also make sure any pending prefs changes are written to disk.
+  [ChromeEarlGrey commitPendingUserPrefsWrite];
+
+  AppLaunchConfiguration config = [self appConfigurationForTestCase];
+  config.relaunch_policy = ForceRelaunchByCleanShutdown;
+  config.features_disabled.push_back(syncer::kMigrateAccountPrefs);
+  config.additional_args.push_back(base::StrCat({
+    "-", test_switches::kAddFakeIdentitiesAtStartup, "=",
+        [FakeSystemIdentity encodeIdentitiesToBase64:@[ identity ]]
+  }));
+  [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
+}
+
+- (void)setTestSyncablePrefValueTo:(int)pref_value
+                   forFakeIdentity:(FakeSystemIdentity*)fakeIdentity {
+  // Sign in and set the pref value.
+  [SigninEarlGrey signinWithFakeIdentity:fakeIdentity];
+  [ChromeEarlGrey
+      waitForSyncTransportStateActiveWithTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey setIntegerValue:pref_value forUserPref:kTestSyncablePref];
+  WaitForTestPreferenceOnFakeServer(true);
+  [SigninEarlGrey signOut];
+
+  // Remove from local store.
+  [ChromeEarlGrey clearUserPrefWithName:kTestSyncablePref];
+}
+
+@end
+
+@interface SyncPreferencesWithMigrateAccountPrefsEnabledTestCase
+    : SyncPreferencesWithMigrateAccountPrefsBaseTestCase
+@end
+
+@implementation SyncPreferencesWithMigrateAccountPrefsEnabledTestCase
+
+- (AppLaunchConfiguration)appConfigurationForTestCase {
+  AppLaunchConfiguration config = [super appConfigurationForTestCase];
+  config.features_enabled.push_back(syncer::kMigrateAccountPrefs);
+  return config;
+}
+
+#pragma mark - SyncPreferencesWithMigrateAccountPrefsEnabledTestCase Tests
+
+- (void)testAccountPrefsDownloadedWithInitialSync {
+  FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];
+  // Set a pref value of `kTestPrefValue1` in account.
+  [self setTestSyncablePrefValueTo:kTestPrefValue1
+                   forFakeIdentity:fakeIdentity];
+
+  [self restartWithMigrateAccountPrefsEnabled:fakeIdentity];
+
+  // Sign in and sync.
+  WaitForTestPreferenceOnFakeServer(true);
+  [SigninEarlGrey signinWithFakeIdentity:fakeIdentity];
+  WaitForPreferenceValue(kTestPrefValue1);
+
+  // Sign out and validate that the pref is not set locally.
+  [SigninEarlGrey signOut];
+  GREYAssertNotEqual([ChromeEarlGrey userIntegerPref:kTestSyncablePref],
+                     kTestPrefValue1, @"Incorrect local pref value.");
+}
+
+- (void)testAccountPrefsPersisted {
+  FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];
+  // Set a pref value of `kTestPrefValue1` in account.
+  [self setTestSyncablePrefValueTo:kTestPrefValue1
+                   forFakeIdentity:fakeIdentity];
+
+  // Sign in and sync.
+  [SigninEarlGrey signinWithFakeIdentity:fakeIdentity];
+  WaitForPreferenceValue(kTestPrefValue1);
+
+  // Restart.
+  [self restartWithMigrateAccountPrefsEnabled:fakeIdentity];
+  GREYAssertEqual([ChromeEarlGrey userIntegerPref:kTestSyncablePref],
+                  kTestPrefValue1, @"Incorrect local pref value.");
+}
+
+- (void)testDisablingFlag {
+  FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];
+
+  // Set a pref value of `kTestPrefValue1` in account.
+  [self setTestSyncablePrefValueTo:kTestPrefValue1
+                   forFakeIdentity:fakeIdentity];
+
+  // Sign in and sync.
+  [SigninEarlGrey signinWithFakeIdentity:fakeIdentity];
+  WaitForPreferenceValue(kTestPrefValue1);
+
+  // Restart with MigrateAccountPrefs flag disabled.
+  [self restartWithMigrateAccountPrefsDisabled:fakeIdentity];
+  GREYAssertEqual([ChromeEarlGrey userIntegerPref:kTestSyncablePref],
+                  kTestPrefValue1, @"Incorrect local pref value.");
+
+  // Sign out and validate that the pref is not set locally.
+  [SigninEarlGrey signOut];
+  GREYAssertNotEqual([ChromeEarlGrey userIntegerPref:kTestSyncablePref],
+                     kTestPrefValue1, @"Incorrect local pref value.");
+}
+
+@end
+
+@interface SyncPreferencesWithMigrateAccountPrefsDisabledTestCase
+    : SyncPreferencesWithMigrateAccountPrefsBaseTestCase
+@end
+
+@implementation SyncPreferencesWithMigrateAccountPrefsDisabledTestCase
+
+- (AppLaunchConfiguration)appConfigurationForTestCase {
+  AppLaunchConfiguration config = [super appConfigurationForTestCase];
+  config.features_disabled.push_back(syncer::kMigrateAccountPrefs);
+  return config;
+}
+
+#pragma mark - SyncPreferencesWithMigrateAccountPrefsDisabledTestCase Tests
+
+- (void)testEnablingFlag {
+  FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];
+  // Set a pref value of `kTestPrefValue1` in account.
+  [self setTestSyncablePrefValueTo:kTestPrefValue1
+                   forFakeIdentity:fakeIdentity];
+
+  // Sign in and sync.
+  [SigninEarlGrey signinWithFakeIdentity:fakeIdentity];
+  WaitForPreferenceValue(kTestPrefValue1);
+
+  // Restart with MigrateAccountPrefs flag enabled.
+  [self restartWithMigrateAccountPrefsEnabled:fakeIdentity];
+  GREYAssertEqual([ChromeEarlGrey userIntegerPref:kTestSyncablePref],
+                  kTestPrefValue1, @"Incorrect local pref value.");
+
+  // Sign out and validate that the pref is not set locally.
+  [SigninEarlGrey signOut];
+  GREYAssertNotEqual([ChromeEarlGrey userIntegerPref:kTestSyncablePref],
+                     kTestPrefValue1, @"Incorrect local pref value.");
+}
+
+- (void)testAccountPrefsDownloadedFromSyncMetadataIfFlagEnabled {
+  FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];
+  // Set a pref value of `kTestPrefValue1` in account.
+  [self setTestSyncablePrefValueTo:kTestPrefValue1
+                   forFakeIdentity:fakeIdentity];
+
+  // Sign in and sync.
+  [SigninEarlGrey signinWithFakeIdentity:fakeIdentity];
+  WaitForPreferenceValue(kTestPrefValue1);
+
+  // Restart with MigrateAccountPrefs flag enabled.
+  [self restartWithMigrateAccountPrefsEnabled:fakeIdentity];
+  GREYAssertEqual([ChromeEarlGrey userIntegerPref:kTestSyncablePref],
+                  kTestPrefValue1, @"Incorrect local pref value.");
+
+  // Sign out and validate that the pref is not set locally.
+  [SigninEarlGrey signOut];
+  GREYAssertNotEqual([ChromeEarlGrey userIntegerPref:kTestSyncablePref],
+                     kTestPrefValue1, @"Incorrect local pref value.");
+}
+
+@end
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_coordinator.mm
index 9570b7c0d..f336cb9 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_coordinator.mm
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_coordinator.mm
@@ -1572,15 +1572,15 @@
       tab_groups::TabGroupSyncServiceFactory::GetForProfile(profile);
   ShareKitService* shareKitService =
       ShareKitServiceFactory::GetForProfile(profile);
-  NSString* collabID =
+  tab_groups::CollaborationId collabID =
       tab_groups::utils::GetTabGroupCollabID(group.get(), syncService);
-  if (!shareKitService || !collabID) {
+  if (!shareKitService || collabID.value().empty()) {
     return;
   }
   ShareKitManageConfiguration* config =
       [[ShareKitManageConfiguration alloc] init];
   config.baseViewController = self.baseViewController;
-  config.collabID = collabID;
+  config.collabID = base::SysUTF8ToNSString(collabID.value());
   config.applicationHandler = HandlerForProtocol(
       self.regularBrowser->GetCommandDispatcher(), ApplicationCommands);
   shareKitService->ManageTabGroup(config);
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/BUILD.gn b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/BUILD.gn
index 6a67ab1..74b06e0 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/BUILD.gn
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/BUILD.gn
@@ -62,6 +62,7 @@
     "//ios/chrome/browser/tab_switcher/ui_bundled/tab_grid:tab_grid_activity_observer",
     "//ios/chrome/browser/tab_switcher/ui_bundled/tab_grid:tab_grid_idle_status_handler",
     "//ios/chrome/browser/tab_switcher/ui_bundled/tab_grid:tab_grid_page_mutator",
+    "//ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid:activity_label_view",
     "//ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid:grid_item_identifier",
     "//ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid:grid_mediator",
     "//ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid:grid_toolbars_mutator",
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/recent_activity_mediator.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/recent_activity_mediator.mm
index 6066d340..8f1ebc57 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/recent_activity_mediator.mm
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/recent_activity_mediator.mm
@@ -93,10 +93,9 @@
 // Creates recent activity logs and passes them to the consumer.
 - (void)populateItemsFromService {
   collaboration::messaging::ActivityLogQueryParams params;
-  NSString* collabID =
+  tab_groups::CollaborationId collabID =
       tab_groups::utils::GetTabGroupCollabID(_tabGroup.get(), _syncService);
-  params.collaboration_id =
-      data_sharing::GroupId(base::SysNSStringToUTF8(collabID));
+  params.collaboration_id = data_sharing::GroupId(collabID.value());
 
   NSMutableArray<RecentActivityLogItem*>* items = [[NSMutableArray alloc] init];
 
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_coordinator.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_coordinator.mm
index 8ebfe16..1858cce2 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_coordinator.mm
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_coordinator.mm
@@ -11,6 +11,7 @@
 #import "components/collaboration/public/collaboration_service.h"
 #import "components/saved_tab_groups/public/saved_tab_group.h"
 #import "ios/chrome/browser/collaboration/model/collaboration_service_factory.h"
+#import "ios/chrome/browser/collaboration/model/messaging/messaging_backend_service_factory.h"
 #import "ios/chrome/browser/saved_tab_groups/model/ios_tab_group_sync_util.h"
 #import "ios/chrome/browser/saved_tab_groups/model/tab_group_sync_service_factory.h"
 #import "ios/chrome/browser/share_kit/model/share_kit_face_pile_configuration.h"
@@ -100,6 +101,9 @@
       ShareKitServiceFactory::GetForProfile(profile);
   collaboration::CollaborationService* collaborationService =
       collaboration::CollaborationServiceFactory::GetForProfile(profile);
+  collaboration::messaging::MessagingBackendService* messagingService =
+      collaboration::messaging::MessagingBackendServiceFactory::GetForProfile(
+          profile);
 
   _mediator = [[TabGroupMediator alloc]
       initWithWebStateList:browser->GetWebStateList()
@@ -109,7 +113,8 @@
                   tabGroup:_tabGroup->GetWeakPtr()
                   consumer:_viewController
               gridConsumer:_viewController.gridViewController
-                modeHolder:self.modeHolder];
+                modeHolder:self.modeHolder
+          messagingService:messagingService];
   _mediator.browser = browser;
   _mediator.tabGroupsHandler = HandlerForProtocol(
       self.browser->GetCommandDispatcher(), TabGroupsCommands);
@@ -360,9 +365,9 @@
       tab_groups::TabGroupSyncServiceFactory::GetForProfile(
           self.browser->GetProfile());
 
-  NSString* savedCollabID =
+  tab_groups::CollaborationId savedCollabID =
       tab_groups::utils::GetTabGroupCollabID(_tabGroup, syncService);
-  if (savedCollabID) {
+  if (!savedCollabID.value().empty()) {
     [self manageGroup:savedCollabID];
   }
   [self shareGroup];
@@ -395,16 +400,19 @@
 }
 
 // Manage the group with `collabID`.
-- (void)manageGroup:(NSString*)collabID {
+- (void)manageGroup:(tab_groups::CollaborationId)collabID {
   ShareKitService* shareKitService =
       ShareKitServiceFactory::GetForProfile(self.browser->GetProfile());
-  if (!collabID || !shareKitService) {
+  if (collabID.value().empty() || !shareKitService) {
     return;
   }
+
+  NSString* collabIDString = base::SysUTF8ToNSString(collabID.value());
+
   ShareKitManageConfiguration* config =
       [[ShareKitManageConfiguration alloc] init];
   config.baseViewController = self.baseViewController;
-  config.collabID = collabID;
+  config.collabID = collabIDString;
   config.applicationHandler = HandlerForProtocol(
       self.browser->GetCommandDispatcher(), ApplicationCommands);
   shareKitService->ManageTabGroup(config);
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_mediator.h b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_mediator.h
index f50e717e..d4adf58 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_mediator.h
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_mediator.h
@@ -13,6 +13,9 @@
 
 namespace collaboration {
 class CollaborationService;
+namespace messaging {
+class MessagingBackendService;
+}  // namespace messaging
 }  // namespace collaboration
 
 namespace tab_groups {
@@ -30,16 +33,18 @@
 // Tab group mediator in charge to handle model update for one group.
 @interface TabGroupMediator : BaseGridMediator <TabGroupMutator>
 
-- (instancetype)initWithWebStateList:(WebStateList*)webStateList
-                 tabGroupSyncService:
-                     (tab_groups::TabGroupSyncService*)tabGroupSyncService
-                     shareKitService:(ShareKitService*)shareKitService
-                collaborationService:
-                    (collaboration::CollaborationService*)collaborationService
-                            tabGroup:(base::WeakPtr<const TabGroup>)tabGroup
-                            consumer:(id<TabGroupConsumer>)consumer
-                        gridConsumer:(id<TabCollectionConsumer>)gridConsumer
-                          modeHolder:(TabGridModeHolder*)modeHolder;
+- (instancetype)
+    initWithWebStateList:(WebStateList*)webStateList
+     tabGroupSyncService:(tab_groups::TabGroupSyncService*)tabGroupSyncService
+         shareKitService:(ShareKitService*)shareKitService
+    collaborationService:
+        (collaboration::CollaborationService*)collaborationService
+                tabGroup:(base::WeakPtr<const TabGroup>)tabGroup
+                consumer:(id<TabGroupConsumer>)consumer
+            gridConsumer:(id<TabCollectionConsumer>)gridConsumer
+              modeHolder:(TabGridModeHolder*)modeHolder
+        messagingService:(collaboration::messaging::MessagingBackendService*)
+                             messagingService;
 
 @end
 
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_mediator.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_mediator.mm
index 32e6f81..5be5de2 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_mediator.mm
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_mediator.mm
@@ -12,10 +12,14 @@
 #import "base/scoped_observation.h"
 #import "base/strings/sys_string_conversions.h"
 #import "components/collaboration/public/collaboration_service.h"
+#import "components/collaboration/public/messaging/message.h"
+#import "components/collaboration/public/messaging/messaging_backend_service.h"
+#import "components/data_sharing/public/group_data.h"
 #import "ios/chrome/browser/collaboration/model/features.h"
 #import "ios/chrome/browser/drag_and_drop/model/drag_item_util.h"
 #import "ios/chrome/browser/saved_tab_groups/model/ios_tab_group_sync_util.h"
 #import "ios/chrome/browser/saved_tab_groups/model/tab_group_sync_service_factory.h"
+#import "ios/chrome/browser/share_kit/model/share_kit_avatar_configuration.h"
 #import "ios/chrome/browser/share_kit/model/share_kit_face_pile_configuration.h"
 #import "ios/chrome/browser/share_kit/model/share_kit_service.h"
 #import "ios/chrome/browser/shared/model/browser/browser.h"
@@ -29,6 +33,7 @@
 #import "ios/chrome/browser/shared/public/features/features.h"
 #import "ios/chrome/browser/tab_switcher/ui_bundled/tab_collection_consumer.h"
 #import "ios/chrome/browser/tab_switcher/ui_bundled/tab_collection_drag_drop_metrics.h"
+#import "ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/activity_label_data.h"
 #import "ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/grid_item_identifier.h"
 #import "ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/grid_utils.h"
 #import "ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_idle_status_handler.h"
@@ -48,6 +53,8 @@
 namespace {
 // The preferred size in points for the avatar icons.
 constexpr CGFloat kFacePileAvatarSize = 24;
+// The preferred size in points for the avatar icon in the activity label.
+constexpr CGFloat kActivityLabelAvatarSize = 16;
 }  // namespace
 
 @interface TabGroupMediator () <TabGroupSyncServiceObserverDelegate>
@@ -67,18 +74,26 @@
   __weak id<TabGroupConsumer> _groupConsumer;
   // Current group.
   base::WeakPtr<const TabGroup> _tabGroup;
+  // A service to get activity messages for a shared tab group.
+  raw_ptr<collaboration::messaging::MessagingBackendService> _messagingService;
+  // A map of a tab ID and a message to indicate that a tab should display a
+  // chip on its cell.
+  std::map<tab_groups::LocalTabID, collaboration::messaging::PersistentMessage>
+      _dirtyTabs;
 }
 
-- (instancetype)initWithWebStateList:(WebStateList*)webStateList
-                 tabGroupSyncService:
-                     (tab_groups::TabGroupSyncService*)tabGroupSyncService
-                     shareKitService:(ShareKitService*)shareKitService
-                collaborationService:
-                    (collaboration::CollaborationService*)collaborationService
-                            tabGroup:(base::WeakPtr<const TabGroup>)tabGroup
-                            consumer:(id<TabGroupConsumer>)groupConsumer
-                        gridConsumer:(id<TabCollectionConsumer>)gridConsumer
-                          modeHolder:(TabGridModeHolder*)modeHolder {
+- (instancetype)
+    initWithWebStateList:(WebStateList*)webStateList
+     tabGroupSyncService:(tab_groups::TabGroupSyncService*)tabGroupSyncService
+         shareKitService:(ShareKitService*)shareKitService
+    collaborationService:
+        (collaboration::CollaborationService*)collaborationService
+                tabGroup:(base::WeakPtr<const TabGroup>)tabGroup
+                consumer:(id<TabGroupConsumer>)groupConsumer
+            gridConsumer:(id<TabCollectionConsumer>)gridConsumer
+              modeHolder:(TabGridModeHolder*)modeHolder
+        messagingService:(collaboration::messaging::MessagingBackendService*)
+                             messagingService {
   CHECK(IsTabGroupInGridEnabled())
       << "You should not be able to create a tab group mediator outside the "
          "Tab Groups experiment.";
@@ -109,6 +124,11 @@
     [_groupConsumer setGroupTitle:tabGroup->GetTitle()];
     [_groupConsumer setGroupColor:tabGroup->GetColor()];
 
+    // TODO(crbug.com/375594684): Start observing the messaging backend service
+    // and update _dirtyTabs.
+    _messagingService = messagingService;
+    [self fetchMessagesForChip];
+
     [self updateFacePileUI];
     [self populateConsumerItems];
   }
@@ -295,9 +315,47 @@
 // Overrides the parent to return the data if there is a new message for a tab
 // in a group.
 - (ActivityLabelData*)activityLabelDataForTab:(web::WebStateID)webStateID {
-  // TODO(crbug.com/375594458): return ActivityLabelData with the string "Added"
-  // or "Changed" and the user icon view.
-  return nil;
+  if (!_dirtyTabs.contains(webStateID.identifier())) {
+    return nil;
+  }
+
+  ActivityLabelData* data = [[ActivityLabelData alloc] init];
+
+  collaboration::messaging::PersistentMessage message =
+      _dirtyTabs[webStateID.identifier()];
+  switch (message.collaboration_event) {
+    case collaboration::messaging::CollaborationEvent::TAB_ADDED:
+      // TODO(crbug.com/371113934): Set the string "Added" to the
+      // data.labelString.
+      break;
+    case collaboration::messaging::CollaborationEvent::TAB_UPDATED:
+      // TODO(crbug.com/371113934): Set the string "Changed" to the
+      // data.labelString.
+      break;
+    default:
+      // Do not show any labels for other activities.
+      return nil;
+  }
+
+  if (!_shareKitService->IsSupported() ||
+      !message.attribution.triggering_user.has_value()) {
+    return nil;
+  }
+
+  ShareKitAvatarConfiguration* config =
+      [[ShareKitAvatarConfiguration alloc] init];
+  data_sharing::GroupMember user = message.attribution.triggering_user.value();
+  config.avatarUrl =
+      [NSURL URLWithString:base::SysUTF8ToNSString(user.avatar_url.spec())];
+  // Use email intead when the display name is empty.
+  config.displayName = user.display_name.empty()
+                           ? base::SysUTF8ToNSString(user.email)
+                           : base::SysUTF8ToNSString(user.display_name);
+  config.avatarSize =
+      CGSizeMake(kActivityLabelAvatarSize, kActivityLabelAvatarSize);
+  data.avatarPrimitive = _shareKitService->AvatarImage(config);
+
+  return data;
 }
 
 #pragma mark - TabCollectionDragDropHandler override
@@ -530,9 +588,10 @@
     return;
   }
 
-  NSString* savedCollabID = tab_groups::utils::GetTabGroupCollabID(
-      _tabGroup.get(), _tabGroupSyncService);
-  BOOL isShared = savedCollabID != nil;
+  tab_groups::CollaborationId savedCollabID =
+      tab_groups::utils::GetTabGroupCollabID(_tabGroup.get(),
+                                             _tabGroupSyncService);
+  BOOL isShared = !savedCollabID.value().empty();
   [_groupConsumer setGroupShared:isShared];
 
   // Prevent the face pile from being set up for tab groups that are not shared
@@ -545,7 +604,7 @@
   // Configure the face pile.
   ShareKitFacePileConfiguration* config =
       [[ShareKitFacePileConfiguration alloc] init];
-  config.collabID = savedCollabID;
+  config.collabID = base::SysUTF8ToNSString(savedCollabID.value());
   config.showsEmptyState = YES;
   config.avatarSize = kFacePileAvatarSize;
   [_groupConsumer setFacePileViewController:_shareKitService->FacePile(config)];
@@ -567,4 +626,27 @@
       selectedItemIdentifier:[self activeIdentifier]];
 }
 
+// Gets messages to indicate that a tab should display a chip on its cell.
+- (void)fetchMessagesForChip {
+  if (!_tabGroup || !_messagingService || !_messagingService->IsInitialized()) {
+    return;
+  }
+
+  std::vector<collaboration::messaging::PersistentMessage> messages =
+      _messagingService->GetMessagesForGroup(
+          _tabGroup->tab_group_id(),
+          collaboration::messaging::PersistentNotificationType::CHIP);
+
+  for (auto& message : messages) {
+    if (!message.attribution.tab_metadata.has_value()) {
+      continue;
+    }
+    auto tab_data = message.attribution.tab_metadata.value();
+    if (!tab_data.local_tab_id.has_value()) {
+      continue;
+    }
+    _dirtyTabs[tab_data.local_tab_id.value()] = message;
+  }
+}
+
 @end
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_mediator_unittest.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_mediator_unittest.mm
index b9c5204..55e81a4 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_mediator_unittest.mm
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_mediator_unittest.mm
@@ -107,7 +107,8 @@
                     tabGroup:tab_group_->GetWeakPtr()
                     consumer:tab_group_consumer_
                 gridConsumer:consumer_
-                  modeHolder:mode_holder_];
+                  modeHolder:mode_holder_
+            messagingService:nil];
     mediator_.browser = browser_.get();
   }
 
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_strip/coordinator/tab_strip_coordinator.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_strip/coordinator/tab_strip_coordinator.mm
index 7d473b52..383838e3 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_strip/coordinator/tab_strip_coordinator.mm
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_strip/coordinator/tab_strip_coordinator.mm
@@ -314,15 +314,15 @@
       tab_groups::TabGroupSyncServiceFactory::GetForProfile(profile);
   ShareKitService* shareKitService =
       ShareKitServiceFactory::GetForProfile(profile);
-  NSString* collabID =
+  tab_groups::CollaborationId collabID =
       tab_groups::utils::GetTabGroupCollabID(group.get(), syncService);
-  if (!shareKitService || !collabID) {
+  if (!shareKitService || collabID.value().empty()) {
     return;
   }
   ShareKitManageConfiguration* config =
       [[ShareKitManageConfiguration alloc] init];
   config.baseViewController = self.baseViewController;
-  config.collabID = collabID;
+  config.collabID = base::SysUTF8ToNSString(collabID.value());
   config.applicationHandler = HandlerForProtocol(
       self.browser->GetCommandDispatcher(), ApplicationCommands);
   shareKitService->ManageTabGroup(config);
diff --git a/ios/chrome/browser/tabs/model/ios_chrome_local_session_event_router.h b/ios/chrome/browser/tabs/model/ios_chrome_local_session_event_router.h
index e1b68d45..b648772 100644
--- a/ios/chrome/browser/tabs/model/ios_chrome_local_session_event_router.h
+++ b/ios/chrome/browser/tabs/model/ios_chrome_local_session_event_router.h
@@ -12,11 +12,11 @@
 #include "base/memory/raw_ptr.h"
 #include "components/sync/model/syncable_service.h"
 #include "components/sync_sessions/local_session_event_router.h"
-#include "ios/chrome/browser/shared/model/web_state_list/web_state_list_observer.h"
-#include "ios/web/public/web_state_observer.h"
 
-class AllWebStateListObservationRegistrar;
 class BrowserList;
+namespace web {
+class WebState;
+}
 
 namespace sync_sessions {
 class SyncSessionsClient;
@@ -45,36 +45,8 @@
   void Stop() override;
 
  private:
-  // Observer implementation for each profile.
-  class Observer : public WebStateListObserver, public web::WebStateObserver {
-   public:
-    explicit Observer(IOSChromeLocalSessionEventRouter* session_router);
-    Observer(const Observer&) = delete;
-    Observer& operator=(const Observer&) = delete;
-    ~Observer() override;
-
-   private:
-    // WebStateListObserver:
-    void WebStateListDidChange(WebStateList* web_state_list,
-                               const WebStateListChange& change,
-                               const WebStateListStatus& status) override;
-    void WillBeginBatchOperation(WebStateList* web_state_list) override;
-    void BatchOperationEnded(WebStateList* web_state_list) override;
-
-    // web::WebStateObserver:
-    void TitleWasSet(web::WebState* web_state) override;
-    void DidFinishNavigation(
-        web::WebState* web_state,
-        web::NavigationContext* navigation_context) override;
-    void PageLoaded(
-        web::WebState* web_state,
-        web::PageLoadCompletionStatus load_completion_status) override;
-    void WasShown(web::WebState* web_state) override;
-    void DidChangeBackForwardState(web::WebState* web_state) override;
-    void WebStateDestroyed(web::WebState* web_state) override;
-
-    raw_ptr<IOSChromeLocalSessionEventRouter> router_;
-  };
+  // Observer implementation for all Browsers.
+  class Observer;
 
   // Called before the Batch operation starts for a web state list.
   void OnSessionEventStarting();
@@ -88,9 +60,8 @@
   // Called when a `web_state` is closed.
   void OnWebStateClosed();
 
-  // Observation registrar for the associated browser list; owns an instance
-  // of IOSChromeLocalSessionEventRouter::Observer.
-  std::unique_ptr<AllWebStateListObservationRegistrar> const registrar_;
+  // Observer.
+  std::unique_ptr<Observer> const observer_;
 
   raw_ptr<sync_sessions::LocalSessionEventHandler> handler_ = nullptr;
   const raw_ptr<sync_sessions::SyncSessionsClient> sessions_client_;
diff --git a/ios/chrome/browser/tabs/model/ios_chrome_local_session_event_router.mm b/ios/chrome/browser/tabs/model/ios_chrome_local_session_event_router.mm
index b85d1f5..d270f65 100644
--- a/ios/chrome/browser/tabs/model/ios_chrome_local_session_event_router.mm
+++ b/ios/chrome/browser/tabs/model/ios_chrome_local_session_event_router.mm
@@ -8,17 +8,22 @@
 
 #import "base/check.h"
 #import "base/functional/bind.h"
+#import "base/scoped_multi_source_observation.h"
+#import "base/scoped_observation.h"
 #import "components/history/core/browser/history_service.h"
 #import "components/keyed_service/core/service_access_type.h"
 #import "components/sync/base/features.h"
 #import "components/sync_sessions/sync_sessions_client.h"
 #import "components/sync_sessions/synced_tab_delegate.h"
 #import "ios/chrome/browser/history/model/history_service_factory.h"
-#import "ios/chrome/browser/shared/model/browser/all_web_state_list_observation_registrar.h"
+#import "ios/chrome/browser/shared/model/browser/browser.h"
 #import "ios/chrome/browser/shared/model/browser/browser_list.h"
+#import "ios/chrome/browser/shared/model/browser/browser_list_observer.h"
 #import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
+#import "ios/chrome/browser/shared/model/web_state_list/web_state_list_observer.h"
 #import "ios/chrome/browser/sync/model/glue/sync_start_util.h"
 #import "ios/chrome/browser/tabs/model/ios_chrome_synced_tab_delegate.h"
+#import "ios/web/public/web_state_observer.h"
 
 namespace {
 
@@ -31,28 +36,126 @@
 
 }  // namespace
 
-IOSChromeLocalSessionEventRouter::IOSChromeLocalSessionEventRouter(
-    BrowserList* browser_list,
-    sync_sessions::SyncSessionsClient* sessions_client,
-    const syncer::SyncableService::StartSyncFlare& flare)
-    : registrar_(std::make_unique<AllWebStateListObservationRegistrar>(
-          browser_list,
-          std::make_unique<Observer>(this),
-          AllWebStateListObservationRegistrar::Mode::REGULAR)),
-      sessions_client_(sessions_client),
-      flare_(flare) {
-  DCHECK(sessions_client_);
-}
+#pragma mark - IOSChromeLocalSessionEventRouter::Observer
 
-IOSChromeLocalSessionEventRouter::~IOSChromeLocalSessionEventRouter() {}
+class IOSChromeLocalSessionEventRouter::Observer
+    : public BrowserListObserver,
+      public WebStateListObserver,
+      public web::WebStateObserver {
+ public:
+  explicit Observer(IOSChromeLocalSessionEventRouter* session_router);
+  ~Observer() override = default;
+
+  void Start(BrowserList* browser_list);
+
+ private:
+  // BrowserListObserver:
+  void OnBrowserAdded(const BrowserList* browser_list,
+                      Browser* browser) override;
+  void OnBrowserRemoved(const BrowserList* browser_list,
+                        Browser* browser) override;
+  void OnBrowserListShutdown(BrowserList* browser_list) override;
+
+  // WebStateListObserver:
+  void WebStateListDidChange(WebStateList* web_state_list,
+                             const WebStateListChange& change,
+                             const WebStateListStatus& status) override;
+  void WillBeginBatchOperation(WebStateList* web_state_list) override;
+  void BatchOperationEnded(WebStateList* web_state_list) override;
+
+  // web::WebStateObserver:
+  void TitleWasSet(web::WebState* web_state) override;
+  void DidFinishNavigation(web::WebState* web_state,
+                           web::NavigationContext* navigation_context) override;
+  void PageLoaded(
+      web::WebState* web_state,
+      web::PageLoadCompletionStatus load_completion_status) override;
+  void WasShown(web::WebState* web_state) override;
+  void DidChangeBackForwardState(web::WebState* web_state) override;
+  void WebStateDestroyed(web::WebState* web_state) override;
+
+  raw_ptr<IOSChromeLocalSessionEventRouter> router_;
+
+  // Scoped observations.
+  base::ScopedObservation<BrowserList, BrowserListObserver>
+      browser_list_observation_{this};
+  base::ScopedMultiSourceObservation<WebStateList, WebStateListObserver>
+      web_state_list_observations_{this};
+  base::ScopedMultiSourceObservation<web::WebState, web::WebStateObserver>
+      web_state_observations_{this};
+};
 
 IOSChromeLocalSessionEventRouter::Observer::Observer(
     IOSChromeLocalSessionEventRouter* session_router)
     : router_(session_router) {}
 
-IOSChromeLocalSessionEventRouter::Observer::~Observer() {}
+void IOSChromeLocalSessionEventRouter::Observer::Start(
+    BrowserList* browser_list) {
+  browser_list_observation_.Observe(browser_list);
 
-#pragma mark - WebStateListObserver
+  // The WebStateList may not be empty when the Observer is created, so
+  // start observing any pre-existing Browsers.
+  for (Browser* browser :
+       browser_list->BrowsersOfType(BrowserList::BrowserType::kRegular)) {
+    OnBrowserAdded(browser_list, browser);
+  }
+}
+
+#pragma mark - IOSChromeLocalSessionEventRouter::Observer (BrowserListObserver)
+
+void IOSChromeLocalSessionEventRouter::Observer::OnBrowserAdded(
+    const BrowserList* browser_list,
+    Browser* browser) {
+  if (browser->type() != Browser::Type::kRegular) {
+    return;
+  }
+
+  WebStateList* web_state_list = browser->GetWebStateList();
+  web_state_list_observations_.AddObservation(web_state_list);
+
+  // In the unlikely event that the WebStateList is not empty, observe
+  // all existing WebStates (pretend this is a batch operation).
+  if (const int count = web_state_list->count(); count != 0) {
+    router_->OnSessionEventStarting();
+    for (int index = 0; index < count; ++index) {
+      web::WebState* web_state = web_state_list->GetWebStateAt(index);
+      web_state_observations_.AddObservation(web_state);
+    }
+    router_->OnSessionEventEnded();
+  }
+}
+
+void IOSChromeLocalSessionEventRouter::Observer::OnBrowserRemoved(
+    const BrowserList* browser_list,
+    Browser* browser) {
+  if (browser->type() != Browser::Type::kRegular) {
+    return;
+  }
+
+  WebStateList* web_state_list = browser->GetWebStateList();
+  web_state_list_observations_.RemoveObservation(web_state_list);
+
+  // The Browser are closed before the WebStateList itself, so it is
+  // possible for the list to be non-empty. Ensure that we stop the
+  // observation of the WebState if this is the case.
+  if (const int count = web_state_list->count(); count != 0) {
+    router_->OnSessionEventStarting();
+    for (int index = 0; index < count; ++index) {
+      web::WebState* web_state = web_state_list->GetWebStateAt(index);
+      web_state_observations_.RemoveObservation(web_state);
+    }
+    router_->OnSessionEventEnded();
+  }
+}
+
+void IOSChromeLocalSessionEventRouter::Observer::OnBrowserListShutdown(
+    BrowserList* browser_list) {
+  browser_list_observation_.Reset();
+  web_state_list_observations_.RemoveAllObservations();
+  web_state_observations_.RemoveAllObservations();
+}
+
+#pragma mark - IOSChromeLocalSessionEventRouter::Observer (WebStateListObserver)
 
 void IOSChromeLocalSessionEventRouter::Observer::WebStateListDidChange(
     WebStateList* web_state_list,
@@ -66,12 +169,12 @@
       const WebStateListChangeDetach& detach_change =
           change.As<WebStateListChangeDetach>();
       web::WebState* detached_web_state = detach_change.detached_web_state();
+      web_state_observations_.RemoveObservation(detached_web_state);
       if (detach_change.is_closing()) {
         router_->OnWebStateClosed();
       } else {
         router_->OnWebStateChange(detached_web_state);
       }
-      detached_web_state->RemoveObserver(this);
       break;
     }
     case WebStateListChange::Type::kMove:
@@ -81,20 +184,20 @@
       const WebStateListChangeReplace& replace_change =
           change.As<WebStateListChangeReplace>();
       web::WebState* replaced_web_state = replace_change.replaced_web_state();
+      web_state_observations_.RemoveObservation(replaced_web_state);
       router_->OnWebStateChange(replaced_web_state);
-      replaced_web_state->RemoveObserver(this);
 
       web::WebState* inserted_web_state = replace_change.inserted_web_state();
+      web_state_observations_.AddObservation(inserted_web_state);
       router_->OnWebStateChange(inserted_web_state);
-      inserted_web_state->AddObserver(this);
       break;
     }
     case WebStateListChange::Type::kInsert: {
       const WebStateListChangeInsert& insert_change =
           change.As<WebStateListChangeInsert>();
       web::WebState* inserted_web_state = insert_change.inserted_web_state();
+      web_state_observations_.AddObservation(inserted_web_state);
       router_->OnWebStateChange(inserted_web_state);
-      inserted_web_state->AddObserver(this);
       break;
     }
     case WebStateListChange::Type::kGroupCreate:
@@ -113,7 +216,7 @@
   }
 }
 
-#pragma mark - WebStateObserver
+#pragma mark - IOSChromeLocalSessionEventRouter::Observer (WebStateObserver)
 
 void IOSChromeLocalSessionEventRouter::Observer::TitleWasSet(
     web::WebState* web_state) {
@@ -144,8 +247,7 @@
 
 void IOSChromeLocalSessionEventRouter::Observer::WebStateDestroyed(
     web::WebState* web_state) {
-  router_->OnWebStateClosed();
-  web_state->RemoveObserver(this);
+  NOTREACHED();
 }
 
 void IOSChromeLocalSessionEventRouter::Observer::WillBeginBatchOperation(
@@ -158,6 +260,23 @@
   router_->OnSessionEventEnded();
 }
 
+#pragma mark - IOSChromeLocalSessionEventRouter
+
+IOSChromeLocalSessionEventRouter::IOSChromeLocalSessionEventRouter(
+    BrowserList* browser_list,
+    sync_sessions::SyncSessionsClient* sessions_client,
+    const syncer::SyncableService::StartSyncFlare& flare)
+    : observer_(std::make_unique<Observer>(this)),
+      sessions_client_(sessions_client),
+      flare_(flare) {
+  DCHECK(sessions_client_);
+  // Start the observer now that the object is fully initialized. This may
+  // call methods on the current instance if the BrowserList is not empty.
+  observer_->Start(browser_list);
+}
+
+IOSChromeLocalSessionEventRouter::~IOSChromeLocalSessionEventRouter() = default;
+
 void IOSChromeLocalSessionEventRouter::OnSessionEventStarting() {
   batch_in_progress_++;
 }
diff --git a/ios/chrome/browser/toolbar/ui_bundled/tab_groups/coordinator/tab_group_indicator_mediator.mm b/ios/chrome/browser/toolbar/ui_bundled/tab_groups/coordinator/tab_group_indicator_mediator.mm
index 868579f..dc2e581 100644
--- a/ios/chrome/browser/toolbar/ui_bundled/tab_groups/coordinator/tab_group_indicator_mediator.mm
+++ b/ios/chrome/browser/toolbar/ui_bundled/tab_groups/coordinator/tab_group_indicator_mediator.mm
@@ -7,6 +7,7 @@
 #import "base/memory/raw_ptr.h"
 #import "base/memory/weak_ptr.h"
 #import "base/scoped_observation.h"
+#import "base/strings/sys_string_conversions.h"
 #import "components/collaboration/public/collaboration_service.h"
 #import "components/feature_engagement/public/feature_constants.h"
 #import "components/feature_engagement/public/tracker.h"
@@ -173,16 +174,16 @@
 
 - (void)manageGroup {
   const TabGroup* tabGroup = [self currentTabGroup];
-  NSString* collabID =
+  tab_groups::CollaborationId collabID =
       tab_groups::utils::GetTabGroupCollabID(tabGroup, _tabGroupSyncService);
-  if (!_shareKitService || !collabID) {
+  if (!_shareKitService || collabID.value().empty()) {
     return;
   }
 
   ShareKitManageConfiguration* config =
       [[ShareKitManageConfiguration alloc] init];
   config.baseViewController = self.baseViewController;
-  config.collabID = collabID;
+  config.collabID = base::SysUTF8ToNSString(collabID.value());
   config.applicationHandler = self.applicationHandler;
   _shareKitService->ManageTabGroup(config);
 }
@@ -299,9 +300,9 @@
 
   const TabGroup* tabGroup = [self currentTabGroup];
 
-  NSString* savedCollabID =
+  tab_groups::CollaborationId savedCollabID =
       tab_groups::utils::GetTabGroupCollabID(tabGroup, _tabGroupSyncService);
-  BOOL isShared = savedCollabID != nil;
+  BOOL isShared = !savedCollabID.value().empty();
   [_consumer setShared:isShared];
 
   // Prevent the face pile from being set up for tab groups that are not shared.
@@ -312,7 +313,7 @@
   // Configure the face pile.
   ShareKitFacePileConfiguration* config =
       [[ShareKitFacePileConfiguration alloc] init];
-  config.collabID = savedCollabID;
+  config.collabID = base::SysUTF8ToNSString(savedCollabID.value());
   config.showsEmptyState = NO;
   config.avatarSize = kFacePileAvatarSize;
 
diff --git a/ios/chrome/browser/ui/authentication/authentication_flow.mm b/ios/chrome/browser/ui/authentication/authentication_flow.mm
index 378c0e48..fc8a9ff 100644
--- a/ios/chrome/browser/ui/authentication/authentication_flow.mm
+++ b/ios/chrome/browser/ui/authentication/authentication_flow.mm
@@ -389,11 +389,13 @@
     }
 
     case SIGN_OUT_IF_NEEDED:
+      // TODO(crbug.com/375605482): skip sign out if there is a profile
+      // switching.
       [_performer signOutProfile:profile];
       return;
 
     case SIGN_IN:
-      [self signInIdentity:_identityToSignIn];
+      [self multiProfileSignIn];
       return;
 
     case REGISTER_FOR_USER_POLICY:
@@ -461,7 +463,7 @@
       [currentIdentity isEqual:_identityToSignIn];
 }
 
-- (void)signInIdentity:(id<SystemIdentity>)identity {
+- (void)multiProfileSignIn {
   if (self.userDecisionCompletion) {
     self.userDecisionCompletion();
   }
@@ -475,30 +477,29 @@
   BOOL isValidIdentityOnDevice = NO;
   if (AreSeparateProfilesForManagedAccountsEnabled()) {
     isValidIdentityOnDevice = IsIdentityInAccountInfos(
-        identity, identityManager->GetAccountsOnDevice());
+        _identityToSignIn, identityManager->GetAccountsOnDevice());
     isValidIdentityInProfile = IsIdentityInCoreAccountInfos(
-        identity, identityManager->GetAccountsWithRefreshTokens());
+        _identityToSignIn, identityManager->GetAccountsWithRefreshTokens());
   } else {
     isValidIdentityOnDevice = isValidIdentityInProfile =
-        accountManagerService->IsValidIdentity(identity);
+        accountManagerService->IsValidIdentity(_identityToSignIn);
   }
 
   if (isValidIdentityInProfile) {
-    [_performer signInIdentity:identity
-                 atAccessPoint:self.accessPoint
-                currentProfile:profile];
-    _didSignIn = YES;
-    [self continueSignin];
+    [self signInInCurrentProfile];
   } else if (isValidIdentityOnDevice) {
     CHECK(AreSeparateProfilesForManagedAccountsEnabled());
     NSString* sceneIdentifier = _browser->GetSceneState().sceneSessionID;
     __weak __typeof(self) weakSelf = self;
     OnProfileSwitchCompletion completion = base::BindOnce(
-        [](__typeof(self) strongSelf, bool success) {
-          [strongSelf onSwitchToProfileWithSuccess:success];
+        [](__typeof(self) strong_self, bool success,
+           Browser* new_profile_browser, UIViewController* view_controller) {
+          [strong_self onSwitchToProfileWithSuccess:success
+                                  newProfileBrowser:new_profile_browser
+                                     viewController:view_controller];
         },
         weakSelf);
-    [_performer switchToProfileWithIdentity:identity
+    [_performer switchToProfileWithIdentity:_identityToSignIn
                             sceneIdentifier:sceneIdentifier
                                  completion:std::move(completion)];
   } else {
@@ -708,27 +709,39 @@
 
 // Called when the profile switching succeeded or failed (according to
 // `success`).
-- (void)onSwitchToProfileWithSuccess:(BOOL)success {
+- (void)onSwitchToProfileWithSuccess:(BOOL)success
+                   newProfileBrowser:(Browser*)newProfileBrowser
+                      viewController:(UIViewController*)viewController {
+  CHECK(AreSeparateProfilesForManagedAccountsEnabled());
   if (success) {
-    // TODO(crbug.com/375604649): Need to define how to finish the
-    // authentication flow after the profile switching.
-    // * What happens for the steps after SIGN_IN?
-    //    REGISTER_FOR_USER_POLICY
-    //    FETCH_USER_POLICY
-    //    FETCH_CAPABILITIES
-    //    COMPLETE_WITH_SUCCESS
-    // * Is there metrics to record before to the flow is finished?
-    // It is important to reach the last step otherwise AuthenticationFlow is
-    // leaked since `_selfRetainer` returns itself.
-
-    // The _browser doesn't exist anymore, since the profile has been switched.
-    _browser = nil;
+    _browser = newProfileBrowser;
+    _presentingViewController = viewController;
+    // TODO(crbug.com/375605482): Need to sign-out if the new profile is not
+    // signed in with the right identity (useful for the personal profile).
+    // TODO(crbug.com/375605482): Need to block user until AuthenticationFlow
+    // is done? Probably with a blur animation.
+    [self signInInCurrentProfile];
   } else {
-    // TODO(crbug.com/375604649): Generate an error and call:
+    // TODO(crbug.com/375605482): Generate an error and call:
     // `[self handleAuthenticationError:error];`.
   }
 }
 
+// Signs in the user using `_identityToSignIn`. The identity must be assigned
+// to the current profile.
+- (void)signInInCurrentProfile {
+  ProfileIOS* profile = [self originalProfile];
+  signin::IdentityManager* identityManager =
+      IdentityManagerFactory::GetForProfile(profile);
+  CHECK(IsIdentityInCoreAccountInfos(
+      _identityToSignIn, identityManager->GetAccountsWithRefreshTokens()));
+  [_performer signInIdentity:_identityToSignIn
+               atAccessPoint:self.accessPoint
+              currentProfile:profile];
+  _didSignIn = YES;
+  [self continueSignin];
+}
+
 #pragma mark - Used for testing
 
 - (void)setPerformerForTesting:(AuthenticationFlowPerformer*)performer {
diff --git a/ios/chrome/browser/ui/authentication/authentication_flow_performer.h b/ios/chrome/browser/ui/authentication/authentication_flow_performer.h
index 9b9f4d97..9b1923d5 100644
--- a/ios/chrome/browser/ui/authentication/authentication_flow_performer.h
+++ b/ios/chrome/browser/ui/authentication/authentication_flow_performer.h
@@ -18,7 +18,13 @@
 class ProfileIOS;
 @protocol SystemIdentity;
 
-using OnProfileSwitchCompletion = base::OnceCallback<void(bool success)>;
+// Callback called the profile switching succeded (`success` is true) or failed
+// (`success` is false).
+// If `success is true:
+// `browser` and `view_controller` are the browser and the view controller of
+// the new profile.
+using OnProfileSwitchCompletion = base::OnceCallback<
+    void(bool success, Browser* browser, UIViewController* view_controller)>;
 
 // Performs the sign-in steps and user interactions as part of the sign-in flow.
 @interface AuthenticationFlowPerformer : NSObject
diff --git a/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm b/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm
index 2d9ca3b..5291e15 100644
--- a/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm
+++ b/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm
@@ -30,8 +30,11 @@
 #import "ios/chrome/browser/policy/model/cloud/user_policy_signin_service_factory.h"
 #import "ios/chrome/browser/policy/model/cloud/user_policy_switch.h"
 #import "ios/chrome/browser/shared/coordinator/alert/alert_coordinator.h"
+#import "ios/chrome/browser/shared/coordinator/scene/scene_state.h"
 #import "ios/chrome/browser/shared/model/application_context/application_context.h"
 #import "ios/chrome/browser/shared/model/browser/browser.h"
+#import "ios/chrome/browser/shared/model/browser/browser_provider.h"
+#import "ios/chrome/browser/shared/model/browser/browser_provider_interface.h"
 #import "ios/chrome/browser/shared/model/profile/profile_ios.h"
 #import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
@@ -148,8 +151,8 @@
           ->FindProfileNameForGaiaID(base::SysNSStringToUTF8(identity.gaiaID));
   if (!profileName.has_value()) {
     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-        FROM_HERE,
-        base::BindOnce(std::move(_onProfileSwitchCompletion), false));
+        FROM_HERE, base::BindOnce(std::move(_onProfileSwitchCompletion), false,
+                                  nullptr, nil));
     return;
   }
   [_changeProfileHandler changeProfile:base::SysUTF8ToNSString(*profileName)
@@ -397,7 +400,7 @@
 #pragma mark - ChangeProfileObserving
 
 - (void)operationFailed:(ChangeProfileFailure)failure {
-  std::move(_onProfileSwitchCompletion).Run(false);
+  std::move(_onProfileSwitchCompletion).Run(false, nullptr, nil);
 }
 
 - (void)willStartOperation:(UIViewController*)viewController {
@@ -406,7 +409,13 @@
 
 - (void)operationDidComplete:(UIViewController*)viewController
               withSceneState:(SceneState*)sceneState {
-  std::move(_onProfileSwitchCompletion).Run(true);
+  Browser* newProfileBrowser =
+      sceneState.browserProviderInterface.currentBrowserProvider.browser;
+  // TODO(crbug.com/375605482): `viewController` is nil. This is not expected.
+  // `sceneState.rootViewController` is used until the bug is fixed.
+  viewController = sceneState.rootViewController;
+  std::move(_onProfileSwitchCompletion)
+      .Run(true, newProfileBrowser, viewController);
 }
 
 #pragma mark - Private
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index ad283da..5e815f7d 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -345,6 +345,7 @@
     "//ios/chrome/browser/policy/model:unit_tests",
     "//ios/chrome/browser/policy/ui_bundled/idle:unit_tests",
     "//ios/chrome/browser/post_restore_signin/ui_bundled:unit_tests",
+    "//ios/chrome/browser/prefs/model:unit_tests",
     "//ios/chrome/browser/prerender/model:unit_tests",
     "//ios/chrome/browser/presenters/ui_bundled:unit_tests",
     "//ios/chrome/browser/price_insights/coordinator:unit_tests",
diff --git a/ios/third_party/earl_grey2/src b/ios/third_party/earl_grey2/src
index 598d8e8..2add385 160000
--- a/ios/third_party/earl_grey2/src
+++ b/ios/third_party/earl_grey2/src
@@ -1 +1 @@
-Subproject commit 598d8e856bc259d9632cd26e944d46d721c43071
+Subproject commit 2add385c1c502920dd753dfb1fbd830b194f7809
diff --git a/ios_internal b/ios_internal
index 0d766f3..a712b78 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit 0d766f3e5bd6d0a896a35d4e398d455f7888b805
+Subproject commit a712b786ea4b03defe96cc34b36f4dbff9f91634
diff --git a/media/base/android/java/src/org/chromium/media/VideoAcceleratorUtil.java b/media/base/android/java/src/org/chromium/media/VideoAcceleratorUtil.java
index 0e7a9c77a..4b03fcc 100644
--- a/media/base/android/java/src/org/chromium/media/VideoAcceleratorUtil.java
+++ b/media/base/android/java/src/org/chromium/media/VideoAcceleratorUtil.java
@@ -189,11 +189,16 @@
         return false;
     }
 
-    // Chromium doesn't bundle a software encoder or decoder for H.264 or H.265 so allow
-    // usage of software codecs through MediaCodec for those codecs.
-    private static boolean requiresHardware(String type) {
-        return !type.equalsIgnoreCase(MediaCodecUtil.MimeTypes.VIDEO_H264)
-                && !type.equalsIgnoreCase(MediaCodecUtil.MimeTypes.VIDEO_HEVC);
+    // Chromium doesn't bundle a software encoder for H.264. Since `c2.android.avc.encoder` can
+    // support up to `2048x2048 & 30fps`, we allow the usage of software codecs through
+    // MediaCodec for H.264.
+    //
+    // However, it should be noted that Chromium also doesn't bundle a software encoder for HEVC.
+    // And since `c2.android.hevc.encoder` only supports up to `512x512 & 30fps`, which normal
+    // users can't use as it is a pretty low resolution framerate combination, we explicitly
+    // choose not to report it as supported.
+    private static boolean requiresHardwareEncoder(String type) {
+        return !type.equalsIgnoreCase(MediaCodecUtil.MimeTypes.VIDEO_H264);
     }
 
     // H.264 high profile isn't required by Android platform, so we can only add support if
@@ -250,7 +255,7 @@
             for (MediaCodecInfo info : codecList) {
                 if (info.isAlias()) continue; // Skip duplicates.
                 if (!info.isEncoder()) continue;
-                if (!info.isHardwareAccelerated() && requiresHardware(type)) continue;
+                if (!info.isHardwareAccelerated() && requiresHardwareEncoder(type)) continue;
 
                 MediaCodecInfo.CodecCapabilities capabilities = null;
                 try {
diff --git a/media/capture/video/shared_memory_buffer_tracker.cc b/media/capture/video/shared_memory_buffer_tracker.cc
index cc2b15a8..83fa38a 100644
--- a/media/capture/video/shared_memory_buffer_tracker.cc
+++ b/media/capture/video/shared_memory_buffer_tracker.cc
@@ -19,7 +19,7 @@
 class SharedMemoryBufferTrackerHandle : public media::VideoCaptureBufferHandle {
  public:
   explicit SharedMemoryBufferTrackerHandle(
-      const base::WritableSharedMemoryMapping& mapping)
+      base::WritableSharedMemoryMapping& mapping)
       : mapped_size_(mapping.size()),
         data_(mapping.GetMemoryAsSpan<uint8_t>().data()) {}
 
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index d331321b..3bc9975 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -262,6 +262,12 @@
       "windows/media_foundation_video_encode_accelerator_win.h",
       "windows/mf_audio_encoder.cc",
       "windows/mf_audio_encoder.h",
+      "windows/mf_video_encoder_shared_state.cc",
+      "windows/mf_video_encoder_shared_state.h",
+      "windows/mf_video_encoder_switches.cc",
+      "windows/mf_video_encoder_switches.h",
+      "windows/mf_video_encoder_util.cc",
+      "windows/mf_video_encoder_util.h",
       "windows/mf_video_processor_accelerator.cc",
       "windows/mf_video_processor_accelerator.h",
       "windows/scoped_d3d_buffers.cc",
diff --git a/media/gpu/android/ndk_video_encode_accelerator.cc b/media/gpu/android/ndk_video_encode_accelerator.cc
index 074658d..631bd90d 100644
--- a/media/gpu/android/ndk_video_encode_accelerator.cc
+++ b/media/gpu/android/ndk_video_encode_accelerator.cc
@@ -21,8 +21,6 @@
 #include "media/base/bitstream_buffer.h"
 #include "media/base/encoder_status.h"
 #include "media/base/media_serializers_base.h"
-#include "media/base/media_switches.h"
-#include "media/base/video_codecs.h"
 #include "media/base/video_frame.h"
 #include "media/gpu/android/video_accelerator_util.h"
 #include "media/parsers/h264_level_limits.h"
@@ -486,26 +484,7 @@
 
   SupportedProfiles profiles;
   for (auto& info : GetEncoderInfoCache()) {
-    const auto codec = VideoCodecProfileToVideoCodec(info.profile.profile);
-    switch (codec) {
-      case VideoCodec::kHEVC:
-#if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
-        if (base::FeatureList::IsEnabled(kPlatformHEVCEncoderSupport) &&
-            // Currently only 8bit NV12 and I420 encoding is supported, so limit
-            // this to main profile only just like other platforms.
-            info.profile.profile == VideoCodecProfile::HEVCPROFILE_MAIN &&
-            // Some devices may report to have a software HEVC encoder,
-            // however based on tests, they are not always working well,
-            // so limit the support to HW only for now.
-            !info.profile.is_software_codec) {
-          profiles.push_back(info.profile);
-        }
-#endif
-        break;
-      default:
-        profiles.push_back(info.profile);
-        break;
-    }
+    profiles.push_back(info.profile);
   }
   return profiles;
 }
@@ -576,14 +555,6 @@
 
   for (const auto& info : GetEncoderInfoCache()) {
     if (info.name == codec_name) {
-      // Skip software HEVC encoders, as it only supports the maximum 512x512
-      // resolution at 30fps, and it is also filtered out by
-      // GetSupportedProfiles().
-      if (info.profile.profile == VideoCodecProfile::HEVCPROFILE_MAIN &&
-          info.profile.is_software_codec) {
-        continue;
-      }
-
       // TODO(crbug.com/382015342): Set the bitrate limits when we can get them
       // through MediaCodec API.
       encoder_info_.resolution_rate_limits.emplace_back(
diff --git a/media/gpu/android/video_accelerator_util.cc b/media/gpu/android/video_accelerator_util.cc
index 9baec5d..4c94e75f 100644
--- a/media/gpu/android/video_accelerator_util.cc
+++ b/media/gpu/android/video_accelerator_util.cc
@@ -7,10 +7,29 @@
 #include "base/android/build_info.h"
 #include "base/android/jni_string.h"
 #include "base/no_destructor.h"
+#include "media/base/media_switches.h"
+#include "media/base/video_codecs.h"
 
 // Must come after all headers that specialize FromJniType() / ToJniType().
 #include "media/base/android/media_jni_headers/VideoAcceleratorUtil_jni.h"
 
+namespace {
+bool isEncoderSupportedProfile(media::VideoCodecProfile profile) {
+  media::VideoCodec codec = media::VideoCodecProfileToVideoCodec(profile);
+  if (codec == media::VideoCodec::kHEVC) {
+#if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
+    // Currently only 8bit NV12 and I420 encoding is supported, so limit
+    // this to main profile only just like other platforms.
+    return base::FeatureList::IsEnabled(media::kPlatformHEVCEncoderSupport) &&
+           profile == media::VideoCodecProfile::HEVCPROFILE_MAIN;
+#else
+    return false;
+#endif
+  }
+  return true;
+}
+}  // namespace
+
 namespace media {
 
 const std::vector<MediaCodecEncoderInfo>& GetEncoderInfoCache() {
@@ -32,6 +51,9 @@
       MediaCodecEncoderInfo info;
       info.profile.profile = static_cast<VideoCodecProfile>(
           Java_SupportedProfileAdapter_getProfile(env, java_profile));
+      if (!isEncoderSupportedProfile(info.profile.profile)) {
+        continue;
+      }
       info.profile.min_resolution = gfx::Size(
           Java_SupportedProfileAdapter_getMinWidth(env, java_profile),
           Java_SupportedProfileAdapter_getMinHeight(env, java_profile));
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
index 0a9e322f..aaaf4d6 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
@@ -52,6 +52,8 @@
 #include "media/gpu/h264_rate_controller.h"
 #include "media/gpu/h264_ratectrl_rtc.h"
 #include "media/gpu/windows/h264_video_rate_control_wrapper.h"
+#include "media/gpu/windows/mf_video_encoder_shared_state.h"
+#include "media/gpu/windows/mf_video_encoder_switches.h"
 #include "media/gpu/windows/vp9_video_rate_control_wrapper.h"
 #include "media/parsers/temporal_scalability_id_extractor.h"
 #include "third_party/libvpx/source/libvpx/vp9/ratectrl_rtc.h"
@@ -68,258 +70,13 @@
 
 namespace media {
 
-BASE_FEATURE(kExpandMediaFoundationEncodingResolutions,
-             "ExpandMediaFoundationEncodingResolutions",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 namespace {
 constexpr uint32_t kDefaultGOPLength = 3000;
 constexpr uint32_t kDefaultTargetBitrate = 5000000u;
-constexpr size_t kDefaultFrameRateNumerator = 30;
-constexpr size_t kDefaultFrameRateDenominator = 1;
 constexpr size_t kNumInputBuffers = 3;
 // Media Foundation uses 100 nanosecond units for time, see
 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms697282(v=vs.85).aspx.
 constexpr size_t kOneMicrosecondInMFSampleTimeUnits = 10;
-constexpr int kH26xMaxQp = 51;
-constexpr uint64_t kVP9MaxQIndex = 255;
-constexpr uint64_t kAV1MaxQIndex = 255;
-
-// Quantizer parameter used in libvpx vp9 rate control, whose range is 0-63.
-// These are based on WebRTC's defaults, cite from
-// third_party/webrtc/media/engine/webrtc_video_engine.h.
-constexpr uint8_t kVP9MinQuantizer = 2;
-constexpr uint8_t kVP9MaxQuantizer = 56;
-// Default value from
-// //third_party/webrtc/modules/video_coding/codecs/av1/libaom_av1_encoder.cc,
-constexpr uint8_t kAV1MinQuantizer = 10;
-// //third_party/webrtc/media/engine/webrtc_video_engine.h.
-constexpr uint8_t kAV1MaxQuantizer = 56;
-
-// The range for the quantization parameter is determined by examining the
-// estimated QP values from the SW bitrate controller in various encoding
-// scenarios.
-constexpr uint8_t kH264MinQuantizer = 16;
-constexpr uint8_t kH264MaxQuantizer = 51;
-
-#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
-// For H.265, ideally we may reuse Min/MaxQp for H.264 from
-// media/gpu/vaapi/h264_vaapi_video_encoder_delegate.cc. However
-// test shows most of the drivers require a min QP of 10 to reach
-// target bitrate especially at low resolution.
-constexpr uint8_t kH265MinQuantizer = 10;
-constexpr uint8_t kH265MaxQuantizer = 42;
-#endif  // BUILDFLAG(ENABLE_PLATFORM_HEVC)
-
-// NV12 is supported natively by all hardware encoders.  Other
-// formats can be converted by MediaFoundationVideoProcessorAccelerator.
-// In the future, specific encoders may also be queried for support
-// for additional formats.  For example, ARGB may be accepted by
-// some encoders directly, or AV1 encoders may accept some 4:4:4
-// formats.
-constexpr auto kSupportedPixelFormats =
-    base::MakeFixedFlatSet<VideoPixelFormat>(
-        {PIXEL_FORMAT_I420, PIXEL_FORMAT_NV12});
-constexpr auto kSupportedPixelFormatsD3DVideoProcessing =
-    base::MakeFixedFlatSet<VideoPixelFormat>(
-        {PIXEL_FORMAT_I420, PIXEL_FORMAT_NV12, PIXEL_FORMAT_YV12,
-         PIXEL_FORMAT_NV21, PIXEL_FORMAT_ARGB, PIXEL_FORMAT_XRGB,
-         PIXEL_FORMAT_ABGR, PIXEL_FORMAT_XBGR});
-
-// The default supported max framerate and resolution.
-constexpr FramerateAndResolution kDefaultMaxFramerateAndResolution = {
-    kDefaultFrameRateNumerator / kDefaultFrameRateDenominator,
-    gfx::Size(1920, 1080)};
-
-// The default supported min resolution.
-constexpr gfx::Size kDefaultMinResolution(32, 32);
-
-// For H.264, some NVIDIA GPUs may report `MF_VIDEO_MAX_MB_PER_SEC` value equals
-// to `6799902`, resulting chromium think 8K & 30fps is supported, and some
-// Intel GPUs only support level 5.2. Since most devices only support up to 4K,
-// so we set level 5.2 as the max allowed level here to limit max resolution and
-// framerate combination can only go up to 2K & 172fps, or 4K & 64fps.
-constexpr FramerateAndResolution kLegacy2KMaxFramerateAndResolution = {
-    172, gfx::Size(1920, 1080)};
-constexpr FramerateAndResolution kLegacy4KMaxFramerateAndResolution = {
-    64, gfx::Size(3840, 2160)};
-
-// For H.265/AV1, some NVIDIA GPUs may report `MF_VIDEO_MAX_MB_PER_SEC` value
-// equals to `7255273`, resulting chromium think 2K & 880fps is supported. Since
-// the max level of H.265/AV1 (6.2/6.3) do not allow framerate >= 300fps, so we
-// set level 6.2/6.3 as the max allowed level here and limit max resolution and
-// framerate combination can only go up to 2K/4K & 300fps, 8K & 128fps.
-constexpr FramerateAndResolution kModern2KMaxFramerateAndResolution = {
-    300, gfx::Size(1920, 1080)};
-constexpr FramerateAndResolution kModern4KMaxFramerateAndResolution = {
-    300, gfx::Size(3840, 2160)};
-constexpr FramerateAndResolution kModern8KMaxFramerateAndResolution = {
-    128, gfx::Size(7680, 4320)};
-
-constexpr CLSID kIntelAV1HybridEncoderCLSID = {
-    0x62c053ce,
-    0x5357,
-    0x4794,
-    {0x8c, 0x5a, 0xfb, 0xef, 0xfe, 0xff, 0xb8, 0x2d}};
-
-#ifndef ARCH_CPU_X86
-// Temporal layers are reported to be supported by the Intel driver, but are
-// only considered supported by MediaFoundation depending on these flags. This
-// support is reported in MediaCapabilities' powerEfficient as well as deciding
-// if Initialize() is allowed to succeed.
-BASE_FEATURE(kMediaFoundationVP9L1T2Support,
-             "MediaFoundationVP9L1T2Support",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-// Up to 3 temporal layers, i.e. this enables both L1T2 and L1T3.
-BASE_FEATURE(kMediaFoundationVP9L1T3Support,
-             "MediaFoundationVP9L1T3Support",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-BASE_FEATURE(kMediaFoundationAV1L1T2Support,
-             "MediaFoundationAV1L1T2Support",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-// Up to 3 temporal layers, i.e. this enables both L1T2 and L1T3.
-BASE_FEATURE(kMediaFoundationAV1L1T3Support,
-             "MediaFoundationAV1L1T3Support",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-#endif  // !defined(ARCH_CPU_X86)
-
-BASE_FEATURE(kMediaFoundationUseSWBRCForH264Camera,
-             "MediaFoundationUseSWBRCForH264Camera",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-BASE_FEATURE(kMediaFoundationUseSWBRCForH264Desktop,
-             "MediaFoundationUseSWBRCForH264Desktop",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
-// H.264 SW Bitrate Controller works in fixed delta QP mode by default. The QP
-// difference between base and enhancement layer can be controlled using a
-// feature parameter.
-BASE_FEATURE(kMediaFoundationSWBRCUseFixedDeltaQP,
-             "MediaFoundationSWBRCUseFixedDeltaQP",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-BASE_FEATURE_PARAM(int,
-                   kMediaFoundationSWBRCFixedDeltaQPValue,
-                   &kMediaFoundationSWBRCUseFixedDeltaQP,
-                   "MediaFoundationSWBRCFixedDeltaQPValue",
-                   0);
-
-#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
-// For H.265 encoding at L1T1/L1T2 we may use SW bitrate controller when
-// constant bitrate encoding is requested.
-BASE_FEATURE(kMediaFoundationUseSWBRCForH265,
-             "MediaFoundationUseSWBRCForH265",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-#endif  // BUILDFLAG(ENABLE_PLATFORM_HEVC)
-
-eAVEncH264VProfile GetH264VProfile(VideoCodecProfile profile,
-                                   bool is_constrained_h264) {
-  switch (profile) {
-    case H264PROFILE_BASELINE:
-      return is_constrained_h264 ? eAVEncH264VProfile_ConstrainedBase
-                                 : eAVEncH264VProfile_Base;
-    case H264PROFILE_MAIN:
-      return eAVEncH264VProfile_Main;
-    case H264PROFILE_HIGH:
-      return eAVEncH264VProfile_High;
-    default:
-      return eAVEncH264VProfile_unknown;
-  }
-}
-
-// Convert AV1/VP9 qindex (0-255) to the quantizer parameter input in MF
-// AVEncVideoEncodeQP. AVEncVideoEncodeQP maps it to libvpx qp tuning parameter
-// and thus the range is 0-63.
-uint8_t QindextoAVEncQP(VideoCodec codec, uint8_t q_index) {
-  if (codec == VideoCodec::kAV1 || codec == VideoCodec::kVP9) {
-    // The following computation is based on the table in
-    // //third_party/libvpx/source/libvpx/vp9/encoder/vp9_quantize.c.
-    // //third_party/libaom/source/libaom/av1/encoder/av1_quantize.c
-    // {
-    //   0,   4,   8,   12,  16,  20,  24,  28,  32,  36,  40,  44,  48,
-    //   52,  56,  60,  64,  68,  72,  76,  80,  84,  88,  92,  96,  100,
-    //   104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152,
-    //   156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204,
-    //   208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 249, 255,
-    // };
-    if (q_index <= 244) {
-      return (q_index + 3) / 4;
-    }
-    if (q_index <= 249) {
-      return 62;
-    }
-    return 63;
-  }
-  return q_index;
-}
-
-// Convert AV1/VP9 AVEncVideoEncodeQP values to qindex (0-255) range.
-// This is the inverse of QindextoAVEncQP() function above.
-uint8_t AVEncQPtoQindex(VideoCodec codec, uint8_t avenc_qp) {
-  if (codec == VideoCodec::kAV1 || codec == VideoCodec::kVP9) {
-    uint8_t q_index = avenc_qp * 4;
-    if (q_index == 248) {
-      q_index = 249;
-    } else if (q_index == 252) {
-      q_index = 255;
-    }
-    return q_index;
-  }
-  return avenc_qp;
-}
-
-// According to AV1/VP9's bitstream specification, the valid range of qp
-// value (defined as base_q_idx) should be 0-255.
-bool IsValidQp(VideoCodec codec, uint64_t qp) {
-  switch (codec) {
-    case VideoCodec::kH264:
-#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
-    case VideoCodec::kHEVC:
-#endif  // BUILDFLAG(ENABLE_PLATFORM_HEVC)
-      return qp <= kH26xMaxQp;
-    case VideoCodec::kVP9:
-      return qp <= kVP9MaxQIndex;
-    case VideoCodec::kAV1:
-      return qp <= kAV1MaxQIndex;
-    default:
-      return false;
-  }
-}
-
-uint8_t GetMaxQuantizer(VideoCodec codec) {
-  switch (codec) {
-    case VideoCodec::kH264:
-      return kH264MaxQuantizer;
-#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
-    case VideoCodec::kHEVC:
-      return kH265MaxQuantizer;
-#endif  // BUILDFLAG(ENABLE_PLATFORM_HEVC)
-    case VideoCodec::kVP9:
-      return kVP9MaxQuantizer;
-    case VideoCodec::kAV1:
-      return kAV1MaxQuantizer;
-    default:
-      return 0;  // Return invalid value for unsupported codec.
-  }
-}
-
-// Only eAVEncVP9VProfile_420_8 is supported on Intel graphics.
-eAVEncVP9VProfile GetVP9VProfile(VideoCodecProfile profile) {
-  switch (profile) {
-    case VP9PROFILE_PROFILE0:
-      return eAVEncVP9VProfile_420_8;
-    default:
-      return eAVEncVP9VProfile_unknown;
-  }
-}
-
-// Only eAVEncH265Vprofile_Main_420_8 is supported.
-eAVEncH265VProfile GetHEVCProfile(VideoCodecProfile profile) {
-  switch (profile) {
-    case HEVCPROFILE_MAIN:
-      return eAVEncH265VProfile_Main_420_8;
-    default:
-      return eAVEncH265VProfile_unknown;
-  }
-}
 
 // Get distance from current frame to next temporal base layer frame.
 uint32_t GetDistanceToNextTemporalBaseLayer(uint32_t frame_number,
@@ -331,579 +88,6 @@
              : pattern_count - (frame_number % pattern_count);
 }
 
-MediaFoundationVideoEncodeAccelerator::DriverVendor GetDriverVendor(
-    IMFActivate* encoder) {
-  using DriverVendor = MediaFoundationVideoEncodeAccelerator::DriverVendor;
-  base::win::ScopedCoMem<WCHAR> vendor_id;
-  UINT32 id_length;
-  encoder->GetAllocatedString(MFT_ENUM_HARDWARE_VENDOR_ID_Attribute, &vendor_id,
-                              &id_length);
-  if (id_length != 8) {  // Normal vendor ids have length 8.
-    return DriverVendor::kOther;
-  }
-  if (!_wcsnicmp(vendor_id.get(), L"VEN_10DE", id_length)) {
-    return DriverVendor::kNvidia;
-  }
-  if (!_wcsnicmp(vendor_id.get(), L"VEN_1002", id_length)) {
-    return DriverVendor::kAMD;
-  }
-  if (!_wcsnicmp(vendor_id.get(), L"VEN_8086 ", id_length)) {
-    return DriverVendor::kIntel;
-  }
-  if (!_wcsnicmp(vendor_id.get(), L"VEN_QCOM", id_length)) {
-    return DriverVendor::kQualcomm;
-  }
-  return DriverVendor::kOther;
-}
-
-// The driver tells us how many temporal layers it supports, but we may need to
-// reduce this limit to avoid bad or untested drivers.
-int GetMaxTemporalLayerVendorLimit(
-    MediaFoundationVideoEncodeAccelerator::DriverVendor vendor,
-    VideoCodec codec,
-    const gpu::GpuDriverBugWorkarounds& workarounds) {
-#if defined(ARCH_CPU_X86)
-  // x86 systems sometimes crash in video drivers here.
-  // More info: https://crbug.com/1253748
-  return 1;
-#else
-  using DriverVendor = MediaFoundationVideoEncodeAccelerator::DriverVendor;
-  // crbug.com/1373780: Nvidia HEVC encoder reports supporting 3 temporal
-  // layers, but will fail initialization if configured to encoded with
-  // more than one temporal layers, thus we block Nvidia HEVC encoder for
-  // temporal SVC encoding.
-  if (codec == VideoCodec::kHEVC && vendor == DriverVendor::kNvidia) {
-    return 1;
-  }
-
-  // Qualcomm HEVC and AV1 encoders report temporal layer support, but will
-  // fail the tests currently, so block from temporal SVC encoding.
-  if ((codec == VideoCodec::kHEVC || codec == VideoCodec::kAV1) &&
-      vendor == DriverVendor::kQualcomm) {
-    return 1;
-  }
-
-  // Intel drivers with issues of dynamically changing bitrate at CBR mode for
-  // HEVC should be blocked from L1T3 encoding, as there is no SW BRC support
-  // for that at present.
-  if (codec == VideoCodec::kHEVC && vendor == DriverVendor::kIntel &&
-      workarounds.disable_hevc_hmft_cbr_encoding) {
-    return 2;
-  }
-
-  // Temporal layer encoding is disabled for VP9 unless a flag is enabled.
-  //
-  // For example, the Intel VP9 HW encoder reports supporting 3 temporal layers
-  // but the number of temporal layers we allow depends on feature flags. At the
-  // time of writing, Intel L1T3 may not be spec-compliant.
-  // - See https://crbug.com/1425117 for temporal layer foundation (L1T2/L1T3).
-  // - See https://crbug.com/1501767 for L1T2 rollout (not L1T3).
-  if (codec == VideoCodec::kVP9) {
-    if (vendor == DriverVendor::kIntel &&
-        workarounds.disable_vp9_hmft_temporal_encoding) {
-      return 1;
-    }
-
-    if (base::FeatureList::IsEnabled(kMediaFoundationVP9L1T3Support)) {
-      return 3;
-    }
-    if (base::FeatureList::IsEnabled(kMediaFoundationVP9L1T2Support)) {
-      return 2;
-    }
-    return 1;
-  }
-
-  if (codec == VideoCodec::kAV1) {
-    // Whenever you add to the allow-list a new temporal layer limit, make sure
-    // you update output bitstream metadata to indicate whether the encoded AV1
-    // bitstream follows WebRTC SVC spec.
-    if (vendor != DriverVendor::kIntel) {
-      return 1;
-    }
-    if (base::FeatureList::IsEnabled(kMediaFoundationAV1L1T3Support)) {
-      return 3;
-    }
-    if (base::FeatureList::IsEnabled(kMediaFoundationAV1L1T2Support)) {
-      return 2;
-    }
-    return 1;
-  }
-
-  // No driver/codec specific limit to enforce.
-  return 3;
-#endif
-}
-
-int GetNumSupportedTemporalLayers(
-    IMFActivate* activate,
-    VideoCodec codec,
-    const gpu::GpuDriverBugWorkarounds& workarounds) {
-  auto vendor = GetDriverVendor(activate);
-  int max_temporal_layer_vendor_limit =
-      GetMaxTemporalLayerVendorLimit(vendor, codec, workarounds);
-  if (max_temporal_layer_vendor_limit == 1) {
-    return 1;
-  }
-
-  ComMFTransform encoder;
-  ComCodecAPI codec_api;
-  HRESULT hr = activate->ActivateObject(IID_PPV_ARGS(&encoder));
-  if (FAILED(hr)) {
-    // Log to VLOG since errors are expected as part of GetSupportedProfiles().
-    DVLOG(2) << "Failed to activate encoder: " << PrintHr(hr);
-    return 1;
-  }
-
-  hr = encoder.As(&codec_api);
-  if (FAILED(hr)) {
-    // Log to VLOG since errors are expected as part of GetSupportedProfiles().
-    DVLOG(2) << "Failed to get encoder as CodecAPI: " << PrintHr(hr);
-    return 1;
-  }
-
-  if (codec_api->IsSupported(&CODECAPI_AVEncVideoTemporalLayerCount) != S_OK) {
-    return 1;
-  }
-
-  base::win::ScopedVariant min, max, step;
-  if (FAILED(codec_api->GetParameterRange(
-          &CODECAPI_AVEncVideoTemporalLayerCount, min.AsInput(), max.AsInput(),
-          step.AsInput()))) {
-    return 1;
-  }
-
-  // Temporal encoding is only considered supported if the driver reports at
-  // least a span of 1-3 temporal layers.
-  if (V_UI4(min.ptr()) > 1u || V_UI4(max.ptr()) < 3u) {
-    return 1;
-  }
-  return max_temporal_layer_vendor_limit;
-}
-
-bool IsIntelHybridAV1Encoder(IMFActivate* activate) {
-  if (GetDriverVendor(activate) ==
-      MediaFoundationVideoEncodeAccelerator::DriverVendor::kIntel) {
-    // Get the CLSID GUID of the HMFT.
-    GUID mft_guid = {0};
-    activate->GetGUID(MFT_TRANSFORM_CLSID_Attribute, &mft_guid);
-    if (mft_guid == kIntelAV1HybridEncoderCLSID) {
-      return true;
-    }
-  }
-  return false;
-}
-
-using MFTEnum2Type = decltype(&MFTEnum2);
-MFTEnum2Type GetMFTEnum2Function() {
-  static const MFTEnum2Type kMFTEnum2Func = []() {
-    auto mf_dll = base::LoadSystemLibrary(L"mfplat.dll");
-    return mf_dll ? reinterpret_cast<MFTEnum2Type>(
-                        base::GetFunctionPointerFromNativeLibrary(mf_dll,
-                                                                  "MFTEnum2"))
-                  : nullptr;
-  }();
-  return kMFTEnum2Func;
-}
-
-// If MFTEnum2 is unavailable, this uses MFTEnumEx and doesn't fill any
-// adapter information if there are more than one adapters.
-std::vector<ComPtr<IMFActivate>> EnumerateHardwareEncodersLegacy(
-    VideoCodec codec) {
-  std::vector<ComPtr<IMFActivate>> encoders;
-
-  uint32_t flags = MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_SORTANDFILTER;
-  MFT_REGISTER_TYPE_INFO input_info;
-  input_info.guidMajorType = MFMediaType_Video;
-  input_info.guidSubtype = MFVideoFormat_NV12;
-  MFT_REGISTER_TYPE_INFO output_info;
-  output_info.guidMajorType = MFMediaType_Video;
-  output_info.guidSubtype = VideoCodecToMFSubtype(codec);
-
-  Microsoft::WRL::ComPtr<IDXGIFactory1> factory;
-  auto hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
-  if (FAILED(hr)) {
-    DVLOG(2) << "Failed to create DXGI Factory";
-    return encoders;
-  }
-
-  LUID single_adapter_luid{0, 0};
-  int num_adapters = 0;
-
-  Microsoft::WRL::ComPtr<IDXGIAdapter> temp_adapter;
-  for (UINT adapter_idx = 0;
-       SUCCEEDED(factory->EnumAdapters(adapter_idx, &temp_adapter));
-       adapter_idx++) {
-    ++num_adapters;
-
-    DXGI_ADAPTER_DESC desc;
-    hr = temp_adapter->GetDesc(&desc);
-    if (FAILED(hr)) {
-      continue;
-    }
-
-    if (desc.VendorId == 0x1414 && desc.DeviceId == 0x8c) {
-      // Skip MS software adapters.
-      --num_adapters;
-    } else {
-      single_adapter_luid = desc.AdapterLuid;
-    }
-  }
-
-  IMFActivate** pp_activates = nullptr;
-  uint32_t count = 0;
-  hr = MFTEnumEx(MFT_CATEGORY_VIDEO_ENCODER, flags, &input_info, &output_info,
-                 &pp_activates, &count);
-
-  if (FAILED(hr)) {
-    // Log to VLOG since errors are expected as part of
-    // GetSupportedProfiles().
-    DVLOG(2) << "Failed to enumerate hardware encoders for "
-             << GetCodecName(codec) << " : " << PrintHr(hr);
-    return encoders;
-  }
-
-  for (UINT32 i = 0; i < count; i++) {
-    if (codec == VideoCodec::kAV1 && IsIntelHybridAV1Encoder(pp_activates[i])) {
-      continue;
-    }
-
-    // We can still infer the MFT's adapter LUID if there's only one adapter
-    // in the system.
-    if (num_adapters == 1) {
-      pp_activates[i]->SetBlob(MFT_ENUM_ADAPTER_LUID,
-                               reinterpret_cast<BYTE*>(&single_adapter_luid),
-                               sizeof(LUID));
-    }
-    encoders.push_back(pp_activates[i]);
-  }
-
-  if (pp_activates) {
-    CoTaskMemFree(pp_activates);
-  }
-
-  return encoders;
-}
-
-std::vector<ComPtr<IMFActivate>> EnumerateHardwareEncoders(VideoCodec codec) {
-  std::vector<ComPtr<IMFActivate>> encoders;
-
-  if (!InitializeMediaFoundation()) {
-    return encoders;
-  }
-#if defined(ARCH_CPU_ARM64)
-  // TODO (crbug.com/1509117): Temporarily disable video encoding on arm64
-  // until we figure out what OS reports all codecs as supported.
-  if (!base::FeatureList::IsEnabled(
-          kMediaFoundationAcceleratedEncodeOnArm64)) {
-    return encoders;
-  }
-#endif
-
-  MFTEnum2Type mftenum2_func = GetMFTEnum2Function();
-  if (!mftenum2_func) {
-    return EnumerateHardwareEncodersLegacy(codec);
-  }
-
-  uint32_t flags = MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_SORTANDFILTER;
-  MFT_REGISTER_TYPE_INFO input_info;
-  input_info.guidMajorType = MFMediaType_Video;
-  input_info.guidSubtype = MFVideoFormat_NV12;
-  MFT_REGISTER_TYPE_INFO output_info;
-  output_info.guidMajorType = MFMediaType_Video;
-  output_info.guidSubtype = VideoCodecToMFSubtype(codec);
-
-  Microsoft::WRL::ComPtr<IDXGIFactory1> factory;
-  auto hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
-  if (FAILED(hr)) {
-    DVLOG(2) << "Failed to create DXGI Factory";
-    return encoders;
-  }
-
-  Microsoft::WRL::ComPtr<IDXGIAdapter> temp_adapter;
-  for (UINT adapter_idx = 0;
-       SUCCEEDED(factory->EnumAdapters(adapter_idx, &temp_adapter));
-       adapter_idx++) {
-    DXGI_ADAPTER_DESC desc;
-    hr = temp_adapter->GetDesc(&desc);
-    if (FAILED(hr)) {
-      DVLOG(2) << "Failed to get description for adapter " << adapter_idx;
-      continue;
-    }
-
-    Microsoft::WRL::ComPtr<IMFAttributes> attributes;
-    hr = MFCreateAttributes(&attributes, 1);
-    if (FAILED(hr = attributes->SetBlob(
-                   MFT_ENUM_ADAPTER_LUID,
-                   reinterpret_cast<BYTE*>(&desc.AdapterLuid), sizeof(LUID)))) {
-      continue;
-    }
-
-    IMFActivate** pp_activates = nullptr;
-    uint32_t count = 0;
-    // MFTEnum2() function call.
-    hr = mftenum2_func(MFT_CATEGORY_VIDEO_ENCODER, flags, &input_info,
-                       &output_info, attributes.Get(), &pp_activates, &count);
-
-    if (FAILED(hr)) {
-      // Log to VLOG since errors are expected as part of
-      // GetSupportedProfiles().
-      DVLOG(2) << "Failed to enumerate hardware encoders for "
-               << GetCodecName(codec) << " at a adapter #" << adapter_idx
-               << " : " << PrintHr(hr);
-      continue;
-    }
-
-    for (UINT32 i = 0; i < count; i++) {
-      if (codec == VideoCodec::kAV1 &&
-          IsIntelHybridAV1Encoder(pp_activates[i])) {
-        continue;
-      }
-      // It's safe to ignore return value here.
-      // if SetBlob fails, the IMFActivate won't have a valid adapter LUID
-      // which will fail the check for preferred adapter LUID, so the
-      // MFDXGIDeviceManager will not be set for MFT, which is a safe option.
-      pp_activates[i]->SetBlob(MFT_ENUM_ADAPTER_LUID,
-                               reinterpret_cast<BYTE*>(&desc.AdapterLuid),
-                               sizeof(LUID));
-      encoders.push_back(pp_activates[i]);
-    }
-
-    if (pp_activates) {
-      CoTaskMemFree(pp_activates);
-    }
-  }
-
-  return encoders;
-}
-
-uint32_t CalculateMaxFramerateFromMacroBlocksPerSecond(
-    const FramerateAndResolution& max_framerate_and_resolution,
-    uint32_t max_macroblocks_per_second) {
-  constexpr uint64_t kMacroBlockWidth = 16u;
-  constexpr uint64_t kMacroBlockHeight = 16u;
-
-  uint64_t max_possible_framerate = std::floor(
-      (max_macroblocks_per_second * kMacroBlockWidth * kMacroBlockHeight) /
-      max_framerate_and_resolution.resolution.Area64());
-
-  return std::clamp(static_cast<uint32_t>(max_possible_framerate), 1u,
-                    max_framerate_and_resolution.frame_rate);
-}
-
-std::vector<FramerateAndResolution> GetMaxFramerateAndResolutionsFromMFT(
-    VideoCodec codec,
-    IMFTransform* encoder,
-    bool allow_set_output_type) {
-  std::vector<FramerateAndResolution> framerate_and_resolutions;
-  if (allow_set_output_type) {
-    ComPtr<IMFMediaType> media_type;
-
-    RETURN_ON_HR_FAILURE(MFCreateMediaType(&media_type),
-                         "Create media type failed", framerate_and_resolutions);
-    RETURN_ON_HR_FAILURE(
-        media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
-        "Set major type failed", framerate_and_resolutions);
-    RETURN_ON_HR_FAILURE(
-        media_type->SetGUID(MF_MT_SUBTYPE, VideoCodecToMFSubtype(codec)),
-        "Set guid for sub type failed", framerate_and_resolutions);
-    RETURN_ON_HR_FAILURE(
-        MFSetAttributeSize(
-            media_type.Get(), MF_MT_FRAME_SIZE,
-            kDefaultMaxFramerateAndResolution.resolution.width(),
-            kDefaultMaxFramerateAndResolution.resolution.height()),
-        "Set attribute size failed", framerate_and_resolutions);
-    // Frame rate,30, is dummy value for pass through.
-    RETURN_ON_HR_FAILURE(
-        MFSetAttributeRatio(
-            media_type.Get(), MF_MT_FRAME_RATE,
-            /*unNumerator=*/kDefaultMaxFramerateAndResolution.frame_rate,
-            /*unDenominator=*/1),
-        "Set attribute ratio failed", framerate_and_resolutions);
-    RETURN_ON_HR_FAILURE(media_type->SetUINT32(MF_MT_AVG_BITRATE, 9000000),
-                         "Set avg bitrate failed", framerate_and_resolutions);
-    RETURN_ON_HR_FAILURE(media_type->SetUINT32(MF_MT_INTERLACE_MODE,
-                                               MFVideoInterlace_Progressive),
-                         "Set interlace mode failed",
-                         framerate_and_resolutions);
-
-    if (codec != VideoCodec::kVP9) {
-      UINT32 max_level;
-      switch (codec) {
-        case VideoCodec::kH264:
-          max_level = eAVEncH264VLevel5_2;
-          break;
-        case VideoCodec::kAV1:
-          max_level = eAVEncAV1VLevel6_3;
-          break;
-        case VideoCodec::kHEVC:
-          max_level = eAVEncH265VLevel6_2;
-          break;
-        default:
-          NOTREACHED();
-      }
-      RETURN_ON_HR_FAILURE(media_type->SetUINT32(MF_MT_VIDEO_LEVEL, max_level),
-                           "Set video level failed", framerate_and_resolutions);
-    }
-
-    RETURN_ON_HR_FAILURE(
-        encoder->SetOutputType(/*stream_id=*/0, media_type.Get(), 0),
-        "Set output type failed", framerate_and_resolutions);
-  }
-
-  ComPtr<IMFAttributes> attributes;
-  RETURN_ON_HR_FAILURE(encoder->GetAttributes(&attributes),
-                       "Get attributes failed", framerate_and_resolutions);
-  uint32_t max_macroblocks_per_second =
-      MFGetAttributeUINT32(attributes.Get(), MF_VIDEO_MAX_MB_PER_SEC, 0);
-  max_macroblocks_per_second &=
-      0x0fffffff;  // Only lower 28 bits are supported.
-
-  std::vector<FramerateAndResolution> max_framerate_and_resolutions;
-  if (codec == VideoCodec::kH264) {
-    max_framerate_and_resolutions.push_back(kLegacy2KMaxFramerateAndResolution);
-    max_framerate_and_resolutions.push_back(kLegacy4KMaxFramerateAndResolution);
-  } else {
-    max_framerate_and_resolutions.push_back(kModern2KMaxFramerateAndResolution);
-    max_framerate_and_resolutions.push_back(kModern4KMaxFramerateAndResolution);
-    max_framerate_and_resolutions.push_back(kModern8KMaxFramerateAndResolution);
-  }
-
-  for (auto& max_framerate_and_resolution : max_framerate_and_resolutions) {
-    FramerateAndResolution framerate_and_resolution = {
-        CalculateMaxFramerateFromMacroBlocksPerSecond(
-            max_framerate_and_resolution, max_macroblocks_per_second),
-        max_framerate_and_resolution.resolution};
-
-    // Only if the calculated framerate >= the default framerate, we then
-    // consider this resolution & framerate combination is supported.
-    if (framerate_and_resolution.frame_rate >=
-        (kDefaultFrameRateNumerator / kDefaultFrameRateDenominator)) {
-      framerate_and_resolutions.push_back(framerate_and_resolution);
-    }
-  }
-
-  // If the received value of `max_macroblocks_per_second` equals to zero,
-  // assign a default value here.
-  if (framerate_and_resolutions.empty()) {
-    framerate_and_resolutions.push_back(kDefaultMaxFramerateAndResolution);
-  }
-
-  return framerate_and_resolutions;
-}
-
-// Ideally, we should query the API to get the minimum resolution of each codec
-// under each vendor. However, since there is no such API available, based on
-// the actual results, although the minimum resolutions of different codecs for
-// each vendor vary, but the results always remain consistent among different
-// GPU models. Therefore, we can just hardcode these values within the function.
-gfx::Size GetMinResolution(
-    VideoCodec codec,
-    MediaFoundationVideoEncodeAccelerator::DriverVendor vendor) {
-  using DriverVendor = MediaFoundationVideoEncodeAccelerator::DriverVendor;
-  switch (codec) {
-    case VideoCodec::kH264:
-      switch (vendor) {
-        case DriverVendor::kAMD:
-          // Below result based on: AMD Radeon(TM) Graphics (Ryzen 7 Pro 4750U),
-          // AMD Radeon(TM) Graphics (Ryzen 9 9950X), AMD Radeon(TM) RX 6600.
-          return gfx::Size(128, 128);
-        case DriverVendor::kIntel:
-          // Below result based on: Intel UHD Graphics 750, Intel Arc(TM) A380,
-          // Intel Arc(TM) Graphic (Ultra5 125H), Intel(R) Iris(R) Xe MAX
-          // Graphics.
-          return gfx::Size(18, 18);
-        case DriverVendor::kNvidia:
-          // Below result based on: NVIDIA RTX 3050, NVIDIA RTX 3070, NVIDIA RTX
-          // 4080.
-          return gfx::Size(146, 50);
-        case DriverVendor::kQualcomm:
-          // Below result based on: Qualcomm(R) Adreno(TM) 690, Qualcomm(R)
-          // Adreno(TM) X1-85.
-          return gfx::Size(96, 96);
-        case DriverVendor::kOther:
-          return kDefaultMinResolution;
-      }
-    case VideoCodec::kHEVC:
-      switch (vendor) {
-        case DriverVendor::kAMD:
-          // Below result based on: AMD Radeon(TM) Graphics (Ryzen 7 Pro 4750U),
-          // AMD Radeon(TM) Graphics (Ryzen 9 9950X), AMD Radeon(TM) RX 6600.
-          return gfx::Size(130, 128);
-        case DriverVendor::kIntel:
-          // Below result based on: Intel UHD Graphics 750, Intel Arc(TM) A380,
-          // Intel Arc(TM) Graphic (Ultra5 125H), Intel(R) Iris(R) Xe MAX
-          // Graphics.
-          return gfx::Size(66, 114);
-        case DriverVendor::kNvidia:
-          // Below result based on: NVIDIA RTX 3050, NVIDIA RTX 3070, NVIDIA RTX
-          // 4080.
-          return gfx::Size(130, 34);
-        case DriverVendor::kQualcomm:
-          // Below result based on: Qualcomm(R) Adreno(TM) 690, Qualcomm(R)
-          // Adreno(TM) X1-85.
-          return gfx::Size(96, 96);
-        case DriverVendor::kOther:
-          return kDefaultMinResolution;
-      }
-    case VideoCodec::kVP9:
-      switch (vendor) {
-        case DriverVendor::kAMD:
-          // Below result based on: AMD Radeon(TM) Graphics (Ryzen 9 9950X).
-          return gfx::Size(66, 66);
-        case DriverVendor::kIntel:
-          // Below result based on: Intel UHD Graphics 750, Intel Arc(TM) A380,
-          // Intel Arc(TM) Graphic (Ultra5 125H), Intel(R) Iris(R) Xe MAX
-          // Graphics.
-          //
-          // NOTE: Intel UHD Graphics 750, Intel Arc(TM) A380, Intel(R) Iris(R)
-          // Xe MAX Graphics actually only requires >= 66x66, but Intel Arc(TM)
-          // Graphic (Ultra5 125H) requires >= 66x120.
-          return gfx::Size(66, 120);
-        case DriverVendor::kNvidia:
-          // Below result based on: NVIDIA RTX 4080.
-          return gfx::Size(66, 66);
-        // As of the testing date, no Qualcomm hardware supports VP9 encoding.
-        case DriverVendor::kQualcomm:
-        case DriverVendor::kOther:
-          return kDefaultMinResolution;
-      }
-    case VideoCodec::kAV1:
-      switch (vendor) {
-        case DriverVendor::kAMD:
-          // Below result based on: AMD Radeon(TM) Graphics (Ryzen 9 9950X).
-          return gfx::Size(114, 82);
-        case DriverVendor::kIntel:
-          // Below result based on: Intel Arc(TM) A380, Intel Arc(TM) Graphic
-          // (Ultra5 125H).
-          return gfx::Size(114, 82);
-        case DriverVendor::kNvidia:
-          // Below result based on: NVIDIA RTX 4080.
-          return gfx::Size(130, 66);
-        case DriverVendor::kQualcomm:
-          // Below result based on: Qualcomm(R) Adreno(TM) X1-85.
-          return gfx::Size(256, 128);
-        case DriverVendor::kOther:
-          return kDefaultMinResolution;
-      }
-    default:
-      NOTREACHED();
-  }
-}
-
-int GetMaxTemporalLayer(VideoCodec codec,
-                        std::vector<ComPtr<IMFActivate>>& activates,
-                        const gpu::GpuDriverBugWorkarounds& workarounds) {
-  int num_temporal_layers = 1;
-
-  for (size_t i = 0; i < activates.size(); i++) {
-    num_temporal_layers = std::max(
-        GetNumSupportedTemporalLayers(activates[i].Get(), codec, workarounds),
-        num_temporal_layers);
-  }
-
-  return num_temporal_layers;
-}
-
 // Per
 // https://learn.microsoft.com/en-us/windows/win32/medfound/handling-stream-changes,
 // encoders should only accept an input type that matches the currently
@@ -1088,117 +272,10 @@
   DVLOG(3) << __func__;
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  std::vector<VideoCodec> supported_codecs(
-      {VideoCodec::kH264, VideoCodec::kVP9, VideoCodec::kAV1});
+  MediaFoundationVideoEncoderSharedState* mf_shared_state =
+      MediaFoundationVideoEncoderSharedState::GetInstance(workarounds_);
 
-#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
-  if (base::FeatureList::IsEnabled(kPlatformHEVCEncoderSupport)) {
-    supported_codecs.emplace_back(VideoCodec::kHEVC);
-  }
-#endif
-
-  SupportedProfiles profiles;
-  for (auto codec : supported_codecs) {
-    auto activates = EnumerateHardwareEncoders(codec);
-    if (activates.empty()) {
-      DVLOG(1) << "Hardware encode acceleration is not available for "
-               << GetCodecName(codec);
-      continue;
-    }
-
-    int num_temporal_layers =
-        GetMaxTemporalLayer(codec, activates, workarounds_);
-    auto bitrate_mode = VideoEncodeAccelerator::kConstantMode |
-                        VideoEncodeAccelerator::kVariableMode;
-    if (codec == VideoCodec::kH264) {
-      bitrate_mode |= VideoEncodeAccelerator::kExternalMode;
-    }
-
-    std::vector<FramerateAndResolution> max_framerate_and_resolutions = {
-        kDefaultMaxFramerateAndResolution};
-    gfx::Size min_resolution = kDefaultMinResolution;
-
-    if (base::FeatureList::IsEnabled(
-            kExpandMediaFoundationEncodingResolutions)) {
-      // https://crbug.com/40233328, Ideally we'd want supported profiles to
-      // return the max supported resolution and then during configure() to
-      // find the encoder which can support the right resolution.
-      // For now checking only the first encoder seems okay, but we probably
-      // still need the configure() part: ensure that selected one supports the
-      // given resolution of the first encoder.
-      IMFActivate* activate = activates[0].Get();
-      ComPtr<IMFTransform> encoder;
-      if (FAILED(activate->ActivateObject(IID_PPV_ARGS(&encoder)))) {
-        continue;
-      }
-
-      CHECK(encoder);
-      max_framerate_and_resolutions = GetMaxFramerateAndResolutionsFromMFT(
-          codec, encoder.Get(), /*allow_set_output_type=*/true);
-      min_resolution = GetMinResolution(codec, GetDriverVendor(activate));
-      activate->ShutdownObject();
-    }
-
-    for (auto& max_framerate_and_resolution : max_framerate_and_resolutions) {
-      DVLOG(3) << __func__ << ": " << codec << " codec, max resolution width: "
-               << max_framerate_and_resolution.resolution.width()
-               << ", height: "
-               << max_framerate_and_resolution.resolution.height()
-               << ", min resolution width: " << min_resolution.width()
-               << ", height: " << min_resolution.height()
-               << ", framerate: " << max_framerate_and_resolution.frame_rate;
-
-      SupportedProfile profile(VIDEO_CODEC_PROFILE_UNKNOWN,
-                               max_framerate_and_resolution.resolution,
-                               max_framerate_and_resolution.frame_rate *
-                                   kDefaultFrameRateDenominator,
-                               kDefaultFrameRateDenominator, bitrate_mode,
-                               {SVCScalabilityMode::kL1T1});
-      profile.min_resolution = min_resolution;
-
-      if (!workarounds_.disable_svc_encoding) {
-        if (num_temporal_layers >= 2) {
-          profile.scalability_modes.push_back(SVCScalabilityMode::kL1T2);
-        }
-        if (num_temporal_layers >= 3) {
-          profile.scalability_modes.push_back(SVCScalabilityMode::kL1T3);
-        }
-      }
-
-      if (base::FeatureList::IsEnabled(kMediaFoundationD3DVideoProcessing)) {
-        base::ranges::copy(
-            kSupportedPixelFormatsD3DVideoProcessing,
-            std::back_inserter(profile.gpu_supported_pixel_formats));
-      }
-
-      SupportedProfile portrait_profile(profile);
-      portrait_profile.max_resolution.Transpose();
-
-      if (base::FeatureList::IsEnabled(kMediaFoundationSharedImageEncode)) {
-        profile.supports_gpu_shared_images = true;
-      }
-
-      std::vector<VideoCodecProfile> codec_profiles;
-      if (codec == VideoCodec::kH264) {
-        codec_profiles = {H264PROFILE_BASELINE, H264PROFILE_MAIN,
-                          H264PROFILE_HIGH};
-      } else if (codec == VideoCodec::kVP9) {
-        codec_profiles = {VP9PROFILE_PROFILE0};
-      } else if (codec == VideoCodec::kAV1) {
-        codec_profiles = {AV1PROFILE_PROFILE_MAIN};
-      } else if (codec == VideoCodec::kHEVC) {
-        codec_profiles = {HEVCPROFILE_MAIN};
-      }
-
-      for (const auto codec_profile : codec_profiles) {
-        profile.profile = portrait_profile.profile = codec_profile;
-        profiles.push_back(profile);
-        profiles.push_back(portrait_profile);
-      }
-    }
-  }
-
-  return profiles;
+  return mf_shared_state->GetSupportedProfiles();
 }
 
 bool MediaFoundationVideoEncodeAccelerator::Initialize(
@@ -1337,22 +414,33 @@
   // Get the max framerate and max/min resolutions of the given codec.
   //
   // NOTE:
-  // We use the actual encoder to retrieve max framerate and max/min
-  // resolutions. The property `MF_VIDEO_MAX_MB_PER_SEC`, which we use to
-  // calculate the resolution, is a static value stored in the encoder provided
-  // by the GPU driver. It doesn't change regardless of the parameters we set
-  // for `SetOutputType()` except for `MF_MT_MAJOR_TYPE` and `MF_MT_SUBTYPE`.
-  // So, as long as the actual encoder remains the same, the result should be
-  // unchanged.
-  //
-  // On a dual GPU system, the actual encoder selected might be different from
-  // the one used by "GetSupportedProfile". If that's the case, and if the
-  // actual encoder can't handle the incoming resolution, we can simply reject
-  // it without hesitation.
+  // We first attempt to retrieve max framerate and max/min resolutions from
+  // cached data. If there is a cache miss, that implies the current encoder is
+  // not on the same adapter as that used by "GetSupportedProfiles". If so we
+  // use the actual encoder to retrieve max framerate and max/min resolutions.
+  // The property `MF_VIDEO_MAX_MB_PER_SEC`, which we use to calculate the
+  // resolution, is a static value stored in the encoder provided by the GPU
+  // driver. It doesn't change regardless of the parameters we set for
+  // `SetOutputType()` except for `MF_MT_MAJOR_TYPE` and `MF_MT_SUBTYPE`. So, as
+  // long as the actual encoder remains the same, the result should be
+  // unchanged. If the actual encoder can't handle the incoming resolution, we
+  // can simply reject it without hesitation.
   if (base::FeatureList::IsEnabled(kExpandMediaFoundationEncodingResolutions)) {
-    max_framerate_and_resolutions_ = GetMaxFramerateAndResolutionsFromMFT(
-        codec_, encoder_.Get(), /*allow_set_output_type=*/false);
-    min_resolution_ = GetMinResolution(codec_, vendor_);
+    size_t activate_hash = GetMFTGuidHash(activate_.Get());
+    MediaFoundationVideoEncoderSharedState* shared_state =
+        MediaFoundationVideoEncoderSharedState::GetInstance(workarounds_);
+    DCHECK(shared_state);
+    const auto& max_framerate_and_resolutions =
+        shared_state->GetMaxFramerateAndResolutions(activate_hash);
+    const auto& min_resolution = shared_state->GetMinResolution(activate_hash);
+    max_framerate_and_resolutions_ =
+        !max_framerate_and_resolutions.empty()
+            ? max_framerate_and_resolutions
+            : GetMaxFramerateAndResolutionsFromMFT(
+                  codec_, encoder_.Get(), /*allow_set_output_type=*/false);
+    min_resolution_ = !min_resolution.IsEmpty()
+                          ? min_resolution
+                          : GetMinResolution(codec_, vendor_);
   } else {
     max_framerate_and_resolutions_ = {kDefaultMaxFramerateAndResolution};
     min_resolution_ = kDefaultMinResolution;
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.h b/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
index 4712f70..61bb8fe1 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
@@ -34,16 +34,12 @@
 #include "media/gpu/command_buffer_helper.h"
 #include "media/gpu/media_gpu_export.h"
 #include "media/gpu/windows/d3d_com_defs.h"
+#include "media/gpu/windows/mf_video_encoder_util.h"
 #include "media/gpu/windows/mf_video_processor_accelerator.h"
 #include "media/video/video_encode_accelerator.h"
 
 namespace media {
 
-struct FramerateAndResolution {
-  uint32_t frame_rate;
-  gfx::Size resolution;
-};
-
 class VideoRateControlWrapper;
 class TemporalScalabilityIdExtractor;
 
@@ -104,8 +100,6 @@
   IFACEMETHODIMP_(ULONG) Release() override;
   IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
 
-  enum class DriverVendor { kOther, kNvidia, kIntel, kAMD, kQualcomm };
-
   struct GetCommandBufferHelperResult {
     GetCommandBufferHelperResult();
     GetCommandBufferHelperResult(const GetCommandBufferHelperResult& other);
diff --git a/media/gpu/windows/mf_video_encoder_shared_state.cc b/media/gpu/windows/mf_video_encoder_shared_state.cc
new file mode 100644
index 0000000..69fa3b9e
--- /dev/null
+++ b/media/gpu/windows/mf_video_encoder_shared_state.cc
@@ -0,0 +1,250 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/gpu/windows/mf_video_encoder_shared_state.h"
+
+#include <objbase.h>
+
+#include <codecapi.h>
+#include <mfapi.h>
+#include <mferror.h>
+#include <mftransform.h>
+#include <wrl/client.h>
+
+#include <utility>
+
+#include "base/features.h"
+#include "base/logging.h"
+#include "base/win/scoped_co_mem.h"
+#include "base/win/scoped_variant.h"
+#include "base/win/win_util.h"
+#include "build/build_config.h"
+#include "media/base/media_switches.h"
+#include "media/base/win/mf_helpers.h"
+#include "media/gpu/windows/d3d_com_defs.h"
+#include "media/gpu/windows/mf_video_encoder_switches.h"
+
+namespace media {
+
+namespace {
+
+int GetNumSupportedTemporalLayers(
+    IMFActivate* activate,
+    VideoCodec codec,
+    const gpu::GpuDriverBugWorkarounds& workarounds) {
+  auto vendor = GetDriverVendor(activate);
+  int max_temporal_layer_vendor_limit =
+      GetMaxTemporalLayerVendorLimit(vendor, codec, workarounds);
+  if (max_temporal_layer_vendor_limit == 1) {
+    return 1;
+  }
+
+  ComMFTransform encoder;
+  ComCodecAPI codec_api;
+  HRESULT hr = activate->ActivateObject(IID_PPV_ARGS(&encoder));
+  if (FAILED(hr)) {
+    // Log to VLOG since errors are expected as part of GetSupportedProfiles().
+    DVLOG(2) << "Failed to activate encoder: " << PrintHr(hr);
+    return 1;
+  }
+
+  hr = encoder.As(&codec_api);
+  if (FAILED(hr)) {
+    // Log to VLOG since errors are expected as part of GetSupportedProfiles().
+    DVLOG(2) << "Failed to get encoder as CodecAPI: " << PrintHr(hr);
+    return 1;
+  }
+
+  if (codec_api->IsSupported(&CODECAPI_AVEncVideoTemporalLayerCount) != S_OK) {
+    return 1;
+  }
+
+  base::win::ScopedVariant min, max, step;
+  if (FAILED(codec_api->GetParameterRange(
+          &CODECAPI_AVEncVideoTemporalLayerCount, min.AsInput(), max.AsInput(),
+          step.AsInput()))) {
+    return 1;
+  }
+
+  // Temporal encoding is only considered supported if the driver reports at
+  // least a span of 1-3 temporal layers.
+  if (V_UI4(min.ptr()) > 1u || V_UI4(max.ptr()) < 3u) {
+    return 1;
+  }
+  return max_temporal_layer_vendor_limit;
+}
+
+int GetMaxTemporalLayer(
+    VideoCodec codec,
+    std::vector<Microsoft::WRL::ComPtr<IMFActivate>>& activates,
+    const gpu::GpuDriverBugWorkarounds& workarounds) {
+  int num_temporal_layers = 1;
+
+  for (size_t i = 0; i < activates.size(); i++) {
+    num_temporal_layers = std::max(
+        GetNumSupportedTemporalLayers(activates[i].Get(), codec, workarounds),
+        num_temporal_layers);
+  }
+
+  return num_temporal_layers;
+}
+
+}  // namespace
+
+// static
+MediaFoundationVideoEncoderSharedState*
+MediaFoundationVideoEncoderSharedState::GetInstance(
+    const gpu::GpuDriverBugWorkarounds& workarounds) {
+  static MediaFoundationVideoEncoderSharedState* instance =
+      new MediaFoundationVideoEncoderSharedState(workarounds);
+  return instance;
+}
+
+MediaFoundationVideoEncoderSharedState::
+    ~MediaFoundationVideoEncoderSharedState() = default;
+
+MediaFoundationVideoEncoderSharedState::MediaFoundationVideoEncoderSharedState(
+    const gpu::GpuDriverBugWorkarounds& workarounds)
+    : workarounds_(workarounds) {
+  GetSupportedProfilesInternal();
+}
+
+const std::vector<FramerateAndResolution>
+MediaFoundationVideoEncoderSharedState::GetMaxFramerateAndResolutions(
+    size_t activate_hash) const {
+  auto it = max_framerate_and_resolutions_.find(activate_hash);
+  if (it != max_framerate_and_resolutions_.end()) {
+    return it->second;
+  }
+  return {};
+}
+
+const gfx::Size MediaFoundationVideoEncoderSharedState::GetMinResolution(
+    size_t activate_hash) const {
+  auto it = min_resolutions_.find(activate_hash);
+  if (it != min_resolutions_.end()) {
+    return it->second;
+  }
+  return {};
+}
+
+void MediaFoundationVideoEncoderSharedState::GetSupportedProfilesInternal() {
+  std::vector<VideoCodec> supported_codecs(
+      {VideoCodec::kH264, VideoCodec::kVP9, VideoCodec::kAV1});
+
+#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
+  if (base::FeatureList::IsEnabled(kPlatformHEVCEncoderSupport)) {
+    supported_codecs.emplace_back(VideoCodec::kHEVC);
+  }
+#endif
+
+  for (auto codec : supported_codecs) {
+    auto activates = EnumerateHardwareEncoders(codec);
+    if (activates.empty()) {
+      DVLOG(1) << "Hardware encode acceleration is not available for "
+               << GetCodecName(codec);
+      continue;
+    }
+
+    int num_temporal_layers =
+        GetMaxTemporalLayer(codec, activates, workarounds_);
+    auto bitrate_mode = VideoEncodeAccelerator::kConstantMode |
+                        VideoEncodeAccelerator::kVariableMode;
+    if (codec == VideoCodec::kH264) {
+      bitrate_mode |= VideoEncodeAccelerator::kExternalMode;
+    }
+
+    std::vector<FramerateAndResolution> max_framerate_and_resolutions = {
+        kDefaultMaxFramerateAndResolution};
+    gfx::Size min_resolution = kDefaultMinResolution;
+
+    size_t activate_hash = 0;
+    if (base::FeatureList::IsEnabled(
+            kExpandMediaFoundationEncodingResolutions)) {
+      // https://crbug.com/40233328, Ideally we'd want supported profiles to
+      // return the max supported resolution and then during configure() to
+      // find the encoder which can support the right resolution.
+      // For now checking only the first encoder seems okay, but we probably
+      // still need the configure() part: ensure that selected one supports the
+      // given resolution of the first encoder.
+      IMFActivate* activate = activates[0].Get();
+      Microsoft::WRL::ComPtr<IMFTransform> encoder;
+      if (FAILED(activate->ActivateObject(IID_PPV_ARGS(&encoder)))) {
+        continue;
+      }
+
+      activate_hash = GetMFTGuidHash(activate);
+      CHECK(encoder);
+      max_framerate_and_resolutions = GetMaxFramerateAndResolutionsFromMFT(
+          codec, encoder.Get(), /*allow_set_output_type=*/true);
+      min_resolution =
+          ::media::GetMinResolution(codec, GetDriverVendor(activate));
+      activate->ShutdownObject();
+    }
+
+    for (auto& max_framerate_and_resolution : max_framerate_and_resolutions) {
+      DVLOG(3) << __func__ << ": " << codec << " codec, max resolution width: "
+               << max_framerate_and_resolution.resolution.width()
+               << ", height: "
+               << max_framerate_and_resolution.resolution.height()
+               << ", min resolution width: " << min_resolution.width()
+               << ", height: " << min_resolution.height()
+               << ", framerate: " << max_framerate_and_resolution.frame_rate;
+
+      VideoEncodeAccelerator::SupportedProfile profile(
+          VIDEO_CODEC_PROFILE_UNKNOWN, max_framerate_and_resolution.resolution,
+          max_framerate_and_resolution.frame_rate *
+              kDefaultFrameRateDenominator,
+          kDefaultFrameRateDenominator, bitrate_mode,
+          {SVCScalabilityMode::kL1T1});
+      profile.min_resolution = min_resolution;
+
+      if (!workarounds_.disable_svc_encoding) {
+        if (num_temporal_layers >= 2) {
+          profile.scalability_modes.push_back(SVCScalabilityMode::kL1T2);
+        }
+        if (num_temporal_layers >= 3) {
+          profile.scalability_modes.push_back(SVCScalabilityMode::kL1T3);
+        }
+      }
+
+      if (base::FeatureList::IsEnabled(kMediaFoundationD3DVideoProcessing)) {
+        base::ranges::copy(
+            kSupportedPixelFormatsD3DVideoProcessing,
+            std::back_inserter(profile.gpu_supported_pixel_formats));
+      }
+
+      VideoEncodeAccelerator::SupportedProfile portrait_profile(profile);
+      portrait_profile.max_resolution.Transpose();
+
+      if (base::FeatureList::IsEnabled(kMediaFoundationSharedImageEncode)) {
+        profile.supports_gpu_shared_images = true;
+      }
+
+      std::vector<VideoCodecProfile> codec_profiles;
+      if (codec == VideoCodec::kH264) {
+        codec_profiles = {H264PROFILE_BASELINE, H264PROFILE_MAIN,
+                          H264PROFILE_HIGH};
+      } else if (codec == VideoCodec::kVP9) {
+        codec_profiles = {VP9PROFILE_PROFILE0};
+      } else if (codec == VideoCodec::kAV1) {
+        codec_profiles = {AV1PROFILE_PROFILE_MAIN};
+      } else if (codec == VideoCodec::kHEVC) {
+        codec_profiles = {HEVCPROFILE_MAIN};
+      }
+
+      for (const auto codec_profile : codec_profiles) {
+        profile.profile = portrait_profile.profile = codec_profile;
+        supported_profiles_.push_back(profile);
+        supported_profiles_.push_back(portrait_profile);
+      }
+    }
+
+    max_framerate_and_resolutions_[activate_hash] =
+        std::move(max_framerate_and_resolutions);
+    min_resolutions_[activate_hash] = std::move(min_resolution);
+  }
+}
+
+}  // namespace media
diff --git a/media/gpu/windows/mf_video_encoder_shared_state.h b/media/gpu/windows/mf_video_encoder_shared_state.h
new file mode 100644
index 0000000..c3614f2b
--- /dev/null
+++ b/media/gpu/windows/mf_video_encoder_shared_state.h
@@ -0,0 +1,63 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_GPU_WINDOWS_MF_VIDEO_ENCODER_SHARED_STATE_H_
+#define MEDIA_GPU_WINDOWS_MF_VIDEO_ENCODER_SHARED_STATE_H_
+
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "gpu/config/gpu_driver_bug_workarounds.h"
+#include "media/gpu/media_gpu_export.h"
+#include "media/gpu/windows/mf_video_encoder_util.h"
+#include "media/video/video_encode_accelerator.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace media {
+
+// This class is used to share some common states among multiple instances of
+// MediaFoundationVideoEncodeAccelerator, such as supported profiles, max
+// supported resolutions and framerates, as well as minimum supported resolution
+// of HMFTs enumerated on the platform.
+class MEDIA_GPU_EXPORT MediaFoundationVideoEncoderSharedState {
+ public:
+  static MediaFoundationVideoEncoderSharedState* GetInstance(
+      const gpu::GpuDriverBugWorkarounds& workarounds);
+
+  MediaFoundationVideoEncoderSharedState(
+      const MediaFoundationVideoEncoderSharedState&) = delete;
+  MediaFoundationVideoEncoderSharedState& operator=(
+      const MediaFoundationVideoEncoderSharedState&) = delete;
+
+  const VideoEncodeAccelerator::SupportedProfiles& GetSupportedProfiles()
+      const {
+    return supported_profiles_;
+  }
+
+  // Returns the maximum framerate and resolution combinations supported by the
+  // activate whose CLSID hash is |activate_hash|.
+  const std::vector<FramerateAndResolution> GetMaxFramerateAndResolutions(
+      size_t activate_hash) const;
+
+  // Returns the minimum resolution supported by the activate whose CLSID hash
+  // is |activate_hash|.
+  const gfx::Size GetMinResolution(size_t activate_hash) const;
+
+ private:
+  MediaFoundationVideoEncoderSharedState(
+      const gpu::GpuDriverBugWorkarounds& workarounds);
+  virtual ~MediaFoundationVideoEncoderSharedState();
+
+  void GetSupportedProfilesInternal();
+
+  gpu::GpuDriverBugWorkarounds workarounds_;
+  VideoEncodeAccelerator::SupportedProfiles supported_profiles_;
+  base::flat_map<size_t, std::vector<FramerateAndResolution>>
+      max_framerate_and_resolutions_;
+  base::flat_map<size_t, gfx::Size> min_resolutions_;
+};
+
+}  // namespace media
+
+#endif  // MEDIA_GPU_WINDOWS_MF_VIDEO_ENCODER_SHARED_STATE_H_
diff --git a/media/gpu/windows/mf_video_encoder_switches.cc b/media/gpu/windows/mf_video_encoder_switches.cc
new file mode 100644
index 0000000..b4a7a84
--- /dev/null
+++ b/media/gpu/windows/mf_video_encoder_switches.cc
@@ -0,0 +1,61 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/gpu/windows/mf_video_encoder_switches.h"
+
+namespace media {
+
+BASE_FEATURE(kExpandMediaFoundationEncodingResolutions,
+             "ExpandMediaFoundationEncodingResolutions",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
+#ifndef ARCH_CPU_X86
+// Temporal layers are reported to be supported by the Intel driver, but are
+// only considered supported by MediaFoundation depending on these flags. This
+// support is reported in MediaCapabilities' powerEfficient as well as deciding
+// if Initialize() is allowed to succeed.
+BASE_FEATURE(kMediaFoundationVP9L1T2Support,
+             "MediaFoundationVP9L1T2Support",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+// Up to 3 temporal layers, i.e. this enables both L1T2 and L1T3.
+BASE_FEATURE(kMediaFoundationVP9L1T3Support,
+             "MediaFoundationVP9L1T3Support",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+BASE_FEATURE(kMediaFoundationAV1L1T2Support,
+             "MediaFoundationAV1L1T2Support",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+// Up to 3 temporal layers, i.e. this enables both L1T2 and L1T3.
+BASE_FEATURE(kMediaFoundationAV1L1T3Support,
+             "MediaFoundationAV1L1T3Support",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+#endif  // !defined(ARCH_CPU_X86)
+
+BASE_FEATURE(kMediaFoundationUseSWBRCForH264Camera,
+             "MediaFoundationUseSWBRCForH264Camera",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kMediaFoundationUseSWBRCForH264Desktop,
+             "MediaFoundationUseSWBRCForH264Desktop",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+// H.264 SW Bitrate Controller works in fixed delta QP mode by default. The QP
+// difference between base and enhancement layer can be controlled using a
+// feature parameter.
+BASE_FEATURE(kMediaFoundationSWBRCUseFixedDeltaQP,
+             "MediaFoundationSWBRCUseFixedDeltaQP",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+const base::FeatureParam<int> kMediaFoundationSWBRCFixedDeltaQPValue(
+    &kMediaFoundationSWBRCUseFixedDeltaQP,
+    "MediaFoundationSWBRCFixedDeltaQPValue",
+    0);
+
+#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
+// For H.265 encoding at L1T1/L1T2 we may use SW bitrate controller when
+// constant bitrate encoding is requested.
+BASE_FEATURE(kMediaFoundationUseSWBRCForH265,
+             "MediaFoundationUseSWBRCForH265",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+#endif  // BUILDFLAG(ENABLE_PLATFORM_HEVC)
+
+}  // namespace media
diff --git a/media/gpu/windows/mf_video_encoder_switches.h b/media/gpu/windows/mf_video_encoder_switches.h
new file mode 100644
index 0000000..9a92052
--- /dev/null
+++ b/media/gpu/windows/mf_video_encoder_switches.h
@@ -0,0 +1,40 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_GPU_WINDOWS_MF_VIDEO_ENCODER_SWITCHES_H_
+#define MEDIA_GPU_WINDOWS_MF_VIDEO_ENCODER_SWITCHES_H_
+
+#include <stdint.h>
+
+#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
+#include "build/build_config.h"
+#include "build/buildflag.h"
+#include "media/gpu/buildflags.h"
+#include "media/media_buildflags.h"
+
+namespace media {
+
+BASE_DECLARE_FEATURE(kExpandMediaFoundationEncodingResolutions);
+
+#ifndef ARCH_CPU_X86
+BASE_DECLARE_FEATURE(kMediaFoundationVP9L1T2Support);
+BASE_DECLARE_FEATURE(kMediaFoundationVP9L1T3Support);
+BASE_DECLARE_FEATURE(kMediaFoundationAV1L1T2Support);
+BASE_DECLARE_FEATURE(kMediaFoundationAV1L1T3Support);
+#endif  // !defined(ARCH_CPU_X86)
+
+BASE_DECLARE_FEATURE(kMediaFoundationUseSWBRCForH264Camera);
+BASE_DECLARE_FEATURE(kMediaFoundationUseSWBRCForH264Desktop);
+
+BASE_DECLARE_FEATURE(kMediaFoundationSWBRCUseFixedDeltaQP);
+extern const base::FeatureParam<int> kMediaFoundationSWBRCFixedDeltaQPValue;
+
+#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
+BASE_DECLARE_FEATURE(kMediaFoundationUseSWBRCForH265);
+#endif  // BUILDFLAG(ENABLE_PLATFORM_HEVC)
+
+}  // namespace media
+
+#endif  // MEDIA_GPU_WINDOWS_MF_VIDEO_ENCODER_SWITCHES_H_
diff --git a/media/gpu/windows/mf_video_encoder_util.cc b/media/gpu/windows/mf_video_encoder_util.cc
new file mode 100644
index 0000000..adb35ea
--- /dev/null
+++ b/media/gpu/windows/mf_video_encoder_util.cc
@@ -0,0 +1,701 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifdef UNSAFE_BUFFERS_BUILD
+// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
+#pragma allow_unsafe_buffers
+#endif
+
+#include "media/gpu/windows/mf_video_encoder_util.h"
+
+#include "base/check.h"
+#include "base/containers/span.h"
+#include "base/hash/hash.h"
+#include "base/native_library.h"
+#include "base/win/scoped_co_mem.h"
+#include "base/win/scoped_variant.h"
+#include "base/win/win_util.h"
+#include "build/build_config.h"
+#include "media/base/media_switches.h"
+#include "media/base/win/mf_helpers.h"
+#include "media/base/win/mf_initializer.h"
+#include "media/gpu/windows/mf_video_encoder_switches.h"
+
+namespace media {
+
+// AVEncVideoEncodeQP maps QP to libvpx qp tuning parameter
+// and thus the range is 0-63.
+uint8_t QindextoAVEncQP(VideoCodec codec, uint8_t q_index) {
+  if (codec == VideoCodec::kAV1 || codec == VideoCodec::kVP9) {
+    // The following computation is based on the table in
+    // //third_party/libvpx/source/libvpx/vp9/encoder/vp9_quantize.c.
+    // //third_party/libaom/source/libaom/av1/encoder/av1_quantize.c
+    // {
+    //   0,   4,   8,   12,  16,  20,  24,  28,  32,  36,  40,  44,  48,
+    //   52,  56,  60,  64,  68,  72,  76,  80,  84,  88,  92,  96,  100,
+    //   104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152,
+    //   156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204,
+    //   208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 249, 255,
+    // };
+    if (q_index <= 244) {
+      return (q_index + 3) / 4;
+    }
+    if (q_index <= 249) {
+      return 62;
+    }
+    return 63;
+  }
+  return q_index;
+}
+
+// This is the inverse of QindextoAVEncQP() function.
+uint8_t AVEncQPtoQindex(VideoCodec codec, uint8_t avenc_qp) {
+  if (codec == VideoCodec::kAV1 || codec == VideoCodec::kVP9) {
+    uint8_t q_index = avenc_qp * 4;
+    if (q_index == 248) {
+      q_index = 249;
+    } else if (q_index == 252) {
+      q_index = 255;
+    }
+    return q_index;
+  }
+  return avenc_qp;
+}
+
+// According to AV1/VP9's bitstream specification, the valid range of qp
+// value (defined as base_q_idx) should be 0-255.
+bool IsValidQp(VideoCodec codec, uint64_t qp) {
+  switch (codec) {
+    case VideoCodec::kH264:
+#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
+    case VideoCodec::kHEVC:
+#endif  // BUILDFLAG(ENABLE_PLATFORM_HEVC)
+      return qp <= kH26xMaxQp;
+    case VideoCodec::kVP9:
+      return qp <= kVP9MaxQIndex;
+    case VideoCodec::kAV1:
+      return qp <= kAV1MaxQIndex;
+    default:
+      return false;
+  }
+}
+
+uint8_t GetMaxQuantizer(VideoCodec codec) {
+  switch (codec) {
+    case VideoCodec::kH264:
+      return kH264MaxQuantizer;
+#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
+    case VideoCodec::kHEVC:
+      return kH265MaxQuantizer;
+#endif  // BUILDFLAG(ENABLE_PLATFORM_HEVC)
+    case VideoCodec::kVP9:
+      return kVP9MaxQuantizer;
+    case VideoCodec::kAV1:
+      return kAV1MaxQuantizer;
+    default:
+      return 0;  // Return invalid value for unsupported codec.
+  }
+}
+
+eAVEncH264VProfile GetH264VProfile(VideoCodecProfile profile,
+                                   bool is_constrained_h264) {
+  switch (profile) {
+    case H264PROFILE_BASELINE:
+      return is_constrained_h264 ? eAVEncH264VProfile_ConstrainedBase
+                                 : eAVEncH264VProfile_Base;
+    case H264PROFILE_MAIN:
+      return eAVEncH264VProfile_Main;
+    case H264PROFILE_HIGH:
+      return eAVEncH264VProfile_High;
+    default:
+      return eAVEncH264VProfile_unknown;
+  }
+}
+
+// Only eAVEncVP9VProfile_420_8 is supported on Intel graphics.
+eAVEncVP9VProfile GetVP9VProfile(VideoCodecProfile profile) {
+  switch (profile) {
+    case VP9PROFILE_PROFILE0:
+      return eAVEncVP9VProfile_420_8;
+    default:
+      return eAVEncVP9VProfile_unknown;
+  }
+}
+
+// Only eAVEncH265Vprofile_Main_420_8 is supported.
+eAVEncH265VProfile GetHEVCProfile(VideoCodecProfile profile) {
+  switch (profile) {
+    case HEVCPROFILE_MAIN:
+      return eAVEncH265VProfile_Main_420_8;
+    default:
+      return eAVEncH265VProfile_unknown;
+  }
+}
+
+DriverVendor GetDriverVendor(IMFActivate* encoder) {
+  DCHECK(encoder);
+  base::win::ScopedCoMem<WCHAR> vendor_id;
+  UINT32 id_length;
+  encoder->GetAllocatedString(MFT_ENUM_HARDWARE_VENDOR_ID_Attribute, &vendor_id,
+                              &id_length);
+  if (id_length != 8) {  // Normal vendor ids have length 8.
+    return DriverVendor::kOther;
+  }
+  if (!_wcsnicmp(vendor_id.get(), L"VEN_10DE", id_length)) {
+    return DriverVendor::kNvidia;
+  }
+  if (!_wcsnicmp(vendor_id.get(), L"VEN_1002", id_length)) {
+    return DriverVendor::kAMD;
+  }
+  if (!_wcsnicmp(vendor_id.get(), L"VEN_8086 ", id_length)) {
+    return DriverVendor::kIntel;
+  }
+  if (!_wcsnicmp(vendor_id.get(), L"VEN_QCOM", id_length)) {
+    return DriverVendor::kQualcomm;
+  }
+  return DriverVendor::kOther;
+}
+
+// The driver tells us how many temporal layers it supports, but we may need to
+// reduce this limit to avoid bad or untested drivers.
+int GetMaxTemporalLayerVendorLimit(
+    DriverVendor vendor,
+    VideoCodec codec,
+    const gpu::GpuDriverBugWorkarounds& workarounds) {
+#if defined(ARCH_CPU_X86)
+  // x86 systems sometimes crash in video drivers here.
+  // More info: https://crbug.com/1253748
+  return 1;
+#else
+  // crbug.com/1373780: Nvidia HEVC encoder reports supporting 3 temporal
+  // layers, but will fail initialization if configured to encoded with
+  // more than one temporal layers, thus we block Nvidia HEVC encoder for
+  // temporal SVC encoding.
+  if (codec == VideoCodec::kHEVC && vendor == DriverVendor::kNvidia) {
+    return 1;
+  }
+
+  // Qualcomm HEVC and AV1 encoders report temporal layer support, but will
+  // fail the tests currently, so block from temporal SVC encoding.
+  if ((codec == VideoCodec::kHEVC || codec == VideoCodec::kAV1) &&
+      vendor == DriverVendor::kQualcomm) {
+    return 1;
+  }
+
+  // Intel drivers with issues of dynamically changing bitrate at CBR mode for
+  // HEVC should be blocked from L1T3 encoding, as there is no SW BRC support
+  // for that at present.
+  if (codec == VideoCodec::kHEVC && vendor == DriverVendor::kIntel &&
+      workarounds.disable_hevc_hmft_cbr_encoding) {
+    return 2;
+  }
+
+  // Temporal layer encoding is disabled for VP9 unless a flag is enabled.
+  //
+  // For example, the Intel VP9 HW encoder reports supporting 3 temporal layers
+  // but the number of temporal layers we allow depends on feature flags. At the
+  // time of writing, Intel L1T3 may not be spec-compliant.
+  // - See https://crbug.com/1425117 for temporal layer foundation (L1T2/L1T3).
+  // - See https://crbug.com/1501767 for L1T2 rollout (not L1T3).
+  if (codec == VideoCodec::kVP9) {
+    if (vendor == DriverVendor::kIntel &&
+        workarounds.disable_vp9_hmft_temporal_encoding) {
+      return 1;
+    }
+
+    if (base::FeatureList::IsEnabled(kMediaFoundationVP9L1T3Support)) {
+      return 3;
+    }
+    if (base::FeatureList::IsEnabled(kMediaFoundationVP9L1T2Support)) {
+      return 2;
+    }
+    return 1;
+  }
+
+  if (codec == VideoCodec::kAV1) {
+    // Whenever you add to the allow-list a new temporal layer limit, make sure
+    // you update output bitstream metadata to indicate whether the encoded AV1
+    // bitstream follows WebRTC SVC spec.
+    if (vendor != DriverVendor::kIntel) {
+      return 1;
+    }
+    if (base::FeatureList::IsEnabled(kMediaFoundationAV1L1T3Support)) {
+      return 3;
+    }
+    if (base::FeatureList::IsEnabled(kMediaFoundationAV1L1T2Support)) {
+      return 2;
+    }
+    return 1;
+  }
+
+  // No driver/codec specific limit to enforce.
+  return 3;
+#endif
+}
+
+int GetNumSupportedTemporalLayers(
+    IMFActivate* activate,
+    VideoCodec codec,
+    const gpu::GpuDriverBugWorkarounds& workarounds) {
+  DCHECK(activate);
+  auto vendor = GetDriverVendor(activate);
+  int max_temporal_layer_vendor_limit =
+      GetMaxTemporalLayerVendorLimit(vendor, codec, workarounds);
+  if (max_temporal_layer_vendor_limit == 1) {
+    return 1;
+  }
+
+  ComMFTransform encoder;
+  ComCodecAPI codec_api;
+  HRESULT hr = activate->ActivateObject(IID_PPV_ARGS(&encoder));
+  if (FAILED(hr)) {
+    // Log to VLOG since errors are expected as part of GetSupportedProfiles().
+    DVLOG(2) << "Failed to activate encoder: " << PrintHr(hr);
+    return 1;
+  }
+
+  hr = encoder.As(&codec_api);
+  if (FAILED(hr)) {
+    // Log to VLOG since errors are expected as part of GetSupportedProfiles().
+    DVLOG(2) << "Failed to get encoder as CodecAPI: " << PrintHr(hr);
+    return 1;
+  }
+
+  if (codec_api->IsSupported(&CODECAPI_AVEncVideoTemporalLayerCount) != S_OK) {
+    return 1;
+  }
+
+  base::win::ScopedVariant min, max, step;
+  if (FAILED(codec_api->GetParameterRange(
+          &CODECAPI_AVEncVideoTemporalLayerCount, min.AsInput(), max.AsInput(),
+          step.AsInput()))) {
+    return 1;
+  }
+
+  // Temporal encoding is only considered supported if the driver reports at
+  // least a span of 1-3 temporal layers.
+  if (V_UI4(min.ptr()) > 1u || V_UI4(max.ptr()) < 3u) {
+    return 1;
+  }
+  return max_temporal_layer_vendor_limit;
+}
+
+bool IsIntelHybridAV1Encoder(IMFActivate* activate) {
+  DCHECK(activate);
+  if (GetDriverVendor(activate) == DriverVendor::kIntel) {
+    // Get the CLSID GUID of the HMFT.
+    GUID mft_guid = {0};
+    activate->GetGUID(MFT_TRANSFORM_CLSID_Attribute, &mft_guid);
+    if (mft_guid == kIntelAV1HybridEncoderCLSID) {
+      return true;
+    }
+  }
+  return false;
+}
+
+using MFTEnum2Type = decltype(&MFTEnum2);
+MFTEnum2Type GetMFTEnum2Function() {
+  static const MFTEnum2Type kMFTEnum2Func = []() {
+    auto mf_dll = base::LoadSystemLibrary(L"mfplat.dll");
+    return mf_dll ? reinterpret_cast<MFTEnum2Type>(
+                        base::GetFunctionPointerFromNativeLibrary(mf_dll,
+                                                                  "MFTEnum2"))
+                  : nullptr;
+  }();
+  return kMFTEnum2Func;
+}
+
+// If MFTEnum2 is unavailable, this uses MFTEnumEx and doesn't fill any
+// adapter information if there are more than one adapters.
+std::vector<Microsoft::WRL::ComPtr<IMFActivate>>
+EnumerateHardwareEncodersLegacy(VideoCodec codec) {
+  std::vector<Microsoft::WRL::ComPtr<IMFActivate>> encoders;
+
+  uint32_t flags = MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_SORTANDFILTER;
+  MFT_REGISTER_TYPE_INFO input_info;
+  input_info.guidMajorType = MFMediaType_Video;
+  input_info.guidSubtype = MFVideoFormat_NV12;
+  MFT_REGISTER_TYPE_INFO output_info;
+  output_info.guidMajorType = MFMediaType_Video;
+  output_info.guidSubtype = VideoCodecToMFSubtype(codec);
+
+  Microsoft::WRL::ComPtr<IDXGIFactory1> factory;
+  auto hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
+  if (FAILED(hr)) {
+    DVLOG(2) << "Failed to create DXGI Factory";
+    return encoders;
+  }
+
+  LUID single_adapter_luid{0, 0};
+  int num_adapters = 0;
+
+  Microsoft::WRL::ComPtr<IDXGIAdapter> temp_adapter;
+  for (UINT adapter_idx = 0;
+       SUCCEEDED(factory->EnumAdapters(adapter_idx, &temp_adapter));
+       adapter_idx++) {
+    ++num_adapters;
+
+    DXGI_ADAPTER_DESC desc;
+    hr = temp_adapter->GetDesc(&desc);
+    if (FAILED(hr)) {
+      continue;
+    }
+
+    if (desc.VendorId == 0x1414 && desc.DeviceId == 0x8c) {
+      // Skip MS software adapters.
+      --num_adapters;
+    } else {
+      single_adapter_luid = desc.AdapterLuid;
+    }
+  }
+
+  IMFActivate** pp_activates = nullptr;
+  uint32_t count = 0;
+  hr = MFTEnumEx(MFT_CATEGORY_VIDEO_ENCODER, flags, &input_info, &output_info,
+                 &pp_activates, &count);
+
+  if (FAILED(hr)) {
+    // Log to VLOG since errors are expected as part of
+    // GetSupportedProfiles().
+    DVLOG(2) << "Failed to enumerate hardware encoders for "
+             << GetCodecName(codec) << " : " << PrintHr(hr);
+    return encoders;
+  }
+
+  for (UINT32 i = 0; i < count; i++) {
+    if (codec == VideoCodec::kAV1 && IsIntelHybridAV1Encoder(pp_activates[i])) {
+      continue;
+    }
+
+    // We can still infer the MFT's adapter LUID if there's only one adapter
+    // in the system.
+    if (num_adapters == 1) {
+      pp_activates[i]->SetBlob(MFT_ENUM_ADAPTER_LUID,
+                               reinterpret_cast<BYTE*>(&single_adapter_luid),
+                               sizeof(LUID));
+    }
+    encoders.push_back(pp_activates[i]);
+  }
+
+  if (pp_activates) {
+    CoTaskMemFree(pp_activates);
+  }
+
+  return encoders;
+}
+
+std::vector<Microsoft::WRL::ComPtr<IMFActivate>> EnumerateHardwareEncoders(
+    VideoCodec codec) {
+  std::vector<Microsoft::WRL::ComPtr<IMFActivate>> encoders;
+
+  if (!InitializeMediaFoundation()) {
+    return encoders;
+  }
+#if defined(ARCH_CPU_ARM64)
+  // TODO (crbug.com/1509117): Temporarily disable video encoding on arm64
+  // until we figure out what OS reports all codecs as supported.
+  if (!base::FeatureList::IsEnabled(kMediaFoundationAcceleratedEncodeOnArm64)) {
+    return encoders;
+  }
+#endif
+
+  MFTEnum2Type mftenum2_func = GetMFTEnum2Function();
+  if (!mftenum2_func) {
+    return EnumerateHardwareEncodersLegacy(codec);
+  }
+
+  uint32_t flags = MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_SORTANDFILTER;
+  MFT_REGISTER_TYPE_INFO input_info;
+  input_info.guidMajorType = MFMediaType_Video;
+  input_info.guidSubtype = MFVideoFormat_NV12;
+  MFT_REGISTER_TYPE_INFO output_info;
+  output_info.guidMajorType = MFMediaType_Video;
+  output_info.guidSubtype = VideoCodecToMFSubtype(codec);
+
+  Microsoft::WRL::ComPtr<IDXGIFactory1> factory;
+  auto hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
+  if (FAILED(hr)) {
+    DVLOG(2) << "Failed to create DXGI Factory";
+    return encoders;
+  }
+
+  Microsoft::WRL::ComPtr<IDXGIAdapter> temp_adapter;
+  for (UINT adapter_idx = 0;
+       SUCCEEDED(factory->EnumAdapters(adapter_idx, &temp_adapter));
+       adapter_idx++) {
+    DXGI_ADAPTER_DESC desc;
+    hr = temp_adapter->GetDesc(&desc);
+    if (FAILED(hr)) {
+      DVLOG(2) << "Failed to get description for adapter " << adapter_idx;
+      continue;
+    }
+
+    Microsoft::WRL::ComPtr<IMFAttributes> attributes;
+    hr = MFCreateAttributes(&attributes, 1);
+    if (FAILED(hr = attributes->SetBlob(
+                   MFT_ENUM_ADAPTER_LUID,
+                   reinterpret_cast<BYTE*>(&desc.AdapterLuid), sizeof(LUID)))) {
+      continue;
+    }
+
+    IMFActivate** pp_activates = nullptr;
+    uint32_t count = 0;
+    // MFTEnum2() function call.
+    hr = mftenum2_func(MFT_CATEGORY_VIDEO_ENCODER, flags, &input_info,
+                       &output_info, attributes.Get(), &pp_activates, &count);
+
+    if (FAILED(hr)) {
+      // Log to VLOG since errors are expected as part of
+      // GetSupportedProfiles().
+      DVLOG(2) << "Failed to enumerate hardware encoders for "
+               << GetCodecName(codec) << " at a adapter #" << adapter_idx
+               << " : " << PrintHr(hr);
+      continue;
+    }
+
+    for (UINT32 i = 0; i < count; i++) {
+      if (codec == VideoCodec::kAV1 &&
+          IsIntelHybridAV1Encoder(pp_activates[i])) {
+        continue;
+      }
+      // It's safe to ignore return value here.
+      // if SetBlob fails, the IMFActivate won't have a valid adapter LUID
+      // which will fail the check for preferred adapter LUID, so the
+      // MFDXGIDeviceManager will not be set for MFT, which is a safe option.
+      pp_activates[i]->SetBlob(MFT_ENUM_ADAPTER_LUID,
+                               reinterpret_cast<BYTE*>(&desc.AdapterLuid),
+                               sizeof(LUID));
+      encoders.push_back(pp_activates[i]);
+    }
+
+    if (pp_activates) {
+      CoTaskMemFree(pp_activates);
+    }
+  }
+
+  return encoders;
+}
+
+uint32_t CalculateMaxFramerateFromMacroBlocksPerSecond(
+    const FramerateAndResolution& max_framerate_and_resolution,
+    uint32_t max_macroblocks_per_second) {
+  constexpr uint64_t kMacroBlockWidth = 16u;
+  constexpr uint64_t kMacroBlockHeight = 16u;
+
+  uint64_t max_possible_framerate = std::floor(
+      (max_macroblocks_per_second * kMacroBlockWidth * kMacroBlockHeight) /
+      max_framerate_and_resolution.resolution.Area64());
+
+  return std::clamp(static_cast<uint32_t>(max_possible_framerate), 1u,
+                    max_framerate_and_resolution.frame_rate);
+}
+
+std::vector<FramerateAndResolution> GetMaxFramerateAndResolutionsFromMFT(
+    VideoCodec codec,
+    IMFTransform* encoder,
+    bool allow_set_output_type) {
+  DCHECK(encoder);
+  std::vector<FramerateAndResolution> framerate_and_resolutions;
+  if (allow_set_output_type) {
+    Microsoft::WRL::ComPtr<IMFMediaType> media_type;
+
+    RETURN_ON_HR_FAILURE(MFCreateMediaType(&media_type),
+                         "Create media type failed", framerate_and_resolutions);
+    RETURN_ON_HR_FAILURE(
+        media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
+        "Set major type failed", framerate_and_resolutions);
+    RETURN_ON_HR_FAILURE(
+        media_type->SetGUID(MF_MT_SUBTYPE, VideoCodecToMFSubtype(codec)),
+        "Set guid for sub type failed", framerate_and_resolutions);
+    RETURN_ON_HR_FAILURE(
+        MFSetAttributeSize(
+            media_type.Get(), MF_MT_FRAME_SIZE,
+            kDefaultMaxFramerateAndResolution.resolution.width(),
+            kDefaultMaxFramerateAndResolution.resolution.height()),
+        "Set attribute size failed", framerate_and_resolutions);
+    // Frame rate,30, is dummy value for pass through.
+    RETURN_ON_HR_FAILURE(
+        MFSetAttributeRatio(
+            media_type.Get(), MF_MT_FRAME_RATE,
+            /*unNumerator=*/kDefaultMaxFramerateAndResolution.frame_rate,
+            /*unDenominator=*/1),
+        "Set attribute ratio failed", framerate_and_resolutions);
+    RETURN_ON_HR_FAILURE(media_type->SetUINT32(MF_MT_AVG_BITRATE, 9000000),
+                         "Set avg bitrate failed", framerate_and_resolutions);
+    RETURN_ON_HR_FAILURE(media_type->SetUINT32(MF_MT_INTERLACE_MODE,
+                                               MFVideoInterlace_Progressive),
+                         "Set interlace mode failed",
+                         framerate_and_resolutions);
+
+    if (codec != VideoCodec::kVP9) {
+      UINT32 max_level;
+      switch (codec) {
+        case VideoCodec::kH264:
+          max_level = eAVEncH264VLevel5_2;
+          break;
+        case VideoCodec::kAV1:
+          max_level = eAVEncAV1VLevel6_3;
+          break;
+        case VideoCodec::kHEVC:
+          max_level = eAVEncH265VLevel6_2;
+          break;
+        default:
+          NOTREACHED();
+      }
+      RETURN_ON_HR_FAILURE(media_type->SetUINT32(MF_MT_VIDEO_LEVEL, max_level),
+                           "Set video level failed", framerate_and_resolutions);
+    }
+
+    RETURN_ON_HR_FAILURE(
+        encoder->SetOutputType(/*stream_id=*/0, media_type.Get(), 0),
+        "Set output type failed", framerate_and_resolutions);
+  }
+
+  Microsoft::WRL::ComPtr<IMFAttributes> attributes;
+  RETURN_ON_HR_FAILURE(encoder->GetAttributes(&attributes),
+                       "Get attributes failed", framerate_and_resolutions);
+  uint32_t max_macroblocks_per_second =
+      MFGetAttributeUINT32(attributes.Get(), MF_VIDEO_MAX_MB_PER_SEC, 0);
+  max_macroblocks_per_second &=
+      0x0fffffff;  // Only lower 28 bits are supported.
+
+  std::vector<FramerateAndResolution> max_framerate_and_resolutions;
+  if (codec == VideoCodec::kH264) {
+    max_framerate_and_resolutions.push_back(kLegacy2KMaxFramerateAndResolution);
+    max_framerate_and_resolutions.push_back(kLegacy4KMaxFramerateAndResolution);
+  } else {
+    max_framerate_and_resolutions.push_back(kModern2KMaxFramerateAndResolution);
+    max_framerate_and_resolutions.push_back(kModern4KMaxFramerateAndResolution);
+    max_framerate_and_resolutions.push_back(kModern8KMaxFramerateAndResolution);
+  }
+
+  for (auto& max_framerate_and_resolution : max_framerate_and_resolutions) {
+    FramerateAndResolution framerate_and_resolution = {
+        CalculateMaxFramerateFromMacroBlocksPerSecond(
+            max_framerate_and_resolution, max_macroblocks_per_second),
+        max_framerate_and_resolution.resolution};
+
+    // Only if the calculated framerate >= the default framerate, we then
+    // consider this resolution & framerate combination is supported.
+    if (framerate_and_resolution.frame_rate >=
+        (kDefaultFrameRateNumerator / kDefaultFrameRateDenominator)) {
+      framerate_and_resolutions.push_back(framerate_and_resolution);
+    }
+  }
+
+  // If the received value of `max_macroblocks_per_second` equals to zero,
+  // assign a default value here.
+  if (framerate_and_resolutions.empty()) {
+    framerate_and_resolutions.push_back(kDefaultMaxFramerateAndResolution);
+  }
+
+  return framerate_and_resolutions;
+}
+
+// Ideally, we should query the API to get the minimum resolution of each codec
+// under each vendor. However, since there is no such API available, based on
+// the actual results, although the minimum resolutions of different codecs for
+// each vendor vary, but the results always remain consistent among different
+// GPU models. Therefore, we can just hardcode these values within the function.
+gfx::Size GetMinResolution(VideoCodec codec, DriverVendor vendor) {
+  switch (codec) {
+    case VideoCodec::kH264:
+      switch (vendor) {
+        case DriverVendor::kAMD:
+          // Below result based on: AMD Radeon(TM) Graphics (Ryzen 7 Pro 4750U),
+          // AMD Radeon(TM) Graphics (Ryzen 9 9950X), AMD Radeon(TM) RX 6600.
+          return gfx::Size(128, 128);
+        case DriverVendor::kIntel:
+          // Below result based on: Intel UHD Graphics 750, Intel Arc(TM) A380,
+          // Intel Arc(TM) Graphic (Ultra5 125H), Intel(R) Iris(R) Xe MAX
+          // Graphics.
+          return gfx::Size(18, 18);
+        case DriverVendor::kNvidia:
+          // Below result based on: NVIDIA RTX 3050, NVIDIA RTX 3070, NVIDIA RTX
+          // 4080.
+          return gfx::Size(146, 50);
+        case DriverVendor::kQualcomm:
+          // Below result based on: Qualcomm(R) Adreno(TM) 690, Qualcomm(R)
+          // Adreno(TM) X1-85.
+          return gfx::Size(96, 96);
+        case DriverVendor::kOther:
+          return kDefaultMinResolution;
+      }
+    case VideoCodec::kHEVC:
+      switch (vendor) {
+        case DriverVendor::kAMD:
+          // Below result based on: AMD Radeon(TM) Graphics (Ryzen 7 Pro 4750U),
+          // AMD Radeon(TM) Graphics (Ryzen 9 9950X), AMD Radeon(TM) RX 6600.
+          return gfx::Size(130, 128);
+        case DriverVendor::kIntel:
+          // Below result based on: Intel UHD Graphics 750, Intel Arc(TM) A380,
+          // Intel Arc(TM) Graphic (Ultra5 125H), Intel(R) Iris(R) Xe MAX
+          // Graphics.
+          return gfx::Size(66, 114);
+        case DriverVendor::kNvidia:
+          // Below result based on: NVIDIA RTX 3050, NVIDIA RTX 3070, NVIDIA RTX
+          // 4080.
+          return gfx::Size(130, 34);
+        case DriverVendor::kQualcomm:
+          // Below result based on: Qualcomm(R) Adreno(TM) 690, Qualcomm(R)
+          // Adreno(TM) X1-85.
+          return gfx::Size(96, 96);
+        case DriverVendor::kOther:
+          return kDefaultMinResolution;
+      }
+    case VideoCodec::kVP9:
+      switch (vendor) {
+        case DriverVendor::kAMD:
+          // Below result based on: AMD Radeon(TM) Graphics (Ryzen 9 9950X).
+          return gfx::Size(66, 66);
+        case DriverVendor::kIntel:
+          // Below result based on: Intel UHD Graphics 750, Intel Arc(TM) A380,
+          // Intel Arc(TM) Graphic (Ultra5 125H), Intel(R) Iris(R) Xe MAX
+          // Graphics.
+          //
+          // NOTE: Intel UHD Graphics 750, Intel Arc(TM) A380, Intel(R) Iris(R)
+          // Xe MAX Graphics actually only requires >= 66x66, but Intel Arc(TM)
+          // Graphic (Ultra5 125H) requires >= 66x120.
+          return gfx::Size(66, 120);
+        case DriverVendor::kNvidia:
+          // Below result based on: NVIDIA RTX 4080.
+          return gfx::Size(66, 66);
+        // As of the testing date, no Qualcomm hardware supports VP9 encoding.
+        case DriverVendor::kQualcomm:
+        case DriverVendor::kOther:
+          return kDefaultMinResolution;
+      }
+    case VideoCodec::kAV1:
+      switch (vendor) {
+        case DriverVendor::kAMD:
+          // Below result based on: AMD Radeon(TM) Graphics (Ryzen 9 9950X).
+          return gfx::Size(114, 82);
+        case DriverVendor::kIntel:
+          // Below result based on: Intel Arc(TM) A380, Intel Arc(TM) Graphic
+          // (Ultra5 125H).
+          return gfx::Size(114, 82);
+        case DriverVendor::kNvidia:
+          // Below result based on: NVIDIA RTX 4080.
+          return gfx::Size(130, 66);
+        case DriverVendor::kQualcomm:
+          // Below result based on: Qualcomm(R) Adreno(TM) X1-85.
+          return gfx::Size(256, 128);
+        case DriverVendor::kOther:
+          return kDefaultMinResolution;
+      }
+    default:
+      NOTREACHED();
+  }
+}
+
+size_t GetMFTGuidHash(IMFActivate* activate) {
+  DCHECK(activate);
+
+  GUID mft_guid = {0};
+  activate->GetGUID(MFT_TRANSFORM_CLSID_Attribute, &mft_guid);
+  return base::FastHash(
+      base::as_byte_span(base::win::WStringFromGUID(mft_guid)));
+}
+
+}  // namespace media
diff --git a/media/gpu/windows/mf_video_encoder_util.h b/media/gpu/windows/mf_video_encoder_util.h
new file mode 100644
index 0000000..9fa752b0
--- /dev/null
+++ b/media/gpu/windows/mf_video_encoder_util.h
@@ -0,0 +1,171 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_GPU_WINDOWS_MF_VIDEO_ENCODER_UTIL_H_
+#define MEDIA_GPU_WINDOWS_MF_VIDEO_ENCODER_UTIL_H_
+
+#include <codecapi.h>
+#include <mfapi.h>
+#include <mfidl.h>
+#include <stdint.h>
+#include <wrl/client.h>
+
+#include <vector>
+
+#include "base/containers/fixed_flat_set.h"
+#include "gpu/config/gpu_driver_bug_workarounds.h"
+#include "media/base/video_codecs.h"
+#include "media/base/video_types.h"
+#include "media/gpu/buildflags.h"
+#include "media/gpu/windows/d3d_com_defs.h"
+#include "media/media_buildflags.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace media {
+
+struct FramerateAndResolution {
+  uint32_t frame_rate;
+  gfx::Size resolution;
+};
+
+enum class DriverVendor { kOther, kNvidia, kIntel, kAMD, kQualcomm };
+
+static constexpr size_t kDefaultFrameRateNumerator = 30;
+static constexpr size_t kDefaultFrameRateDenominator = 1;
+
+// The default supported max framerate and resolution.
+static constexpr FramerateAndResolution kDefaultMaxFramerateAndResolution = {
+    kDefaultFrameRateNumerator / kDefaultFrameRateDenominator,
+    gfx::Size(1920, 1080)};
+
+// The default supported min resolution.
+static constexpr gfx::Size kDefaultMinResolution(32, 32);
+
+// For H.264, some NVIDIA GPUs may report `MF_VIDEO_MAX_MB_PER_SEC` value equals
+// to `6799902`, resulting chromium think 8K & 30fps is supported, and some
+// Intel GPUs only support level 5.2. Since most devices only support up to 4K,
+// so we set level 5.2 as the max allowed level here to limit max resolution and
+// framerate combination can only go up to 2K & 172fps, or 4K & 64fps.
+static constexpr FramerateAndResolution kLegacy2KMaxFramerateAndResolution = {
+    172, gfx::Size(1920, 1080)};
+static constexpr FramerateAndResolution kLegacy4KMaxFramerateAndResolution = {
+    64, gfx::Size(3840, 2160)};
+
+// For H.265/AV1, some NVIDIA GPUs may report `MF_VIDEO_MAX_MB_PER_SEC` value
+// equals to `7255273`, resulting chromium think 2K & 880fps is supported. Since
+// the max level of H.265/AV1 (6.2/6.3) do not allow framerate >= 300fps, so we
+// set level 6.2/6.3 as the max allowed level here and limit max resolution and
+// framerate combination can only go up to 2K/4K & 300fps, 8K & 128fps.
+static constexpr FramerateAndResolution kModern2KMaxFramerateAndResolution = {
+    300, gfx::Size(1920, 1080)};
+static constexpr FramerateAndResolution kModern4KMaxFramerateAndResolution = {
+    300, gfx::Size(3840, 2160)};
+static constexpr FramerateAndResolution kModern8KMaxFramerateAndResolution = {
+    128, gfx::Size(7680, 4320)};
+
+static constexpr CLSID kIntelAV1HybridEncoderCLSID = {
+    0x62c053ce,
+    0x5357,
+    0x4794,
+    {0x8c, 0x5a, 0xfb, 0xef, 0xfe, 0xff, 0xb8, 0x2d}};
+
+static constexpr auto kSupportedPixelFormats =
+    base::MakeFixedFlatSet<VideoPixelFormat>(
+        {PIXEL_FORMAT_I420, PIXEL_FORMAT_NV12});
+static constexpr auto kSupportedPixelFormatsD3DVideoProcessing =
+    base::MakeFixedFlatSet<VideoPixelFormat>(
+        {PIXEL_FORMAT_I420, PIXEL_FORMAT_NV12, PIXEL_FORMAT_YV12,
+         PIXEL_FORMAT_NV21, PIXEL_FORMAT_ARGB, PIXEL_FORMAT_XRGB,
+         PIXEL_FORMAT_ABGR, PIXEL_FORMAT_XBGR});
+
+static constexpr int kH26xMaxQp = 51;
+static constexpr uint64_t kVP9MaxQIndex = 255;
+static constexpr uint64_t kAV1MaxQIndex = 255;
+
+// Quantizer parameter used in libvpx vp9 rate control, whose range is 0-63.
+// These are based on WebRTC's defaults, cite from
+// third_party/webrtc/media/engine/webrtc_video_engine.h.
+static constexpr uint8_t kVP9MinQuantizer = 2;
+static constexpr uint8_t kVP9MaxQuantizer = 56;
+// Default value from
+// //third_party/webrtc/modules/video_coding/codecs/av1/libaom_av1_encoder.cc,
+static constexpr uint8_t kAV1MinQuantizer = 10;
+// //third_party/webrtc/media/engine/webrtc_video_engine.h.
+static constexpr uint8_t kAV1MaxQuantizer = 56;
+
+// The range for the quantization parameter is determined by examining the
+// estimated QP values from the SW bitrate controller in various encoding
+// scenarios.
+static constexpr uint8_t kH264MinQuantizer = 16;
+static constexpr uint8_t kH264MaxQuantizer = 51;
+
+#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
+// For H.265, ideally we may reuse Min/MaxQp for H.264 from
+// media/gpu/vaapi/h264_vaapi_video_encoder_delegate.cc. However
+// test shows most of the drivers require a min QP of 10 to reach
+// target bitrate especially at low resolution.
+static constexpr uint8_t kH265MinQuantizer = 10;
+static constexpr uint8_t kH265MaxQuantizer = 42;
+#endif  // BUILDFLAG(ENABLE_PLATFORM_HEVC)
+
+// Converts AV1/VP9 qindex (0-255) to the quantizer parameter input in MF
+// AVEncVideoEncodeQP.
+uint8_t QindextoAVEncQP(VideoCodec codec, uint8_t q_index);
+
+// Converts AV1/VP9 AVEncVideoEncodeQP values to qindex (0-255) range.
+uint8_t AVEncQPtoQindex(VideoCodec codec, uint8_t avenc_qp);
+
+// Returns true if |qp| is a valid quantizer parameter for |codec|.
+bool IsValidQp(VideoCodec codec, uint64_t qp);
+
+// Returns the maximum quantizer value for |codec|.
+uint8_t GetMaxQuantizer(VideoCodec codec);
+
+// Converts VideoCodecProfile to eAVEncH264VProfile.
+eAVEncH264VProfile GetH264VProfile(VideoCodecProfile profile,
+                                   bool is_constrained_h264);
+
+// Converts VideoCodecProfile to eAVEncVP9VProfile.
+eAVEncVP9VProfile GetVP9VProfile(VideoCodecProfile profile);
+
+// Converts VideoCodecProfile to eAVEncAV1VProfile.
+eAVEncH265VProfile GetHEVCProfile(VideoCodecProfile profile);
+
+// Returns the driver vendor of the given |encoder|.
+DriverVendor GetDriverVendor(IMFActivate* encoder);
+
+// Get the maximum number of temporal layers supported by the given |encoder|
+// from |vendor|, taking into account |workarounds|.
+int GetMaxTemporalLayerVendorLimit(
+    DriverVendor vendor,
+    VideoCodec codec,
+    const gpu::GpuDriverBugWorkarounds& workarounds);
+
+// Enumeration of HMFT without specifying LUID.
+std::vector<Microsoft::WRL::ComPtr<IMFActivate>>
+EnumerateHardwareEncodersLegacy(VideoCodec codec);
+
+// Adapter-based enumeration of HMFT. The adapter with lower index is enumerated
+// first.
+std::vector<Microsoft::WRL::ComPtr<IMFActivate>> EnumerateHardwareEncoders(
+    VideoCodec codec);
+
+// Get the maximum supported framerate and resolution combinations for the given
+// codec and HMFT. If |allow_set_output_type| is true, it will try to set the
+// output type to get the maximum supported framerate and resolution; otherwise,
+// we merely query the maximum supported macroblocks per second for calculation.
+std::vector<FramerateAndResolution> GetMaxFramerateAndResolutionsFromMFT(
+    VideoCodec codec,
+    IMFTransform* encoder,
+    bool allow_set_output_type);
+
+// Get the minimum supported encoding resolution for the given codec and vendor.
+gfx::Size GetMinResolution(VideoCodec codec, DriverVendor vendor);
+
+// Get the hash of the CLSID of the IMFActivate instance.
+size_t GetMFTGuidHash(IMFActivate* activate);
+
+}  // namespace media
+
+#endif  // MEDIA_GPU_WINDOWS_MF_VIDEO_ENCODER_UTIL_H_
diff --git a/media/mojo/mojom/speech_recognition.mojom b/media/mojo/mojom/speech_recognition.mojom
index ba38326..9839113 100644
--- a/media/mojo/mojom/speech_recognition.mojom
+++ b/media/mojo/mojom/speech_recognition.mojom
@@ -230,15 +230,6 @@
   OnFullscreenToggled@1();
 };
 
-// Static metadata about a remote speech surface. Used by the speech service
-// client in Ash.
-struct SpeechRecognitionSurfaceMetadata {
-  // A unique identifier for the "session" (i.e. tab) of the surface. Is used to
-  // hide the caption bubble for all streams in a tab if the bubble is closed
-  // once.
-  mojo_base.mojom.UnguessableToken session_id;
-};
-
 // This interface between the speech recognition client and the browser.
 // The remote lives in the renderer process and the receiver lives in the
 // browser process. Not necessary for browser-side features (e.g. CrOS system
@@ -248,16 +239,8 @@
   BindSpeechRecognitionBrowserObserver@0(
       pending_remote<SpeechRecognitionBrowserObserver> observer);
 
-  // Requests that a remote speech recognition client be instantiated and bound
-  // in the Ash browser process. The instantiated client should use the surface
-  // and surface client bindings to perform tasks (such as refocusing) that
-  // require coordination with the current lacros tab.
   [MinVersion=1]
-  BindRecognizerToRemoteClient@1(
-      pending_receiver<SpeechRecognitionRecognizerClient> client,
-      pending_receiver<SpeechRecognitionSurfaceClient> surface_client,
-      pending_remote<SpeechRecognitionSurface> surface,
-      SpeechRecognitionSurfaceMetadata metadata);
+  REMOVED_1@1();
 
   // Similar to BindSpeechRecognitionBrowserObserver, however binds Browser
   // observers that listen to events specific to BabelOrca rather than
diff --git a/mojo/public/cpp/base/shared_memory_version.cc b/mojo/public/cpp/base/shared_memory_version.cc
index 568cf34c..8823d3d 100644
--- a/mojo/public/cpp/base/shared_memory_version.cc
+++ b/mojo/public/cpp/base/shared_memory_version.cc
@@ -45,7 +45,7 @@
 
   // Relaxed memory order because no other memory operation depends on the
   // version.
-  return mapped_region_->WritableRef().load(std::memory_order_relaxed);
+  return mapped_region_->ReadOnlyRef().load(std::memory_order_relaxed);
 }
 
 void SharedMemoryVersionController::Increment() {
diff --git a/mojo/public/cpp/base/shared_memory_version.h b/mojo/public/cpp/base/shared_memory_version.h
index 64783bc..fe3cb3ef 100644
--- a/mojo/public/cpp/base/shared_memory_version.h
+++ b/mojo/public/cpp/base/shared_memory_version.h
@@ -120,7 +120,7 @@
   void SetVersion(VersionType version);
 
  private:
-  const std::optional<base::AtomicSharedMemory<VersionType>> mapped_region_;
+  std::optional<base::AtomicSharedMemory<VersionType>> mapped_region_;
 };
 
 // Used to keep track of a remote version number and compare it to a
diff --git a/net/dns/host_resolver_manager_service_endpoint_request_impl.cc b/net/dns/host_resolver_manager_service_endpoint_request_impl.cc
index 486ec08..32ad45f 100644
--- a/net/dns/host_resolver_manager_service_endpoint_request_impl.cc
+++ b/net/dns/host_resolver_manager_service_endpoint_request_impl.cc
@@ -203,7 +203,6 @@
   }
 
   CHECK(job_);
-  CHECK(job_.value()->dns_task_results_manager());
   CHECK(delegate_);
   delegate_->OnServiceEndpointsUpdated();
   // Do not add code below. `this` may be deleted at this point.
diff --git a/services/media_session/audio_focus_manager.cc b/services/media_session/audio_focus_manager.cc
index c277cfd..3fd8540 100644
--- a/services/media_session/audio_focus_manager.cc
+++ b/services/media_session/audio_focus_manager.cc
@@ -282,6 +282,26 @@
   }
 }
 
+void AudioFocusManager::StartDuckingAllAudio(
+    const std::optional<base::UnguessableToken>& exempted_request_id) {
+  ducking_all_audio_ = true;
+  ducking_exempted_request_id_ = exempted_request_id;
+  EnforceAudioFocus();
+}
+
+void AudioFocusManager::StopDuckingAllAudio() {
+  ducking_all_audio_ = false;
+  EnforceAudioFocus();
+}
+
+void AudioFocusManager::FlushForTesting(FlushForTestingCallback callback) {
+  for (auto& row : audio_focus_stack_) {
+    row->FlushForTesting();  // IN-TEST
+  }
+  observers_.FlushForTesting();  // IN-TEST
+  std::move(callback).Run();
+}
+
 void AudioFocusManager::CreateActiveMediaController(
     mojo::PendingReceiver<mojom::MediaController> receiver) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -474,6 +494,11 @@
 bool AudioFocusManager::ShouldSessionBeDucked(
     const AudioFocusRequest* session,
     const EnforcementState& state) const {
+  if (ducking_all_audio_ && (!ducking_exempted_request_id_.has_value() ||
+                             *ducking_exempted_request_id_ != session->id())) {
+    return true;
+  }
+
   switch (enforcement_mode_) {
     case mojom::EnforcementMode::kSingleSession:
     case mojom::EnforcementMode::kSingleGroup:
diff --git a/services/media_session/audio_focus_manager.h b/services/media_session/audio_focus_manager.h
index 1dc365f..67449d06 100644
--- a/services/media_session/audio_focus_manager.h
+++ b/services/media_session/audio_focus_manager.h
@@ -79,6 +79,10 @@
   void GetSourceFocusRequests(const base::UnguessableToken& source_id,
                               GetFocusRequestsCallback callback) override;
   void RequestIdReleased(const base::UnguessableToken& request_id) override;
+  void StartDuckingAllAudio(const std::optional<base::UnguessableToken>&
+                                exempted_request_id) override;
+  void StopDuckingAllAudio() override;
+  void FlushForTesting(FlushForTestingCallback callback) override;
 
   // mojom::AudioFocusManagerDebug.
   void GetDebugInfoForRequest(const RequestId& request_id,
@@ -187,6 +191,10 @@
 
   mojom::EnforcementMode enforcement_mode_;
 
+  bool ducking_all_audio_ = false;
+
+  std::optional<base::UnguessableToken> ducking_exempted_request_id_;
+
   // Adding observers should happen on the same thread that the service is
   // running on.
   THREAD_CHECKER(thread_checker_);
diff --git a/services/media_session/audio_focus_manager_unittest.cc b/services/media_session/audio_focus_manager_unittest.cc
index 988ec81..78910c2 100644
--- a/services/media_session/audio_focus_manager_unittest.cc
+++ b/services/media_session/audio_focus_manager_unittest.cc
@@ -132,12 +132,6 @@
       test::MockMediaSession* session) {
     mojom::MediaSessionInfo::SessionState state = session->GetState();
 
-    if (!IsEnforcementEnabled()) {
-      // If audio focus enforcement is disabled then we should never see ducking
-      // in the tests.
-      EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking, state);
-    }
-
     return state;
   }
 
@@ -234,6 +228,17 @@
         ->identity();
   }
 
+  void StartDuckingAllAudio(
+      const std::optional<base::UnguessableToken>& exempted_request_id) {
+    GetService()->StartDuckingAllAudio(exempted_request_id);
+    FlushForTesting();
+  }
+
+  void StopDuckingAllAudio() {
+    GetService()->StopDuckingAllAudio();
+    FlushForTesting();
+  }
+
   void FlushForTesting() { audio_focus_remote_.FlushForTesting(); }
 
  private:
@@ -1742,4 +1747,80 @@
   EXPECT_TRUE(identity_3_requests.empty());
 }
 
+TEST_P(AudioFocusManagerTest, StartDuckingAllAudio_NoExemption) {
+  test::MockMediaSession media_session_1;
+  test::MockMediaSession media_session_2;
+
+  base::UnguessableToken group_id = base::UnguessableToken::Create();
+
+  // Request audio focus for two media sessions.
+  ASSERT_TRUE(RequestGroupedAudioFocus(base::UnguessableToken::Create(),
+                                       &media_session_1,
+                                       mojom::AudioFocusType::kGain, group_id));
+  ASSERT_TRUE(RequestGroupedAudioFocus(base::UnguessableToken::Create(),
+                                       &media_session_2,
+                                       mojom::AudioFocusType::kGain, group_id));
+  EXPECT_EQ(IsGroupingEnabled()
+                ? mojom::MediaSessionInfo::SessionState::kActive
+                : mojom::MediaSessionInfo::SessionState::kSuspended,
+            GetState(&media_session_1));
+  EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive,
+            GetState(&media_session_2));
+
+  // A call to `StartDuckingAllAudio()` with no exempted request ID should duck
+  // all sessions.
+  StartDuckingAllAudio(std::nullopt);
+  EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kDucking,
+            GetState(&media_session_1));
+  EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kDucking,
+            GetState(&media_session_2));
+
+  // Once ducking all audio is stopped, the sessions should no longer be ducked.
+  StopDuckingAllAudio();
+  EXPECT_EQ(IsGroupingEnabled()
+                ? mojom::MediaSessionInfo::SessionState::kActive
+                : mojom::MediaSessionInfo::SessionState::kSuspended,
+            GetState(&media_session_1));
+  EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive,
+            GetState(&media_session_2));
+}
+
+TEST_P(AudioFocusManagerTest, StartDuckingAllAudio_WithExemption) {
+  test::MockMediaSession media_session_1;
+  test::MockMediaSession media_session_2;
+
+  base::UnguessableToken group_id = base::UnguessableToken::Create();
+  base::UnguessableToken id_2 = base::UnguessableToken::Create();
+
+  // Request audio focus for two media sessions.
+  ASSERT_TRUE(RequestGroupedAudioFocus(base::UnguessableToken::Create(),
+                                       &media_session_1,
+                                       mojom::AudioFocusType::kGain, group_id));
+  ASSERT_TRUE(RequestGroupedAudioFocus(id_2, &media_session_2,
+                                       mojom::AudioFocusType::kGain, group_id));
+  EXPECT_EQ(IsGroupingEnabled()
+                ? mojom::MediaSessionInfo::SessionState::kActive
+                : mojom::MediaSessionInfo::SessionState::kSuspended,
+            GetState(&media_session_1));
+  EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive,
+            GetState(&media_session_2));
+
+  // A call to `StartDuckingAllAudio()` with an exempted request ID should duck
+  // all sessions except the exempted one.
+  StartDuckingAllAudio(id_2);
+  EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kDucking,
+            GetState(&media_session_1));
+  EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive,
+            GetState(&media_session_2));
+
+  // Once ducking all audio is stopped, the sessions should no longer be ducked.
+  StopDuckingAllAudio();
+  EXPECT_EQ(IsGroupingEnabled()
+                ? mojom::MediaSessionInfo::SessionState::kActive
+                : mojom::MediaSessionInfo::SessionState::kSuspended,
+            GetState(&media_session_1));
+  EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive,
+            GetState(&media_session_2));
+}
+
 }  // namespace media_session
diff --git a/services/media_session/audio_focus_request.cc b/services/media_session/audio_focus_request.cc
index 2d0f7b2..b26224d15 100644
--- a/services/media_session/audio_focus_request.cc
+++ b/services/media_session/audio_focus_request.cc
@@ -175,6 +175,10 @@
                      base::Unretained(this), std::move(callback)));
 }
 
+void AudioFocusRequest::FlushForTesting() {
+  session_.FlushForTesting();  // IN-TEST
+}
+
 void AudioFocusRequest::SetSessionInfo(
     mojom::MediaSessionInfoPtr session_info) {
   bool is_controllable_changed =
diff --git a/services/media_session/audio_focus_request.h b/services/media_session/audio_focus_request.h
index 756fdf24..6bf9b3d 100644
--- a/services/media_session/audio_focus_request.h
+++ b/services/media_session/audio_focus_request.h
@@ -85,6 +85,8 @@
   const base::UnguessableToken& group_id() const { return group_id_; }
   const base::UnguessableToken& identity() const { return identity_; }
 
+  void FlushForTesting();
+
  private:
   void SetSessionInfo(mojom::MediaSessionInfoPtr session_info);
   void OnConnectionError();
diff --git a/services/media_session/public/cpp/test/mock_audio_focus_manager.h b/services/media_session/public/cpp/test/mock_audio_focus_manager.h
index cf4d212..07f1e4a 100644
--- a/services/media_session/public/cpp/test/mock_audio_focus_manager.h
+++ b/services/media_session/public/cpp/test/mock_audio_focus_manager.h
@@ -62,6 +62,12 @@
   MOCK_METHOD(void,
               RequestIdReleased,
               (const base::UnguessableToken& request_id));
+  MOCK_METHOD(
+      void,
+      StartDuckingAllAudio,
+      (const std::optional<base::UnguessableToken>& exempted_request_id));
+  MOCK_METHOD(void, StopDuckingAllAudio, ());
+  MOCK_METHOD(void, FlushForTesting, (FlushForTestingCallback));
 
  private:
   mojo::Receiver<mojom::AudioFocusManager> receiver_{this};
diff --git a/services/media_session/public/mojom/audio_focus.mojom b/services/media_session/public/mojom/audio_focus.mojom
index dfa07d80..599bcd5 100644
--- a/services/media_session/public/mojom/audio_focus.mojom
+++ b/services/media_session/public/mojom/audio_focus.mojom
@@ -7,7 +7,7 @@
 import "mojo/public/mojom/base/unguessable_token.mojom";
 import "services/media_session/public/mojom/media_session.mojom";
 
-// Next MinVersion: 10
+// Next MinVersion: 11
 
 // These are the different modes the AudioFocusManager can enforce audio focus.
 [Stable, Extensible]
@@ -167,6 +167,21 @@
   // |RequestGroupedAudioFocus()|.
   [MinVersion=8] RequestIdReleased@9(
       mojo_base.mojom.UnguessableToken request_id);
+
+  // Begins ducking all audio focus sessions, except the one associated with the
+  // optionally provided request ID. This ignores the audio focus enforcement
+  // mode to enforce ducking regardless. If there is already an audio ducking
+  // request, this request will supersede the previous one.
+  [MinVersion=10] StartDuckingAllAudio@10(
+      mojo_base.mojom.UnguessableToken? exempted_request_id);
+
+  // Stops ducking that was started via `StartDuckingAllAudio()`. Does nothing
+  // if audio is not currently being ducked.
+  [MinVersion=10] StopDuckingAllAudio@11();
+
+  // Flushes messages to observers and the audio focus stack. Calls the given
+  // callback once flushing has occurred. For testing only.
+  [MinVersion=10] FlushForTesting@12() => ();
 };
 
 // Provides debug information about audio focus requests.
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index a2fbf1e..f402dc0 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -2648,8 +2648,6 @@
     builder.SetCookieStore(std::move(cookie_store));
   }
 
-  if (base::FeatureList::IsEnabled(features::kPrivateStateTokens) ||
-      base::FeatureList::IsEnabled(features::kFledgePst)) {
     trust_token_store_ = std::make_unique<PendingTrustTokenStore>();
 
     base::FilePath trust_token_path;
@@ -2670,7 +2668,6 @@
           std::make_unique<ExpiryInspectingRecordExpiryDelegate>(
               network_service()->trust_token_key_commitments())));
     }
-  }
 
   std::unique_ptr<net::StaticHttpUserAgentSettings> user_agent_settings =
       std::make_unique<net::StaticHttpUserAgentSettings>(
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 5bd14a1..54618b9 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -8132,9 +8132,6 @@
 }
 
 TEST_F(NetworkContextTest, EnableTrustTokens) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(features::kPrivateStateTokens);
-
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
 
@@ -8235,10 +8232,6 @@
 }
 
 TEST_F(NetworkContextTest, EnableTrustTokensForFledge) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures({features::kFledgePst},
-                                       {features::kPrivateStateTokens});
-
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
 
@@ -8256,9 +8249,6 @@
 }
 
 TEST_F(NetworkContextTestWithMockTime, EnableTrustTokensWithStoreOnDisk) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(features::kPrivateStateTokens);
-
   base::ScopedTempDir dir;
   ASSERT_TRUE(dir.CreateUniqueTempDir());
   base::FilePath database_name(FILE_PATH_LITERAL("my_token_store"));
@@ -8321,20 +8311,6 @@
   task_environment_.RunUntilIdle();
 }
 
-TEST_F(NetworkContextTest, DisableTrustTokens) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {}, {features::kPrivateStateTokens, features::kFledgePst});
-
-  std::unique_ptr<NetworkContext> network_context =
-      CreateContextWithParams(CreateNetworkContextParamsForTesting());
-
-  // Allow the store time to initialize asynchronously.
-  task_environment_.RunUntilIdle();
-
-  EXPECT_FALSE(network_context->trust_token_store());
-}
-
 class NetworkContextExpectBadMessageTest : public NetworkContextTest {
  public:
   NetworkContextExpectBadMessageTest() {
@@ -8355,36 +8331,7 @@
 };
 
 TEST_F(NetworkContextExpectBadMessageTest,
-       FailsTrustTokenBearingRequestWhenTrustTokensIsDisabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {}, {features::kPrivateStateTokens, features::kFledgePst});
-
-  std::unique_ptr<NetworkContext> network_context =
-      CreateContextWithParams(CreateNetworkContextParamsForTesting());
-
-  // Allow the store time to initialize asynchronously.
-  task_environment_.RunUntilIdle();
-
-  EXPECT_FALSE(network_context->trust_token_store());
-
-  ResourceRequest my_request;
-  my_request.request_initiator =
-      url::Origin::Create(GURL("https://initiator.com"));
-  my_request.trust_token_params =
-      OptionalTrustTokenParams(mojom::TrustTokenParams::New());
-
-  std::unique_ptr<TestURLLoaderClient> client =
-      FetchRequest(my_request, network_context.get());
-
-  AssertBadMessage();
-}
-
-TEST_F(NetworkContextExpectBadMessageTest,
        FailsTrustTokenRedemptionWhenForbidden) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(features::kPrivateStateTokens);
-
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
 
@@ -8412,9 +8359,6 @@
 
 TEST_F(NetworkContextExpectBadMessageTest,
        FailsTrustTokenSigningWhenForbidden) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(features::kPrivateStateTokens);
-
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
 
@@ -8442,9 +8386,6 @@
 
 TEST_F(NetworkContextExpectBadMessageTest,
        FailsTrustTokenIssuanceWhenForbidden) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(features::kPrivateStateTokens);
-
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
 
@@ -8472,9 +8413,6 @@
 
 TEST_F(NetworkContextTest,
        AttemptsTrustTokenBearingRequestWhenTrustTokensIsEnabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(features::kPrivateStateTokens);
-
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
 
@@ -8498,9 +8436,6 @@
 
 TEST_F(NetworkContextTest,
        RejectsTrustTokenBearingRequestWhenTrustTokensAreBlocked) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(features::kPrivateStateTokens);
-
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
 
@@ -8528,9 +8463,6 @@
 
 TEST_F(NetworkContextTest,
        RejectsTrustTokenBearingRequestWhenStorageIsBlocked) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(features::kPrivateStateTokens);
-
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
 
@@ -8557,27 +8489,7 @@
             mojom::TrustTokenOperationStatus::kUnauthorized);
 }
 
-TEST_F(NetworkContextTest,
-       NoAvailableRedemptionRecordsWhenTrustTokensAreDisabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      /*enabled_features=*/{}, /*disabled_features=*/{
-          features::kPrivateStateTokens, features::kFledgePst});
-
-  std::unique_ptr<NetworkContext> network_context =
-      CreateContextWithParams(CreateNetworkContextParamsForTesting());
-
-  base::test::TestFuture<base::flat_map<
-      url::Origin, std::vector<network::mojom::ToplevelRedemptionRecordPtr>>>
-      future;
-  network_context->GetPrivateStateTokenRedemptionRecords(future.GetCallback());
-  EXPECT_THAT(future.Get(), testing::IsEmpty());
-}
-
 TEST_F(NetworkContextTestWithMockTime, GetPrivateStateTokenRedemptionRecords) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(features::kPrivateStateTokens);
-
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
   base::RunLoop run_loop;
@@ -8676,33 +8588,7 @@
             last_redemption_b);
 }
 
-TEST_F(NetworkContextTest, NoAvailableTrustTokensWhenTrustTokensAreDisabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {}, {features::kPrivateStateTokens, features::kFledgePst});
-
-  std::unique_ptr<NetworkContext> network_context =
-      CreateContextWithParams(CreateNetworkContextParamsForTesting());
-
-  // Allow the store time to initialize asynchronously.
-  base::RunLoop run_loop;
-  std::optional<std::vector<mojom::StoredTrustTokensForIssuerPtr>> trust_tokens;
-  network_context->GetStoredTrustTokenCounts(base::BindLambdaForTesting(
-      [&trust_tokens,
-       &run_loop](std::vector<mojom::StoredTrustTokensForIssuerPtr> tokens) {
-        trust_tokens = std::move(tokens);
-        run_loop.Quit();
-      }));
-  run_loop.Run();
-
-  ASSERT_TRUE(trust_tokens.has_value());
-  EXPECT_TRUE(trust_tokens->empty());
-}
-
 TEST_F(NetworkContextTest, GetStoredTrustTokens) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(features::kPrivateStateTokens);
-
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
 
@@ -8748,9 +8634,6 @@
 }
 
 TEST_F(NetworkContextTest, GetStoredTrustTokensReentrant) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(features::kPrivateStateTokens);
-
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
 
@@ -8791,36 +8674,7 @@
 }
 
 TEST_F(NetworkContextTest,
-       DeleteStoredTrustTokensReportsErrorWhenFeatureIsDisabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {}, {features::kPrivateStateTokens, features::kFledgePst});
-
-  std::unique_ptr<NetworkContext> network_context =
-      CreateContextWithParams(CreateNetworkContextParamsForTesting());
-
-  // Allow the store time to initialize asynchronously.
-  base::RunLoop run_loop;
-  std::optional<mojom::DeleteStoredTrustTokensStatus> actual_status;
-  network_context->DeleteStoredTrustTokens(
-      url::Origin::Create(GURL("https://example.com")),
-      base::BindLambdaForTesting(
-          [&](mojom::DeleteStoredTrustTokensStatus status) {
-            actual_status = status;
-            run_loop.Quit();
-          }));
-  run_loop.Run();
-
-  EXPECT_THAT(
-      actual_status,
-      Optional(mojom::DeleteStoredTrustTokensStatus::kFailureFeatureDisabled));
-}
-
-TEST_F(NetworkContextTest,
        DeleteStoredTrustTokensReportsErrorWithInvalidOrigin) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(features::kPrivateStateTokens);
-
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
 
@@ -8842,9 +8696,6 @@
 }
 
 TEST_F(NetworkContextTest, DeleteStoredTrustTokens) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(features::kPrivateStateTokens);
-
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
 
@@ -8897,9 +8748,6 @@
 }
 
 TEST_F(NetworkContextTest, DeleteStoredTrustTokensReentrant) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(features::kPrivateStateTokens);
-
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
 
@@ -8964,9 +8812,6 @@
   test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
   ASSERT_TRUE(test_server.Start());
 
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(features::kPrivateStateTokens);
-
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
 
@@ -9043,9 +8888,6 @@
   test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
   ASSERT_TRUE(test_server.Start());
 
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(features::kPrivateStateTokens);
-
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
 
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc
index e4a9992..c6bbf5f 100644
--- a/services/network/public/cpp/features.cc
+++ b/services/network/public/cpp/features.cc
@@ -178,48 +178,6 @@
              "AttributionReportingCrossAppWeb",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-// Enables preprocessing requests with the Private State Tokens API Fetch flags
-// set, and handling their responses, according to the protocol.
-// (See https://github.com/WICG/trust-token-api.)
-BASE_FEATURE(kPrivateStateTokens,
-             "PrivateStateTokens",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
-// Secondary flag used by the FLEDGE ads experiment in the interim before
-// PSTs are fully rolled out to stable.
-BASE_FEATURE(kFledgePst, "TrustTokens", base::FEATURE_ENABLED_BY_DEFAULT);
-
-// Determines which Trust Tokens operations require the TrustTokens origin trial
-// active in order to be used. This is runtime-configurable so that the Trust
-// Tokens operations of issuance, redemption, and signing are compatible with
-// both standard origin trials and third-party origin trials:
-//
-// - For standard origin trials, set kOnlyIssuanceRequiresOriginTrial. In Blink,
-// all of the interface will be enabled (so long as the base::Feature is!), and
-// issuance operations will check at runtime if the origin trial is enabled,
-// returning an error if it is not.
-// - For third-party origin trials, set kAllOperationsRequireOriginTrial. In
-// Blink, the interface will be enabled exactly when the origin trial is present
-// in the executing context (so long as the base::Feature is present).
-//
-// For testing, set kOriginTrialNotRequired. With this option, although all
-// operations will still only be available if the base::Feature is enabled, none
-// will additionally require that the origin trial be active.
-const base::FeatureParam<TrustTokenOriginTrialSpec>::Option
-    kTrustTokenOriginTrialParamOptions[] = {
-        {TrustTokenOriginTrialSpec::kOriginTrialNotRequired,
-         "origin-trial-not-required"},
-        {TrustTokenOriginTrialSpec::kAllOperationsRequireOriginTrial,
-         "all-operations-require-origin-trial"},
-        {TrustTokenOriginTrialSpec::kOnlyIssuanceRequiresOriginTrial,
-         "only-issuance-requires-origin-trial"}};
-BASE_FEATURE_ENUM_PARAM(TrustTokenOriginTrialSpec,
-                        kTrustTokenOperationsRequiringOriginTrial,
-                        &kFledgePst,
-                        "TrustTokenOperationsRequiringOriginTrial",
-                        TrustTokenOriginTrialSpec::kOriginTrialNotRequired,
-                        &kTrustTokenOriginTrialParamOptions);
-
 // Enable support for ACCEPT_CH H2/3 frame as part of Client Hint Reliability.
 // See:
 // https://tools.ietf.org/html/draft-davidben-http-client-hint-reliability-02#section-4.3
diff --git a/services/network/public/cpp/features.h b/services/network/public/cpp/features.h
index aca47aa..a2d1dad 100644
--- a/services/network/public/cpp/features.h
+++ b/services/network/public/cpp/features.h
@@ -60,26 +60,6 @@
 COMPONENT_EXPORT(NETWORK_CPP)
 BASE_DECLARE_FEATURE(kAttributionReportingCrossAppWeb);
 
-// Both flags need to be checked for required PST components as they are being
-// used in different experiments.
-//
-// kFledgePst is the original flag used in the OT and respects
-// the TrustTrialOriginTrialSpec. It will be deprecated in favor of
-// kPrivateStateTokens when the experiment is over.
-COMPONENT_EXPORT(NETWORK_CPP) BASE_DECLARE_FEATURE(kPrivateStateTokens);
-COMPONENT_EXPORT(NETWORK_CPP) BASE_DECLARE_FEATURE(kFledgePst);
-
-enum class TrustTokenOriginTrialSpec {
-  // See the .cc file for definitions.
-  kAllOperationsRequireOriginTrial,
-  kOnlyIssuanceRequiresOriginTrial,
-  kOriginTrialNotRequired,
-};
-COMPONENT_EXPORT(NETWORK_CPP)
-BASE_DECLARE_FEATURE_PARAM(TrustTokenOriginTrialSpec,
-                           kTrustTokenOperationsRequiringOriginTrial);
-COMPONENT_EXPORT(NETWORK_CPP)
-
 COMPONENT_EXPORT(NETWORK_CPP) BASE_DECLARE_FEATURE(kAcceptCHFrame);
 
 COMPONENT_EXPORT(NETWORK_CPP)
diff --git a/services/tracing/perfetto/consumer_host_unittest.cc b/services/tracing/perfetto/consumer_host_unittest.cc
index ed637c3..8ec64b9c 100644
--- a/services/tracing/perfetto/consumer_host_unittest.cc
+++ b/services/tracing/perfetto/consumer_host_unittest.cc
@@ -557,28 +557,22 @@
   no_more_data.Run();
 }
 
-#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID)
-// TODO(crbug.com/383878432): Re-enable this test
-#define MAYBE_FlushProducers DISABLED_FlushProducers
-#else
-#define MAYBE_FlushProducers FlushProducers
-#endif
-TEST_F(TracingConsumerTest, MAYBE_FlushProducers) {
+TEST_F(TracingConsumerTest, FlushProducers) {
   EnableTracingWithDataSourceName(kDataSourceName);
 
   threaded_perfetto_service()->CreateProducer();
   auto writer = threaded_perfetto_service()->CreateTraceWriter(kDataSourceName);
-  MockProducer::WritePackets(*writer, 10);
 
   base::RunLoop wait_for_packets;
   ExpectPackets(kPerfettoTestString, wait_for_packets.QuitClosure());
 
-  base::RunLoop wait_for_flush;
+  MockProducer::WritePackets(*writer, 10);
 
+  base::RunLoop wait_for_flush;
   threaded_perfetto_service()->Flush(*writer, wait_for_flush.QuitClosure());
-  ReadBuffers();
 
   wait_for_flush.Run();
+  ReadBuffers();
   wait_for_packets.Run();
 
   EXPECT_EQ(10u, matching_packet_count());
diff --git a/testing/buildbot/internal.optimization_guide.json b/testing/buildbot/internal.optimization_guide.json
index d319de5..0167e217 100644
--- a/testing/buildbot/internal.optimization_guide.json
+++ b/testing/buildbot/internal.optimization_guide.json
@@ -932,38 +932,7 @@
     ]
   },
   "optimization_guide-android-arm64": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--gtest_filter=*OptimizationGuide*:*PageEntities*:*EntityAnnotator*",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "optimization_guide_components_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "optimization_guide_components_unittests",
-        "swarming": {
-          "dimensions": {
-            "cpu": null,
-            "device_os": "R",
-            "device_os_type": "userdebug",
-            "device_type": "flame",
-            "os": "Android",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_unittests",
-        "test_id_prefix": "ninja://components:components_unittests/"
-      }
-    ]
+    "gtest_tests": []
   },
   "optimization_guide-chromeos": {
     "gtest_tests": [
@@ -985,25 +954,6 @@
         },
         "test": "browser_tests",
         "test_id_prefix": "ninja://chrome/test:browser_tests/"
-      },
-      {
-        "args": [
-          "--gtest_filter=*OptimizationGuide*:*PageEntities*:*EntityAnnotator*"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "optimization_guide_components_unittests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Ubuntu-22.04",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_unittests",
-        "test_id_prefix": "ninja://components:components_unittests/"
       }
     ]
   },
@@ -1230,27 +1180,6 @@
       },
       {
         "args": [
-          "--gtest_filter=*OptimizationGuide*:*PageEntities*:*EntityAnnotator*",
-          "--use-xvfb"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "optimization_guide_components_unittests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "gce": "1",
-            "os": "Ubuntu-22.04",
-            "pool": "chrome.tests.intelligence"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_unittests",
-        "test_id_prefix": "ninja://components:components_unittests/"
-      },
-      {
-        "args": [
           "--ui-test-action-timeout=30000",
           "-use-xvfb"
         ],
@@ -1470,25 +1399,6 @@
       },
       {
         "args": [
-          "--gtest_filter=*OptimizationGuide*:*PageEntities*:*EntityAnnotator*"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "optimization_guide_components_unittests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "arm64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_unittests",
-        "test_id_prefix": "ninja://components:components_unittests/"
-      },
-      {
-        "args": [
           "--ui-test-action-timeout=30000"
         ],
         "merge": {
@@ -1695,25 +1605,6 @@
       },
       {
         "args": [
-          "--gtest_filter=*OptimizationGuide*:*PageEntities*:*EntityAnnotator*"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "optimization_guide_components_unittests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_unittests",
-        "test_id_prefix": "ninja://components:components_unittests/"
-      },
-      {
-        "args": [
           "--ui-test-action-timeout=30000"
         ],
         "merge": {
@@ -1924,27 +1815,6 @@
       },
       {
         "args": [
-          "--gtest_filter=*OptimizationGuide*:*PageEntities*:*EntityAnnotator*"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "optimization_guide_components_unittests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "arm64",
-            "os": "Windows-11",
-            "pool": "chrome.tests",
-            "screen_scaling_percent": "100"
-          },
-          "expiration": 7200,
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_unittests",
-        "test_id_prefix": "ninja://components:components_unittests/"
-      },
-      {
-        "args": [
           "--ui-test-action-timeout=30000"
         ],
         "merge": {
@@ -2133,25 +2003,6 @@
       },
       {
         "args": [
-          "--gtest_filter=*OptimizationGuide*:*PageEntities*:*EntityAnnotator*"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "optimization_guide_components_unittests",
-        "swarming": {
-          "dimensions": {
-            "gce": "1",
-            "os": "Windows-10-19045",
-            "pool": "chrome.tests.intelligence"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_unittests",
-        "test_id_prefix": "ninja://components:components_unittests/"
-      },
-      {
-        "args": [
           "--ui-test-action-timeout=30000"
         ],
         "merge": {
@@ -2421,25 +2272,6 @@
       },
       {
         "args": [
-          "--gtest_filter=*OptimizationGuide*:*PageEntities*:*EntityAnnotator*"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "optimization_guide_components_unittests",
-        "swarming": {
-          "dimensions": {
-            "gce": "1",
-            "os": "Windows-10-19045",
-            "pool": "chrome.tests.intelligence"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_unittests",
-        "test_id_prefix": "ninja://components:components_unittests/"
-      },
-      {
-        "args": [
           "--ui-test-action-timeout=30000"
         ],
         "merge": {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index d4c45d6b..74720b0 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2958,7 +2958,7 @@
             ],
             "experiments": [
                 {
-                    "name": "Disabled",
+                    "name": "Holdback",
                     "disable_features": [
                         "BackForwardCacheNonStickyDoubleFix"
                     ]
@@ -13329,6 +13329,7 @@
                     "name": "Enabled_Dogfood",
                     "enable_features": [
                         "LobsterDogfood",
+                        "LobsterQuickInsertZeroState",
                         "LobsterRightClickMenu"
                     ]
                 }
@@ -17353,24 +17354,6 @@
             ]
         }
     ],
-    "Prerender2NewTabPageAndroidTrigger": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled_20240821",
-                    "params": {
-                        "prerender_new_tab_page_on_touch_trigger": "47"
-                    },
-                    "enable_features": [
-                        "NewTabPageAndroidTriggerForPrerender2"
-                    ]
-                }
-            ]
-        }
-    ],
     "Prerender2NewTabPageTriggerV2": [
         {
             "platforms": [
diff --git a/third_party/angle b/third_party/angle
index e72cc71..1c096a8 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit e72cc71b28a13ec0dcd9791bc2467f55482afa35
+Subproject commit 1c096a8589802f2cdc12cd423a1b6f248fc930b0
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index fdcc294..deecb3a2 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -2265,10 +2265,6 @@
              "ReleaseResourceDecodedDataOnMemoryPressure",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-BASE_FEATURE(kRemoveAuthroizationOnCrossOriginRedirect,
-             "RemoveAutorizationOnCrossOriginRedirect",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kRenderBlockingFonts,
              "RenderBlockingFonts",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index bc94dd2..ce91b3f 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -1454,10 +1454,6 @@
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(
     kReleaseResourceStrongReferencesOnMemoryPressure);
 
-// Kill-switch for removing Authorization header upon cross origin redirects.
-BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(
-    kRemoveAuthroizationOnCrossOriginRedirect);
-
 // Makes preloaded fonts render-blocking up to the limits below.
 // See https://crbug.com/1412861
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kRenderBlockingFonts);
diff --git a/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom
index 1f7305c7..38a71c5 100644
--- a/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom
+++ b/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom
@@ -325,6 +325,7 @@
   kWindowControlsOverlay = 267,
   kFetchPriority = 268,
   kHighlight = 269,
+  kDRAFT_ErrorIsError = 270,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc b/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc
index 3a66b8f..d605775 100644
--- a/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc
+++ b/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc
@@ -450,6 +450,9 @@
     case v8::Isolate::kWeakReferences:
       webdx_feature = WebDXFeature::kWeakReferences;
       break;
+    case v8::Isolate::kErrorIsError:
+      webdx_feature = WebDXFeature::kDRAFT_ErrorIsError;
+      break;
     default:
       // This can happen if V8 has added counters that this version of Blink
       // does not know about. It's harmless.
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
index 98da84e..464528e 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
@@ -742,6 +742,10 @@
   meta->CreateDataProperty(context, resolve_key, resolve_value).ToChecked();
 }
 
+bool IsDOMExceptionWrapper(v8::Isolate* isolate, v8::Local<v8::Object> object) {
+  return V8DOMException::HasInstance(isolate, object);
+}
+
 struct PrintV8OOM {
   const char* location;
   const v8::OOMDetails& details;
@@ -783,6 +787,7 @@
   isolate->SetHostImportModuleDynamicallyCallback(HostImportModuleDynamically);
   isolate->SetHostInitializeImportMetaObjectCallback(
       HostGetImportMetaProperties);
+  isolate->SetIsJSApiWrapperNativeErrorCallback(IsDOMExceptionWrapper);
   isolate->SetMetricsRecorder(std::make_shared<V8MetricsRecorder>(isolate));
 
 #if BUILDFLAG(IS_WIN)
diff --git a/third_party/blink/renderer/core/css/build.gni b/third_party/blink/renderer/core/css/build.gni
index 0c9bfa9..528d3d8 100644
--- a/third_party/blink/renderer/core/css/build.gni
+++ b/third_party/blink/renderer/core/css/build.gni
@@ -545,8 +545,8 @@
   "parser/css_at_rule_id.h",
   "parser/css_lazy_parsing_state.cc",
   "parser/css_lazy_parsing_state.h",
-  "parser/css_lazy_property_parser_impl.cc",
-  "parser/css_lazy_property_parser_impl.h",
+  "parser/css_lazy_property_parser.cc",
+  "parser/css_lazy_property_parser.h",
   "parser/css_nesting_type.h",
   "parser/css_parser.cc",
   "parser/css_parser.h",
diff --git a/third_party/blink/renderer/core/css/check_pseudo_has_argument_context.cc b/third_party/blink/renderer/core/css/check_pseudo_has_argument_context.cc
index 44b2b64..d8ed363 100644
--- a/third_party/blink/renderer/core/css/check_pseudo_has_argument_context.cc
+++ b/third_party/blink/renderer/core/css/check_pseudo_has_argument_context.cc
@@ -245,8 +245,11 @@
 
 CheckPseudoHasArgumentContext::CheckPseudoHasArgumentContext(
     const CSSSelector* selector,
+    const ContainerNode* scope,
     bool match_in_shadow_tree)
-    : has_argument_(selector), match_in_shadow_tree_(match_in_shadow_tree) {
+    : has_argument_(selector),
+      scope_(scope),
+      match_in_shadow_tree_(match_in_shadow_tree) {
   depth_limit_ = 0;
   adjacent_distance_limit_ = 0;
   bool contains_child_or_descendant_combinator = false;
diff --git a/third_party/blink/renderer/core/css/check_pseudo_has_argument_context.h b/third_party/blink/renderer/core/css/check_pseudo_has_argument_context.h
index 72556ce23..e094a52 100644
--- a/third_party/blink/renderer/core/css/check_pseudo_has_argument_context.h
+++ b/third_party/blink/renderer/core/css/check_pseudo_has_argument_context.h
@@ -90,6 +90,7 @@
 
  public:
   explicit CheckPseudoHasArgumentContext(const CSSSelector* selector,
+                                         const ContainerNode* scope,
                                          bool match_in_shadow_tree);
 
   inline bool AdjacentDistanceFixed() const {
@@ -130,6 +131,9 @@
 
   const CSSSelector* HasArgument() const { return has_argument_; }
 
+  // See SelectorCheckingContext::scope.
+  const ContainerNode* Scope() const { return scope_; }
+
   const Vector<unsigned>& GetPseudoHasArgumentHashes() const {
     return pseudo_has_argument_hashes_;
   }
@@ -281,6 +285,7 @@
   CheckPseudoHasArgumentTraversalScope traversal_scope_;
   SiblingsAffectedByHasFlags siblings_affected_by_has_flags_;
   const CSSSelector* has_argument_;
+  const ContainerNode* scope_;
   bool match_in_shadow_tree_;
 
   Vector<unsigned> pseudo_has_argument_hashes_;
diff --git a/third_party/blink/renderer/core/css/check_pseudo_has_argument_context_test.cc b/third_party/blink/renderer/core/css/check_pseudo_has_argument_context_test.cc
index d512002..ca77fdb1 100644
--- a/third_party/blink/renderer/core/css/check_pseudo_has_argument_context_test.cc
+++ b/third_party/blink/renderer/core/css/check_pseudo_has_argument_context_test.cc
@@ -37,7 +37,8 @@
     CSSSelectorList* selector_list =
         css_test_helpers::ParseSelectorList(selector_text);
     CheckPseudoHasArgumentContext context(
-        selector_list->First()->SelectorList()->First(), match_in_shadow_tree);
+        selector_list->First()->SelectorList()->First(), /*scope=*/nullptr,
+        match_in_shadow_tree);
 
     EXPECT_EQ(expected_leftmost_relation, context.LeftmostRelation())
         << "Failed : " << selector_text;
@@ -73,7 +74,8 @@
     CSSSelectorList* selector_list =
         css_test_helpers::ParseSelectorList(selector_text);
     CheckPseudoHasArgumentContext argument_context(
-        selector_list->First()->SelectorList()->First(), match_in_shadow_tree);
+        selector_list->First()->SelectorList()->First(), /*scope=*/nullptr,
+        match_in_shadow_tree);
     for (CheckPseudoHasArgumentTraversalIterator iterator(*has_anchor_element,
                                                           argument_context);
          !iterator.AtEnd(); ++iterator, ++i) {
@@ -100,7 +102,8 @@
     EXPECT_EQ(selector_list->First()->GetPseudoType(), CSSSelector::kPseudoHas);
 
     CheckPseudoHasArgumentContext context(
-        selector_list->First()->SelectorList()->First(), match_in_shadow_tree);
+        selector_list->First()->SelectorList()->First(), /*scope=*/nullptr,
+        match_in_shadow_tree);
     return context.TraversalType();
   }
 
@@ -124,7 +127,8 @@
     CSSSelectorList* selector_list =
         css_test_helpers::ParseSelectorList(selector_text);
     CheckPseudoHasArgumentContext argument_context(
-        selector_list->First()->SelectorList()->First(), match_in_shadow_tree);
+        selector_list->First()->SelectorList()->First(), /*scope=*/nullptr,
+        match_in_shadow_tree);
     for (CheckPseudoHasArgumentTraversalIterator iterator(*has_anchor_element,
                                                           argument_context);
          !iterator.AtEnd(); ++iterator, ++i) {
diff --git a/third_party/blink/renderer/core/css/check_pseudo_has_cache_scope.cc b/third_party/blink/renderer/core/css/check_pseudo_has_cache_scope.cc
index aa98248..55ed147 100644
--- a/third_party/blink/renderer/core/css/check_pseudo_has_cache_scope.cc
+++ b/third_party/blink/renderer/core/css/check_pseudo_has_cache_scope.cc
@@ -44,11 +44,14 @@
 // static
 ElementCheckPseudoHasResultMap& CheckPseudoHasCacheScope::GetResultMap(
     const Document* document,
-    const CSSSelector* selector) {
+    const CSSSelector* selector,
+    const ContainerNode* scope) {
+  uintptr_t scope_id = reinterpret_cast<uintptr_t>(scope);
   // To increase the cache hit ratio, we need to have a same cache key
   // for multiple selector instances those are actually has a same selector.
   // TODO(blee@igalia.com) Find a way to get hash key without serialization.
-  String selector_text = selector->SelectorTextExpandingPseudoParent();
+  String selector_text =
+      selector->SelectorTextExpandingPseudoReferences(scope_id);
 
   DCHECK(document);
   DCHECK(document->GetCheckPseudoHasCacheScope());
@@ -93,7 +96,7 @@
     case CheckPseudoHasArgumentTraversalScope::kAllNextSiblings:
       cache_allowed_ = true;
       result_map_ = &CheckPseudoHasCacheScope::GetResultMap(
-          document, argument_context.HasArgument());
+          document, argument_context.HasArgument(), argument_context.Scope());
       fast_reject_filter_map_ =
           &CheckPseudoHasCacheScope::GetFastRejectFilterMap(
               document, argument_context.TraversalType());
diff --git a/third_party/blink/renderer/core/css/check_pseudo_has_cache_scope.h b/third_party/blink/renderer/core/css/check_pseudo_has_cache_scope.h
index acd19cf..194c2eb 100644
--- a/third_party/blink/renderer/core/css/check_pseudo_has_cache_scope.h
+++ b/third_party/blink/renderer/core/css/check_pseudo_has_cache_scope.h
@@ -290,8 +290,8 @@
   };
 
  private:
-  static ElementCheckPseudoHasResultMap& GetResultMap(const Document*,
-                                                      const CSSSelector*);
+  static ElementCheckPseudoHasResultMap&
+  GetResultMap(const Document*, const CSSSelector*, const ContainerNode* scope);
   static ElementCheckPseudoHasFastRejectFilterMap& GetFastRejectFilterMap(
       const Document*,
       CheckPseudoHasArgumentTraversalType);
diff --git a/third_party/blink/renderer/core/css/check_pseudo_has_cache_scope_context_test.cc b/third_party/blink/renderer/core/css/check_pseudo_has_cache_scope_context_test.cc
index 9c90a22..d52d767b 100644
--- a/third_party/blink/renderer/core/css/check_pseudo_has_cache_scope_context_test.cc
+++ b/third_party/blink/renderer/core/css/check_pseudo_has_cache_scope_context_test.cc
@@ -113,6 +113,7 @@
     const CSSSelector* argument_selector = selector->SelectorList()->First();
 
     CheckPseudoHasArgumentContext argument_context(argument_selector,
+                                                   /*scope=*/nullptr,
                                                    match_in_shadow_tree);
     CheckPseudoHasCacheScope::Context cache_scope_context(document,
                                                           argument_context);
diff --git a/third_party/blink/renderer/core/css/check_pseudo_has_fast_reject_filter_test.cc b/third_party/blink/renderer/core/css/check_pseudo_has_fast_reject_filter_test.cc
index 13790fe..07d20e24 100644
--- a/third_party/blink/renderer/core/css/check_pseudo_has_fast_reject_filter_test.cc
+++ b/third_party/blink/renderer/core/css/check_pseudo_has_fast_reject_filter_test.cc
@@ -49,6 +49,7 @@
 
     CheckPseudoHasArgumentContext context(
         selector_list->First()->SelectorList()->First(),
+        /*scope=*/nullptr,
         /* match_in_shadow_tree */ false);
 
     return filter.FastReject(context.GetPseudoHasArgumentHashes());
diff --git a/third_party/blink/renderer/core/css/css_property_value_set.cc b/third_party/blink/renderer/core/css/css_property_value_set.cc
index 5e2ac6f..4675138 100644
--- a/third_party/blink/renderer/core/css/css_property_value_set.cc
+++ b/third_party/blink/renderer/core/css/css_property_value_set.cc
@@ -805,6 +805,4 @@
 }
 #endif
 
-void CSSLazyPropertyParser::Trace(Visitor* visitor) const {}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/css_property_value_set.h b/third_party/blink/renderer/core/css/css_property_value_set.h
index 8cfac35..24adc9c 100644
--- a/third_party/blink/renderer/core/css/css_property_value_set.h
+++ b/third_party/blink/renderer/core/css/css_property_value_set.h
@@ -196,17 +196,6 @@
   friend class PropertySetCSSStyleDeclaration;
 };
 
-// Used for lazily parsing properties.
-class CSSLazyPropertyParser : public GarbageCollected<CSSLazyPropertyParser> {
- public:
-  CSSLazyPropertyParser() = default;
-  CSSLazyPropertyParser(const CSSLazyPropertyParser&) = delete;
-  CSSLazyPropertyParser& operator=(const CSSLazyPropertyParser&) = delete;
-  virtual ~CSSLazyPropertyParser() = default;
-  virtual CSSPropertyValueSet* ParseProperties() = 0;
-  virtual void Trace(Visitor*) const;
-};
-
 class CORE_EXPORT alignas(CSSPropertyName) ImmutableCSSPropertyValueSet
     : public CSSPropertyValueSet {
  public:
diff --git a/third_party/blink/renderer/core/css/css_selector.cc b/third_party/blink/renderer/core/css/css_selector.cc
index aba7ba9..aaee3dc 100644
--- a/third_party/blink/renderer/core/css/css_selector.cc
+++ b/third_party/blink/renderer/core/css/css_selector.cc
@@ -59,7 +59,7 @@
 
 namespace {
 
-constexpr bool kExpandPseudoParent = true;
+constexpr bool kExpandPseudoReferences = true;
 
 unsigned MaximumSpecificity(const CSSSelectorList* list) {
   if (!list) {
@@ -1097,29 +1097,35 @@
 }
 
 // static
-template <bool expand_pseudo_parent>
+template <bool expand_pseudo_references>
 void CSSSelector::SerializeSelectorList(const CSSSelectorList* selector_list,
-                                        StringBuilder& builder) {
+                                        StringBuilder& builder,
+                                        uintptr_t scope_id) {
   const CSSSelector* first_sub_selector = selector_list->First();
   for (const CSSSelector* sub_selector = first_sub_selector; sub_selector;
        sub_selector = CSSSelectorList::Next(*sub_selector)) {
     if (sub_selector != first_sub_selector) {
       builder.Append(", ");
     }
-    builder.Append(sub_selector->SelectorTextInternal<expand_pseudo_parent>());
+    builder.Append(
+        sub_selector->SelectorTextInternal<expand_pseudo_references>(scope_id));
   }
 }
 
 String CSSSelector::SelectorText() const {
-  return SelectorTextInternal<!kExpandPseudoParent>();
+  // The value of `scope_id` does not matter when
+  // `expand_pseudo_references` is `false`.
+  return SelectorTextInternal<!kExpandPseudoReferences>(/*scope_id=*/0);
 }
 
-String CSSSelector::SelectorTextExpandingPseudoParent() const {
-  return SelectorTextInternal<kExpandPseudoParent>();
+String CSSSelector::SelectorTextExpandingPseudoReferences(
+    uintptr_t scope_id) const {
+  return SelectorTextInternal<kExpandPseudoReferences>(scope_id);
 }
 
-template <bool expand_pseudo_parent>
-bool CSSSelector::SerializeSimpleSelector(StringBuilder& builder) const {
+template <bool expand_pseudo_references>
+bool CSSSelector::SerializeSimpleSelector(StringBuilder& builder,
+                                          uintptr_t scope_id) const {
   bool suppress_selector_list = false;
   if (Match() == kId) {
     builder.Append('#');
@@ -1130,7 +1136,8 @@
   } else if (Match() == kPseudoClass || Match() == kPagePseudoClass) {
     if (GetPseudoType() == kPseudoUnparsed) {
       builder.Append(Value());
-    } else if (GetPseudoType() != kPseudoParent) {
+    } else if (GetPseudoType() != kPseudoParent &&
+               GetPseudoType() != kPseudoScope) {
       builder.Append(':');
       builder.Append(SerializingValue());
     }
@@ -1166,8 +1173,8 @@
         // Only relevant for :nth-child, not :nth-of-type.
         if (data_.rare_data_->selector_list_ != nullptr) {
           builder.Append(" of ");
-          SerializeSelectorList<expand_pseudo_parent>(
-              data_.rare_data_->selector_list_, builder);
+          SerializeSelectorList<expand_pseudo_references>(
+              data_.rare_data_->selector_list_, builder, scope_id);
           suppress_selector_list = true;
         }
 
@@ -1192,18 +1199,28 @@
       case kPseudoWhere:
         break;
       case kPseudoParent:
-        if constexpr (expand_pseudo_parent) {
+        if constexpr (expand_pseudo_references) {
           // Replace parent pseudo with equivalent :is() pseudo.
           builder.Append(":is");
           if (auto* parent = SelectorListOrParent()) {
             builder.Append('(');
-            builder.Append(parent->SelectorTextExpandingPseudoParent());
+            builder.Append(
+                parent->SelectorTextExpandingPseudoReferences(scope_id));
             builder.Append(')');
           }
         } else {
           builder.Append('&');
         }
         break;
+      case kPseudoScope:
+        if constexpr (expand_pseudo_references) {
+          builder.Append(":-internal-scope-");
+          builder.AppendNumber(scope_id);
+        } else {
+          builder.Append(':');
+          builder.Append(SerializingValue());
+        }
+        break;
       case kPseudoRelativeAnchor:
         NOTREACHED();
       case kPseudoActiveViewTransitionType: {
@@ -1319,15 +1336,16 @@
 
   if (SelectorList() && !suppress_selector_list) {
     builder.Append('(');
-    SerializeSelectorList<expand_pseudo_parent>(SelectorList(), builder);
+    SerializeSelectorList<expand_pseudo_references>(SelectorList(), builder,
+                                                    scope_id);
     builder.Append(')');
   }
   return true;
 }
 
-template <bool expand_pseudo_parent>
-const CSSSelector* CSSSelector::SerializeCompound(
-    StringBuilder& builder) const {
+template <bool expand_pseudo_references>
+const CSSSelector* CSSSelector::SerializeCompound(StringBuilder& builder,
+                                                  uintptr_t scope_id) const {
   if (Match() == kTag && !IsImplicit()) {
     SerializeNamespacePrefixIfNeeded(TagQName().Prefix(), g_star_atom, builder,
                                      IsAttributeSelector());
@@ -1337,8 +1355,8 @@
 
   for (const CSSSelector* simple_selector = this; simple_selector;
        simple_selector = simple_selector->NextSimpleSelector()) {
-    if (!simple_selector->SerializeSimpleSelector<expand_pseudo_parent>(
-            builder)) {
+    if (!simple_selector->SerializeSimpleSelector<expand_pseudo_references>(
+            builder, scope_id)) {
       return nullptr;
     }
     if (simple_selector->Relation() != kSubSelector) {
@@ -1348,13 +1366,14 @@
   return nullptr;
 }
 
-template <bool expand_pseudo_parent>
-String CSSSelector::SelectorTextInternal() const {
+template <bool expand_pseudo_references>
+String CSSSelector::SelectorTextInternal(uintptr_t scope_id) const {
   String result;
   for (const CSSSelector* compound = this; compound;
        compound = compound->NextSimpleSelector()) {
     StringBuilder builder;
-    compound = compound->SerializeCompound<expand_pseudo_parent>(builder);
+    compound = compound->SerializeCompound<expand_pseudo_references>(builder,
+                                                                     scope_id);
     if (!compound) {
       return builder.ReleaseString() + result;
     }
@@ -1366,10 +1385,13 @@
     DCHECK(next_compound);
 
     // If we are combining with an implicit :scope, it is as if we
-    // used a relative combinator.
-    if (!next_compound || (next_compound->Match() == kPseudoClass &&
-                           next_compound->GetPseudoType() == kPseudoScope &&
-                           next_compound->IsImplicit())) {
+    // used a relative combinator. However, when expand_pseudo_references=true,
+    // we must serialize the implicit compound anyway, since the :has() cache
+    // needs this to be a part of the key.
+    bool implicit = next_compound->IsImplicit() && !expand_pseudo_references;
+    if (!next_compound ||
+        (next_compound->Match() == kPseudoClass &&
+         next_compound->GetPseudoType() == kPseudoScope && implicit)) {
       relation = ConvertRelationToRelative(relation);
     }
 
@@ -1413,7 +1435,8 @@
     SerializeIdentifierOrAny(TagQName().LocalName(), UniversalSelectorAtom(),
                              builder);
   } else {
-    SerializeSimpleSelector<!kExpandPseudoParent>(builder);
+    // `scope_id` is ignored when `expand_pseudo_references` is false.
+    SerializeSimpleSelector<!kExpandPseudoReferences>(builder, /*scope_id=*/0);
   }
   return builder.ToString();
 }
diff --git a/third_party/blink/renderer/core/css/css_selector.h b/third_party/blink/renderer/core/css/css_selector.h
index 6f505ad..23a932ad 100644
--- a/third_party/blink/renderer/core/css/css_selector.h
+++ b/third_party/blink/renderer/core/css/css_selector.h
@@ -156,11 +156,15 @@
   ~CSSSelector();
 
   String SelectorText() const;
-  // Like `SelectorText`, but replaces any '&' selectors
-  // with ':is(<parent rule selector list>)'. This is needed
-  // by the :has() cache, because it uses the serialization of
-  // the selector as a key.
-  String SelectorTextExpandingPseudoParent() const;
+  // Like `SelectorText`, but replaces any "pseudo-references" with an expansion
+  // which makes the result useful as a key in the :has() cache.
+  // A "pseudo-reference" is either a '&' selector (which is replaced with
+  // :is(<parent rule selector list>)), or a :scope selector (which is replaced
+  // with :-internal-scope-<scope_id>).
+  //
+  // Note that this means that the returned text is not necessarily a valid
+  // selector.
+  String SelectorTextExpandingPseudoReferences(uintptr_t scope_id) const;
   String SimpleSelectorTextForDebug() const;
 
   CSSSelector& operator=(const CSSSelector&) = delete;
@@ -685,18 +689,21 @@
   unsigned SpecificityForOneSelector() const;
   unsigned SpecificityForPage() const;
 
-  template <bool expand_pseudo_parent>
-  bool SerializeSimpleSelector(WTF::StringBuilder& builder) const;
+  template <bool expand_pseudo_references>
+  bool SerializeSimpleSelector(WTF::StringBuilder& builder,
+                               uintptr_t scope_id) const;
 
-  template <bool expand_pseudo_parent>
-  const CSSSelector* SerializeCompound(WTF::StringBuilder&) const;
+  template <bool expand_pseudo_references>
+  const CSSSelector* SerializeCompound(WTF::StringBuilder&,
+                                       uintptr_t scope_id) const;
 
-  template <bool expand_pseudo_parent>
+  template <bool expand_pseudo_references>
   static void SerializeSelectorList(const CSSSelectorList* selector_list,
-                                    WTF::StringBuilder& builder);
+                                    WTF::StringBuilder& builder,
+                                    uintptr_t scope_id);
 
-  template <bool expand_pseudo_parent>
-  String SelectorTextInternal() const;
+  template <bool expand_pseudo_references>
+  String SelectorTextInternal(uintptr_t scope_id) const;
 
   struct RareData : public GarbageCollected<RareData> {
     explicit RareData(const AtomicString& value);
diff --git a/third_party/blink/renderer/core/css/css_selector_test.cc b/third_party/blink/renderer/core/css/css_selector_test.cc
index d98cdd3..1c91b13 100644
--- a/third_party/blink/renderer/core/css/css_selector_test.cc
+++ b/third_party/blink/renderer/core/css/css_selector_test.cc
@@ -312,7 +312,7 @@
             selector[0].Specificity());
 }
 
-TEST(CSSSelector, CheckSelectorTextExpandingPseudoParent) {
+TEST(CSSSelector, SelectorTextExpandingPseudoReferences_Parent) {
   test::TaskEnvironment task_environment;
 
   css_test_helpers::TestStyleSheet sheet;
@@ -330,21 +330,23 @@
   ASSERT_EQ(1u, rules.size());
   selector = &rules[0].Selector();
   EXPECT_EQ("& .b", selector->SelectorText());
-  EXPECT_EQ(":is(.a) .b", selector->SelectorTextExpandingPseudoParent());
+  EXPECT_EQ(":is(.a) .b",
+            selector->SelectorTextExpandingPseudoReferences(/*scope_id=*/0));
 
   rules = rule_set.ClassRules(AtomicString("c"));
   ASSERT_EQ(3u, rules.size());
   selector = &rules[0].Selector();
   EXPECT_EQ("& .c", selector->SelectorText());
   EXPECT_EQ(":is(:is(.a) .b) .c",
-            selector->SelectorTextExpandingPseudoParent());
+            selector->SelectorTextExpandingPseudoReferences(/*scope_id=*/0));
   selector = &rules[1].Selector();
   EXPECT_EQ("&.c", selector->SelectorText());
-  EXPECT_EQ(":is(:is(.a) .b).c", selector->SelectorTextExpandingPseudoParent());
+  EXPECT_EQ(":is(:is(.a) .b).c",
+            selector->SelectorTextExpandingPseudoReferences(/*scope_id=*/0));
   selector = &rules[2].Selector();
   EXPECT_EQ(".c:has(&)", selector->SelectorText());
   EXPECT_EQ(".c:has(:is(:is(.a) .b))",
-            selector->SelectorTextExpandingPseudoParent());
+            selector->SelectorTextExpandingPseudoReferences(/*scope_id=*/0));
 
   rules = rule_set.ClassRules(AtomicString("e"));
   ASSERT_EQ(1u, rules.size());
@@ -356,7 +358,54 @@
   selector = &rules[0].Selector();
   EXPECT_EQ(".f:has(> &)", selector->SelectorText());
   EXPECT_EQ(".f:has(> :is(.d .e))",
-            selector->SelectorTextExpandingPseudoParent());
+            selector->SelectorTextExpandingPseudoReferences(/*scope_id=*/0));
+}
+
+TEST(CSSSelector, SelectorTextExpandingPseudoReferences_Scope) {
+  test::TaskEnvironment task_environment;
+
+  auto expanded_selector_text = [](String s) {
+    return css_test_helpers::ParseSelectorList(s)
+        ->First()
+        ->SelectorTextExpandingPseudoReferences(/*scope_id=*/42);
+  };
+
+  EXPECT_EQ(".a .b :has(.c)", expanded_selector_text(".a .b :has(.c)"));
+
+  EXPECT_EQ(":-internal-scope-42", expanded_selector_text(":scope"));
+  EXPECT_EQ(".a:-internal-scope-42", expanded_selector_text(".a:scope"));
+  EXPECT_EQ(".a :-internal-scope-42", expanded_selector_text(".a :scope"));
+  EXPECT_EQ(":-internal-scope-42.a", expanded_selector_text(":scope.a"));
+  EXPECT_EQ(":is(.a, :-internal-scope-42)",
+            expanded_selector_text(":is(.a, :scope)"));
+  EXPECT_EQ(":not(.a, :-internal-scope-42)",
+            expanded_selector_text(":not(.a, :scope)"));
+  EXPECT_EQ(
+      ":not(.a, :-internal-scope-42)"
+      ":where(:-internal-scope-42, :-internal-scope-42):-internal-scope-42",
+      expanded_selector_text(":not(.a, :scope):where(:scope, :scope):scope"));
+  EXPECT_EQ(":has(.b:not(:-internal-scope-42 .a *))",
+            expanded_selector_text(":has(.b:not(:scope .a *))"));
+}
+
+TEST(CSSSelector, SelectorTextExpandingPseudoReferences_ImplicitScope) {
+  test::TaskEnvironment task_environment;
+
+  css_test_helpers::TestStyleSheet sheet;
+  sheet.AddCSSRules(R"CSS(
+    @scope (.a) {
+      /* There's an implicit (non-serialized) ':scope' (plus descendant
+         combinator) prepended to the selector below. */
+      .b {}
+    }
+  )CSS");
+  RuleSet& rule_set = sheet.GetRuleSet();
+  base::span<const RuleData> rules = rule_set.ClassRules(AtomicString("b"));
+  ASSERT_EQ(1u, rules.size());
+  const CSSSelector* selector = &rules[0].Selector();
+  EXPECT_EQ(".b", selector->SelectorText());
+  EXPECT_EQ(":-internal-scope-99 .b",
+            selector->SelectorTextExpandingPseudoReferences(/*scope_id=*/99));
 }
 
 TEST(CSSSelector, CheckHasArgumentMatchInShadowTreeFlag) {
@@ -482,10 +531,12 @@
   CSSSelectorList* new_list = old_list->Renest(b);
   EXPECT_NE(old_list, new_list);
 
-  EXPECT_EQ(":is(.a):is(:is(.a), .d)",
-            old_list->First()->SelectorTextExpandingPseudoParent());
-  EXPECT_EQ(":is(.b):is(:is(.b), .d)",
-            new_list->First()->SelectorTextExpandingPseudoParent());
+  EXPECT_EQ(
+      ":is(.a):is(:is(.a), .d)",
+      old_list->First()->SelectorTextExpandingPseudoReferences(/*scope_id=*/0));
+  EXPECT_EQ(
+      ":is(.b):is(:is(.b), .d)",
+      new_list->First()->SelectorTextExpandingPseudoReferences(/*scope_id=*/0));
 }
 
 TEST(CSSSelector, RenestNoNesting) {
diff --git a/third_party/blink/renderer/core/css/css_style_declaration.cc b/third_party/blink/renderer/core/css/css_style_declaration.cc
index 0cf3b1c..2b9fdd53 100644
--- a/third_party/blink/renderer/core/css/css_style_declaration.cc
+++ b/third_party/blink/renderer/core/css/css_style_declaration.cc
@@ -192,26 +192,23 @@
   if (!IsValidCSSPropertyID(unresolved_property)) {
     return NamedPropertySetterResult::kDidNotIntercept;
   }
-  // We create the ExceptionState manually due to performance issues: adding
-  // [RaisesException] to the IDL causes the bindings layer to expensively
-  // create a std::string to set the ExceptionState's |property_name| argument,
-  // while we can use CSSProperty::GetPropertyName() here (see bug 829408).
-  ExceptionState exception_state(script_state->GetIsolate());
   // TODO(crbug.com/1499981): This should be removed once synchronized scrolling
   // impact is understood.
   SyncScrollAttemptHeuristic::DidSetStyle();
   if (value->IsNumber()) {
-    double double_value = NativeValueTraits<IDLUnrestrictedDouble>::NativeValue(
-        script_state->GetIsolate(), value, exception_state);
-    if (exception_state.HadException()) [[unlikely]] {
-      return NamedPropertySetterResult::kIntercepted;
-    }
+    double double_value = value.As<v8::Number>()->Value();
     if (FastPathSetProperty(unresolved_property, double_value)) {
       return NamedPropertySetterResult::kIntercepted;
     }
     // The fast path failed, e.g. because the property was a longhand,
     // so let the normal string handling deal with it.
   }
+  // We create the ExceptionState manually due to performance issues: adding
+  // [RaisesException] to the IDL causes the bindings layer to expensively
+  // create a std::string to set the ExceptionState's |property_name|
+  // argument, while we can use CSSProperty::GetPropertyName() here (see bug
+  // 829408).
+  ExceptionState exception_state(script_state->GetIsolate());
   if (value->IsString()) {
     // NativeValueTraits::ToBlinkStringView() (called implicitly on conversion)
     // tries fairly hard to make an AtomicString out of the string,
diff --git a/third_party/blink/renderer/core/css/cssom_utils.cc b/third_party/blink/renderer/core/css/cssom_utils.cc
index c5ef5c6..55aeb1e 100644
--- a/third_party/blink/renderer/core/css/cssom_utils.cc
+++ b/third_party/blink/renderer/core/css/cssom_utils.cc
@@ -157,11 +157,10 @@
         grid_area_text.Append(' ');
       }
     }
-    if (!grid_area_text.empty()) {
-      template_row_list->Append(*MakeGarbageCollected<CSSStringValue>(
-          grid_area_text.ReleaseString()));
-      ++row;
-    }
+    DCHECK(!grid_area_text.empty());
+    template_row_list->Append(
+        *MakeGarbageCollected<CSSStringValue>(grid_area_text.ReleaseString()));
+    ++row;
 
     // Omit `auto` values.
     if (!IsAutoValue(row_value.Get())) {
diff --git a/third_party/blink/renderer/core/css/parser/css_lazy_property_parser.cc b/third_party/blink/renderer/core/css/parser/css_lazy_property_parser.cc
new file mode 100644
index 0000000..a5199aa
--- /dev/null
+++ b/third_party/blink/renderer/core/css/parser/css_lazy_property_parser.cc
@@ -0,0 +1,25 @@
+// Copyright 2016 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/parser/css_lazy_property_parser.h"
+
+#include "third_party/blink/renderer/core/css/parser/css_lazy_parsing_state.h"
+#include "third_party/blink/renderer/core/css/parser/css_parser_impl.h"
+
+namespace blink {
+
+CSSLazyPropertyParser::CSSLazyPropertyParser(wtf_size_t offset,
+                                             CSSLazyParsingState* state)
+    : offset_(offset), lazy_state_(state) {}
+
+CSSPropertyValueSet* CSSLazyPropertyParser::ParseProperties() {
+  return CSSParserImpl::ParseDeclarationListForLazyStyle(
+      lazy_state_->SheetText(), offset_, lazy_state_->Context());
+}
+
+void CSSLazyPropertyParser::Trace(Visitor* visitor) const {
+  visitor->Trace(lazy_state_);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/parser/css_lazy_property_parser_impl.h b/third_party/blink/renderer/core/css/parser/css_lazy_property_parser.h
similarity index 66%
rename from third_party/blink/renderer/core/css/parser/css_lazy_property_parser_impl.h
rename to third_party/blink/renderer/core/css/parser/css_lazy_property_parser.h
index 9a1baf7..f7e72ce 100644
--- a/third_party/blink/renderer/core/css/parser/css_lazy_property_parser_impl.h
+++ b/third_party/blink/renderer/core/css/parser/css_lazy_property_parser.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PARSER_CSS_LAZY_PROPERTY_PARSER_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PARSER_CSS_LAZY_PROPERTY_PARSER_IMPL_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PARSER_CSS_LAZY_PROPERTY_PARSER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PARSER_CSS_LAZY_PROPERTY_PARSER_H_
 
 #include "third_party/blink/renderer/core/css/css_property_value_set.h"
 #include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
@@ -13,17 +13,14 @@
 class CSSLazyParsingState;
 
 // This class is responsible for lazily parsing a single CSS declaration list.
-class CSSLazyPropertyParserImpl : public CSSLazyPropertyParser {
+class CSSLazyPropertyParser : public GarbageCollected<CSSLazyPropertyParser> {
  public:
-  CSSLazyPropertyParserImpl(wtf_size_t offset, CSSLazyParsingState*);
+  CSSLazyPropertyParser(wtf_size_t offset, CSSLazyParsingState*);
 
   // CSSLazyPropertyParser:
-  CSSPropertyValueSet* ParseProperties() override;
+  CSSPropertyValueSet* ParseProperties();
 
-  void Trace(Visitor* visitor) const override {
-    visitor->Trace(lazy_state_);
-    CSSLazyPropertyParser::Trace(visitor);
-  }
+  void Trace(Visitor* visitor) const;
 
  private:
   wtf_size_t offset_;
@@ -32,4 +29,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PARSER_CSS_LAZY_PROPERTY_PARSER_IMPL_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PARSER_CSS_LAZY_PROPERTY_PARSER_H_
diff --git a/third_party/blink/renderer/core/css/parser/css_lazy_property_parser_impl.cc b/third_party/blink/renderer/core/css/parser/css_lazy_property_parser_impl.cc
deleted file mode 100644
index a4314d8f..0000000
--- a/third_party/blink/renderer/core/css/parser/css_lazy_property_parser_impl.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/css/parser/css_lazy_property_parser_impl.h"
-
-#include "third_party/blink/renderer/core/css/parser/css_lazy_parsing_state.h"
-#include "third_party/blink/renderer/core/css/parser/css_parser_impl.h"
-
-namespace blink {
-
-CSSLazyPropertyParserImpl::CSSLazyPropertyParserImpl(wtf_size_t offset,
-                                                     CSSLazyParsingState* state)
-    : CSSLazyPropertyParser(), offset_(offset), lazy_state_(state) {}
-
-CSSPropertyValueSet* CSSLazyPropertyParserImpl::ParseProperties() {
-  return CSSParserImpl::ParseDeclarationListForLazyStyle(
-      lazy_state_->SheetText(), offset_, lazy_state_->Context());
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/parser/css_parser_impl.cc b/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
index 477862b..cdde6c0 100644
--- a/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
+++ b/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
@@ -30,7 +30,7 @@
 #include "third_party/blink/renderer/core/css/parser/container_query_parser.h"
 #include "third_party/blink/renderer/core/css/parser/css_at_rule_id.h"
 #include "third_party/blink/renderer/core/css/parser/css_lazy_parsing_state.h"
-#include "third_party/blink/renderer/core/css/parser/css_lazy_property_parser_impl.h"
+#include "third_party/blink/renderer/core/css/parser/css_lazy_property_parser.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_observer.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_token_stream.h"
 #include "third_party/blink/renderer/core/css/parser/css_property_parser.h"
@@ -2671,9 +2671,9 @@
       if (len != 0) {
         wtf_size_t block_start_offset = stream.Offset();
         stream.SkipToEndOfBlock(len + 2);  // +2 for { and }.
-        return StyleRule::Create(
-            selector_vector, MakeGarbageCollected<CSSLazyPropertyParserImpl>(
-                                 block_start_offset, lazy_state_));
+        return StyleRule::Create(selector_vector,
+                                 MakeGarbageCollected<CSSLazyPropertyParser>(
+                                     block_start_offset, lazy_state_));
       }
     }
     CSSParserTokenStream::BlockGuard guard(stream);
@@ -2706,7 +2706,7 @@
       }
 
       return StyleRule::Create(selector_vector,
-                               MakeGarbageCollected<CSSLazyPropertyParserImpl>(
+                               MakeGarbageCollected<CSSLazyPropertyParser>(
                                    block_start_offset, lazy_state_));
     }
     return ConsumeStyleRuleContents(selector_vector, stream,
diff --git a/third_party/blink/renderer/core/css/parser/css_parser_impl_test.cc b/third_party/blink/renderer/core/css/parser/css_parser_impl_test.cc
index 9f02b9fa..5a9db03 100644
--- a/third_party/blink/renderer/core/css/parser/css_parser_impl_test.cc
+++ b/third_party/blink/renderer/core/css/parser/css_parser_impl_test.cc
@@ -1374,9 +1374,10 @@
   auto* a = To<StyleRule>(css_test_helpers::ParseRule(*document, ".a{}"));
   StyleRuleBase* nested = css_test_helpers::ParseNestedRule(
       *document, "&{}", CSSNestingType::kNesting, a);
-  EXPECT_EQ(":is(.a)", To<StyleRule>(nested)
-                           ->FirstSelector()
-                           ->SelectorTextExpandingPseudoParent());
+  EXPECT_EQ(":is(.a)",
+            To<StyleRule>(nested)
+                ->FirstSelector()
+                ->SelectorTextExpandingPseudoReferences(/*scope_id=*/0));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/resolver/matched_properties_cache.h b/third_party/blink/renderer/core/css/resolver/matched_properties_cache.h
index c8ba7a6..c747cce5 100644
--- a/third_party/blink/renderer/core/css/resolver/matched_properties_cache.h
+++ b/third_party/blink/renderer/core/css/resolver/matched_properties_cache.h
@@ -143,7 +143,9 @@
   // well with complex keys. Of course, it means we are vulnerable to hash
   // collisions, in that we cannot store more than one different cache entry
   // with the same hash.
-  using Cache = HeapHashMap<unsigned, Member<CachedMatchedProperties>>;
+  using Cache = HeapHashMap<unsigned,
+                            Member<CachedMatchedProperties>,
+                            AlreadyHashedTraits>;
 
   void CleanMatchedPropertiesCache(const LivenessBroker&);
 
diff --git a/third_party/blink/renderer/core/css/selector_checker.cc b/third_party/blink/renderer/core/css/selector_checker.cc
index 82816d5..0c27bb1 100644
--- a/third_party/blink/renderer/core/css/selector_checker.cc
+++ b/third_party/blink/renderer/core/css/selector_checker.cc
@@ -1418,7 +1418,7 @@
   DCHECK(context.selector->SelectorList());
   for (const CSSSelector* selector = context.selector->SelectorList()->First();
        selector; selector = CSSSelectorList::Next(*selector)) {
-    CheckPseudoHasArgumentContext argument_context(selector,
+    CheckPseudoHasArgumentContext argument_context(selector, context.scope,
                                                    match_in_shadow_tree);
 
     // In case of matching a :has() argument on a shadow root subtree, skip
diff --git a/third_party/blink/renderer/core/css/style_rule.h b/third_party/blink/renderer/core/css/style_rule.h
index d43bf22..b5c77cdf 100644
--- a/third_party/blink/renderer/core/css/style_rule.h
+++ b/third_party/blink/renderer/core/css/style_rule.h
@@ -40,6 +40,7 @@
 #include "third_party/blink/renderer/core/css/css_variable_data.h"
 #include "third_party/blink/renderer/core/css/media_list.h"
 #include "third_party/blink/renderer/core/css/parser/css_at_rule_id.h"
+#include "third_party/blink/renderer/core/css/parser/css_lazy_property_parser.h"
 #include "third_party/blink/renderer/core/css/parser/css_nesting_type.h"
 #include "third_party/blink/renderer/core/css/style_scope.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
@@ -409,6 +410,7 @@
   void TraceAfterDispatch(blink::Visitor*) const;
 
   const StyleScope& GetStyleScope() const { return *style_scope_; }
+
  private:
   Member<const StyleScope> style_scope_;
 };
diff --git a/third_party/blink/renderer/core/css/style_rule_test.cc b/third_party/blink/renderer/core/css/style_rule_test.cc
index 9190d822..1299379 100644
--- a/third_party/blink/renderer/core/css/style_rule_test.cc
+++ b/third_party/blink/renderer/core/css/style_rule_test.cc
@@ -317,14 +317,17 @@
       /*parent_rule_for_nesting=*/a));
 
   EXPECT_EQ(":is(.a)",
-            nested->FirstSelector()->SelectorTextExpandingPseudoParent());
+            nested->FirstSelector()->SelectorTextExpandingPseudoReferences(
+                /*scope_id=*/0));
 
   auto* reparented = To<StyleRule>(nested->Renest(b));
   EXPECT_NE(nested, reparented);
   EXPECT_EQ(":is(.a)",
-            nested->FirstSelector()->SelectorTextExpandingPseudoParent());
+            nested->FirstSelector()->SelectorTextExpandingPseudoReferences(
+                /*scope_id=*/0));
   EXPECT_EQ(":is(.b)",
-            reparented->FirstSelector()->SelectorTextExpandingPseudoParent());
+            reparented->FirstSelector()->SelectorTextExpandingPseudoReferences(
+                /*scope_id=*/0));
 }
 
 TEST_F(StyleRuleTest, RenestStyleRuleNoOp) {
@@ -333,7 +336,8 @@
       GetDocument(), "& {}", CSSNestingType::kNesting,
       /*parent_rule_for_nesting=*/a));
   EXPECT_EQ(":is(.a)",
-            nested->FirstSelector()->SelectorTextExpandingPseudoParent());
+            nested->FirstSelector()->SelectorTextExpandingPseudoReferences(
+                /*scope_id=*/0));
   auto* reparented = To<StyleRule>(nested->Renest(a));
   EXPECT_EQ(nested, reparented);
 }
@@ -346,20 +350,23 @@
       /*parent_rule_for_nesting=*/a));
 
   ASSERT_EQ(1u, media->ChildRules().size());
-  EXPECT_EQ(":is(.a)", To<StyleRule>(media->ChildRules().front().Get())
-                           ->FirstSelector()
-                           ->SelectorTextExpandingPseudoParent());
+  EXPECT_EQ(":is(.a)",
+            To<StyleRule>(media->ChildRules().front().Get())
+                ->FirstSelector()
+                ->SelectorTextExpandingPseudoReferences(/*scope_id=*/0));
 
   EXPECT_EQ(media->Renest(a), media);  // No-op.
 
   auto* reparented = To<StyleRuleMedia>(media->Renest(b));
   EXPECT_NE(media, reparented);
-  EXPECT_EQ(":is(.a)", To<StyleRule>(media->ChildRules().front().Get())
-                           ->FirstSelector()
-                           ->SelectorTextExpandingPseudoParent());
-  EXPECT_EQ(":is(.b)", To<StyleRule>(reparented->ChildRules().front().Get())
-                           ->FirstSelector()
-                           ->SelectorTextExpandingPseudoParent());
+  EXPECT_EQ(":is(.a)",
+            To<StyleRule>(media->ChildRules().front().Get())
+                ->FirstSelector()
+                ->SelectorTextExpandingPseudoReferences(/*scope_id=*/0));
+  EXPECT_EQ(":is(.b)",
+            To<StyleRule>(reparented->ChildRules().front().Get())
+                ->FirstSelector()
+                ->SelectorTextExpandingPseudoReferences(/*scope_id=*/0));
 }
 
 TEST_F(StyleRuleTest, RenestStyleRuleStartingStyle) {
@@ -371,20 +378,23 @@
           /*parent_rule_for_nesting=*/a));
 
   ASSERT_EQ(1u, starting_style->ChildRules().size());
-  EXPECT_EQ(":is(.a)", To<StyleRule>(starting_style->ChildRules().front().Get())
-                           ->FirstSelector()
-                           ->SelectorTextExpandingPseudoParent());
+  EXPECT_EQ(":is(.a)",
+            To<StyleRule>(starting_style->ChildRules().front().Get())
+                ->FirstSelector()
+                ->SelectorTextExpandingPseudoReferences(/*scope_id=*/0));
 
   EXPECT_EQ(starting_style->Renest(a), starting_style);  // No-op.
 
   auto* reparented = To<StyleRuleStartingStyle>(starting_style->Renest(b));
   EXPECT_NE(starting_style, reparented);
-  EXPECT_EQ(":is(.a)", To<StyleRule>(starting_style->ChildRules().front().Get())
-                           ->FirstSelector()
-                           ->SelectorTextExpandingPseudoParent());
-  EXPECT_EQ(":is(.b)", To<StyleRule>(reparented->ChildRules().front().Get())
-                           ->FirstSelector()
-                           ->SelectorTextExpandingPseudoParent());
+  EXPECT_EQ(":is(.a)",
+            To<StyleRule>(starting_style->ChildRules().front().Get())
+                ->FirstSelector()
+                ->SelectorTextExpandingPseudoReferences(/*scope_id=*/0));
+  EXPECT_EQ(":is(.b)",
+            To<StyleRule>(reparented->ChildRules().front().Get())
+                ->FirstSelector()
+                ->SelectorTextExpandingPseudoReferences(/*scope_id=*/0));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/abort_controller.idl b/third_party/blink/renderer/core/dom/abort_controller.idl
index 748c127..3effadd 100644
--- a/third_party/blink/renderer/core/dom/abort_controller.idl
+++ b/third_party/blink/renderer/core/dom/abort_controller.idl
@@ -5,7 +5,7 @@
 // https://dom.spec.whatwg.org/#interface-abortcontroller
 
 [
-    Exposed=(Window,Worker)
+    Exposed=(Window,Worker,ShadowRealm) // TODO(crbug.com/41480387): This should be Exposed=*
 ] interface AbortController {
     [CallWith=ScriptState, Measure] constructor();
     [SameObject] readonly attribute AbortSignal signal;
diff --git a/third_party/blink/renderer/core/dom/abort_signal.idl b/third_party/blink/renderer/core/dom/abort_signal.idl
index d0d3318..7f1d3e0 100644
--- a/third_party/blink/renderer/core/dom/abort_signal.idl
+++ b/third_party/blink/renderer/core/dom/abort_signal.idl
@@ -5,7 +5,7 @@
 // https://dom.spec.whatwg.org/#interface-AbortSignal
 
 [
-    Exposed=(Window,Worker)
+    Exposed=(Window,Worker,ShadowRealm) // TODO(crbug.com/41480387): This should be Exposed=*
 ] interface AbortSignal : EventTarget {
     [
         CallWith=ScriptState,
@@ -13,6 +13,7 @@
         NewObject
     ] static AbortSignal abort(optional any reason);
     [
+        Exposed=(Window,Worker),
         CallWith=ScriptState,
         MeasureAs=AbortSignalTimeout,
         NewObject
diff --git a/third_party/blink/renderer/core/dom/dom_exception.idl b/third_party/blink/renderer/core/dom/dom_exception.idl
index 866ffbc..6e82962 100644
--- a/third_party/blink/renderer/core/dom/dom_exception.idl
+++ b/third_party/blink/renderer/core/dom/dom_exception.idl
@@ -31,7 +31,7 @@
 // https://webidl.spec.whatwg.org/#es-DOMException
 
 [
-    Exposed=(Window,Worker),
+    Exposed=(Window,Worker,ShadowRealm), // TODO(crbug.com/41480387): This should be Exposed=*
     Serializable
 ] interface DOMException {
     constructor(optional DOMString message = "", optional DOMString name = "Error");
diff --git a/third_party/blink/renderer/core/dom/events/custom_event.idl b/third_party/blink/renderer/core/dom/events/custom_event.idl
index 0bb00fd..91eb44be 100644
--- a/third_party/blink/renderer/core/dom/events/custom_event.idl
+++ b/third_party/blink/renderer/core/dom/events/custom_event.idl
@@ -26,7 +26,7 @@
 // https://dom.spec.whatwg.org/#interface-customevent
 
 [
-    Exposed=(Window,Worker)
+    Exposed=(Window,Worker,ShadowRealm) // TODO(crbug.com/41480387): This should be Exposed=*
 ] interface CustomEvent : Event {
     [CallWith=ScriptState] constructor(DOMString type, optional CustomEventInit eventInitDict = {});
     [CallWith=ScriptState] readonly attribute any detail;
diff --git a/third_party/blink/renderer/core/dom/events/event.idl b/third_party/blink/renderer/core/dom/events/event.idl
index 5566b4b8..7ef78b6 100644
--- a/third_party/blink/renderer/core/dom/events/event.idl
+++ b/third_party/blink/renderer/core/dom/events/event.idl
@@ -21,7 +21,7 @@
 // https://dom.spec.whatwg.org/#interface-event
 
 [
-    Exposed=(Window,Worker,AudioWorklet)
+    Exposed=(Window,Worker,AudioWorklet,ShadowRealm) // TODO(crbug.com/41480387): This should be Exposed=*
 ] interface Event {
     constructor(DOMString type, optional EventInit eventInitDict = {});
     readonly attribute DOMString type;
diff --git a/third_party/blink/renderer/core/dom/events/event_listener.h b/third_party/blink/renderer/core/dom/events/event_listener.h
index 373cf6e..c8ddba3 100644
--- a/third_party/blink/renderer/core/dom/events/event_listener.h
+++ b/third_party/blink/renderer/core/dom/events/event_listener.h
@@ -22,7 +22,6 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_EVENTS_EVENT_LISTENER_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/probe/async_task_context.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -85,11 +84,8 @@
   virtual bool IsJSBasedEventListener() const { return false; }
   virtual bool IsNativeEventListener() const { return false; }
 
-  probe::AsyncTaskContext* async_task_context() { return &async_task_context_; }
-
  private:
   EventListener() = default;
-  probe::AsyncTaskContext async_task_context_;
 
   // Only these two classes are direct subclasses of EventListener.  Other
   // subclasses must inherit from either of them.
diff --git a/third_party/blink/renderer/core/dom/events/event_target.cc b/third_party/blink/renderer/core/dom/events/event_target.cc
index 7d081b1..49f2d7f 100644
--- a/third_party/blink/renderer/core/dom/events/event_target.cc
+++ b/third_party/blink/renderer/core/dom/events/event_target.cc
@@ -111,11 +111,6 @@
          IsWheelScrollBlockingEvent(event_type);
 }
 
-bool IsInstrumentedForAsyncStack(const AtomicString& event_type) {
-  return event_type == event_type_names::kLoad ||
-         event_type == event_type_names::kError;
-}
-
 base::TimeDelta BlockedEventsWarningThreshold(ExecutionContext* context,
                                               const Event& event) {
   if (!event.cancelable())
@@ -673,11 +668,6 @@
     }
 
     AddedEventListener(event_type, *registered_listener);
-    if (IsA<JSBasedEventListener>(listener) &&
-        IsInstrumentedForAsyncStack(event_type)) {
-      listener->async_task_context()->Schedule(GetExecutionContext(),
-                                               event_type);
-    }
   }
   return added;
 }
@@ -867,11 +857,6 @@
     return false;
   }
   if (registered_listener) {
-    if (IsA<JSBasedEventListener>(listener) &&
-        IsInstrumentedForAsyncStack(event_type)) {
-      listener->async_task_context()->Schedule(GetExecutionContext(),
-                                               event_type);
-    }
     registered_listener->SetCallback(listener);
     return true;
   }
@@ -1103,9 +1088,6 @@
     event.SetHandlingPassive(EventPassiveMode(*registered_listener));
 
     probe::UserCallback probe(context, nullptr, event.type(), false, this);
-    probe::AsyncTask async_task(context, listener->async_task_context(),
-                                "event",
-                                IsInstrumentedForAsyncStack(event.type()));
 
     // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling
     // event listeners, even though that violates some versions of the DOM spec.
diff --git a/third_party/blink/renderer/core/dom/events/event_target.idl b/third_party/blink/renderer/core/dom/events/event_target.idl
index c85efe46..8eebe64 100644
--- a/third_party/blink/renderer/core/dom/events/event_target.idl
+++ b/third_party/blink/renderer/core/dom/events/event_target.idl
@@ -26,7 +26,7 @@
 };
 
 [
-    Exposed=(Window,Worker,AudioWorklet)
+    Exposed=(Window,Worker,AudioWorklet,ShadowRealm) // TODO(crbug.com/41480387): This should be Exposed=*
 ] interface EventTarget {
     [CallWith=ScriptState] constructor();
     void addEventListener(DOMString type, EventListener? listener, optional (AddEventListenerOptions or boolean) options);
diff --git a/third_party/blink/renderer/core/dom/observable.idl b/third_party/blink/renderer/core/dom/observable.idl
index 648c9ba..b4660e8 100644
--- a/third_party/blink/renderer/core/dom/observable.idl
+++ b/third_party/blink/renderer/core/dom/observable.idl
@@ -45,7 +45,7 @@
 typedef (ObserverCallback or Observer) ObserverUnion;
 typedef (ObserverCallback or ObservableInspector) ObservableInspectorUnion;
 
-[Exposed=(Window,Worker), RuntimeEnabled=ObservableAPI]
+[Exposed=(Window,Worker,ShadowRealm), RuntimeEnabled=ObservableAPI] // TODO(crbug.com/40282760): This should be Exposed=*
 interface Observable {
   [CallWith=ScriptState, MeasureAs=ObservableConstructor] constructor(SubscribeCallback callback);
   [CallWith=ScriptState] void subscribe(optional ObserverUnion observer = {}, optional SubscribeOptions options = {});
diff --git a/third_party/blink/renderer/core/dom/subscriber.idl b/third_party/blink/renderer/core/dom/subscriber.idl
index 889cff6..197ed3ed 100644
--- a/third_party/blink/renderer/core/dom/subscriber.idl
+++ b/third_party/blink/renderer/core/dom/subscriber.idl
@@ -4,7 +4,7 @@
 
 // https://github.com/WICG/observable
 
-[Exposed=(Window,Worker), RuntimeEnabled=ObservableAPI]
+[Exposed=(Window,Worker,ShadowRealm), RuntimeEnabled=ObservableAPI] // TODO(crbug.com/40282760): This should be Exposed=*
 interface Subscriber {
   void next(any result);
   [CallWith=ScriptState] void error(any error);
diff --git a/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc b/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc
index a75a1d8..d2ce8672 100644
--- a/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc
+++ b/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc
@@ -218,9 +218,11 @@
     }
     if (RuntimeEnabledFeatures::IncludeTableTagInExtendedSelectionEnabled()) {
       if (last_closed_ && IsTablePartElement(last_closed_)) {
-        last_closed_ =
-            Traversal<HTMLTableElement>::FirstAncestor(*last_closed_);
-        should_append_parent_tag = true;
+        if (auto* first_ancestor_table_traversal =
+                Traversal<HTMLTableElement>::FirstAncestor(*last_closed_)) {
+          last_closed_ = first_ancestor_table_traversal;
+          should_append_parent_tag = true;
+        }
       }
     }
   }
@@ -304,7 +306,7 @@
       if (ancestor == highest_node_to_be_serialized_)
         break;
     }
-  } else if (should_append_parent_tag) {
+  } else if (should_append_parent_tag && last_closed_) {
     EditingStyle* style = traverser.CreateInlineStyleIfNeeded(*last_closed_);
     traverser.WrapWithNode(To<ContainerNode>(*last_closed_), style);
   }
diff --git a/third_party/blink/renderer/core/events/error_event.idl b/third_party/blink/renderer/core/events/error_event.idl
index d3e4362..cacba41 100644
--- a/third_party/blink/renderer/core/events/error_event.idl
+++ b/third_party/blink/renderer/core/events/error_event.idl
@@ -31,7 +31,7 @@
 // https://html.spec.whatwg.org/C/#the-errorevent-interface
 
 [
-    Exposed=(Window,Worker)
+    Exposed=(Window,Worker,ShadowRealm) // TODO(crbug.com/41480387): This should be Exposed=*
 ] interface ErrorEvent : Event {
     [CallWith=ScriptState] constructor(DOMString type, optional ErrorEventInit eventInitDict = {});
     readonly attribute DOMString message;
diff --git a/third_party/blink/renderer/core/events/promise_rejection_event.idl b/third_party/blink/renderer/core/events/promise_rejection_event.idl
index bd64040d..2885d196 100644
--- a/third_party/blink/renderer/core/events/promise_rejection_event.idl
+++ b/third_party/blink/renderer/core/events/promise_rejection_event.idl
@@ -5,7 +5,7 @@
 // https://html.spec.whatwg.org/C/#promiserejectionevent
 
 [
-    Exposed=(Window,Worker)
+    Exposed=(Window,Worker,ShadowRealm) // TODO(crbug.com/41480387): This should be Exposed=*
 ] interface PromiseRejectionEvent : Event {
     [CallWith=ScriptState] constructor(DOMString type, PromiseRejectionEventInit eventInitDict);
     [CallWith=ScriptState] readonly attribute Promise<any> promise;
diff --git a/third_party/blink/renderer/core/fetch/fetch_request_data.cc b/third_party/blink/renderer/core/fetch/fetch_request_data.cc
index 8e0104c..79d6efd5 100644
--- a/third_party/blink/renderer/core/fetch/fetch_request_data.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_request_data.cc
@@ -196,11 +196,6 @@
     request->SetWindowId(fetch_api_request->fetch_window_id.value());
 
   if (fetch_api_request->trust_token_params) {
-    if (script_state) {
-      // script state might be null for some tests
-      DCHECK(RuntimeEnabledFeatures::PrivateStateTokensEnabled(
-          ExecutionContext::From(script_state)));
-    }
     std::optional<network::mojom::blink::TrustTokenParams> trust_token_params =
         std::move(*(fetch_api_request->trust_token_params->Clone().get()));
     request->SetTrustTokenParams(trust_token_params);
diff --git a/third_party/blink/renderer/core/frame/build.gni b/third_party/blink/renderer/core/frame/build.gni
index 43da1ba..b94981da 100644
--- a/third_party/blink/renderer/core/frame/build.gni
+++ b/third_party/blink/renderer/core/frame/build.gni
@@ -91,6 +91,8 @@
   "frame_view.h",
   "frame_view_auto_size_info.cc",
   "frame_view_auto_size_info.h",
+  "frame_visibility_observer.cc",
+  "frame_visibility_observer.h",
   "fullscreen_controller.cc",
   "fullscreen_controller.h",
   "history.cc",
diff --git a/third_party/blink/renderer/core/frame/frame_visibility_observer.cc b/third_party/blink/renderer/core/frame/frame_visibility_observer.cc
new file mode 100644
index 0000000..303966b
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/frame_visibility_observer.cc
@@ -0,0 +1,15 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/frame/frame_visibility_observer.h"
+
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+
+namespace blink {
+
+FrameVisibilityObserver::FrameVisibilityObserver(LocalFrame* frame) {
+  frame->GetFrameVisibilityObserverSet().insert(this);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/frame_visibility_observer.h b/third_party/blink/renderer/core/frame/frame_visibility_observer.h
new file mode 100644
index 0000000..8c53e25
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/frame_visibility_observer.h
@@ -0,0 +1,30 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_VISIBILITY_OBSERVER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_VISIBILITY_OBSERVER_H_
+
+#include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+
+namespace blink {
+
+class LocalFrame;
+
+// This is an observer to observe changes to the in-viewport visibility of a
+// given frame.
+class CORE_EXPORT FrameVisibilityObserver : public GarbageCollectedMixin {
+ public:
+  virtual ~FrameVisibilityObserver() = default;
+
+  virtual void FrameVisibilityChanged(mojom::blink::FrameVisibility) = 0;
+
+ protected:
+  explicit FrameVisibilityObserver(LocalFrame*);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_VISIBILITY_OBSERVER_H_
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 53ed7eae..30b4225 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -214,6 +214,7 @@
 #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
 #include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_properties.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
@@ -528,6 +529,7 @@
   visitor->Trace(lcpp_);
   visitor->Trace(v8_local_compile_hints_producer_);
   visitor->Trace(browser_interface_broker_proxy_);
+  visitor->Trace(frame_visibility_observers_);
 #if !BUILDFLAG(IS_ANDROID)
   visitor->Trace(window_controls_overlay_changed_delegate_);
 #endif
@@ -796,6 +798,8 @@
   if (text_fragment_handler_)
     text_fragment_handler_->DidDetachDocumentOrFrame();
 
+  frame_visibility_observers_.clear();
+
   not_restored_reasons_.reset();
 
   DCHECK(!view_->IsAttached());
@@ -4163,4 +4167,18 @@
   std::move(callback).Run(is_allowed);
 }
 
+void LocalFrame::NotifyFrameVisibilityChanged(
+    mojom::blink::FrameVisibility visibility) {
+  HeapVector<Member<FrameVisibilityObserver>>
+      frame_visibility_observers_as_vector;
+  // Iterate on a copy of the vector to avoid invalidating the iterator if
+  // `FrameVisibilityChanged` happens to remove the observer from
+  // `frame_visibility_observers_`.
+  CopyToVector(frame_visibility_observers_,
+               frame_visibility_observers_as_vector);
+  for (auto observer : frame_visibility_observers_as_vector) {
+    observer->FrameVisibilityChanged(visibility);
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index fb7996c..af3627c 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -79,6 +79,7 @@
 #include "third_party/blink/renderer/core/frame/ad_script_identifier.h"
 #include "third_party/blink/renderer/core/frame/frame.h"
 #include "third_party/blink/renderer/core/frame/frame_types.h"
+#include "third_party/blink/renderer/core/frame/frame_visibility_observer.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/loader/back_forward_cache_loader_helper_impl.h"
 #include "third_party/blink/renderer/core/loader/frame_loader.h"
@@ -961,6 +962,13 @@
   bool AllowStorageAccessSyncAndNotify(
       blink::WebContentSettingsClient::StorageType storage_type);
 
+  void NotifyFrameVisibilityChanged(mojom::blink::FrameVisibility visibility);
+
+  HeapHashSet<WeakMember<FrameVisibilityObserver>>&
+  GetFrameVisibilityObserverSet() {
+    return frame_visibility_observers_;
+  }
+
  private:
   friend class FrameNavigationDisabler;
   // LocalFrameMojoHandler is a part of LocalFrame.
@@ -1234,6 +1242,8 @@
   bool is_link_preivew_triggerer_initialized_ = false;
   std::unique_ptr<WebLinkPreviewTriggerer> link_preview_triggerer_;
 
+  HeapHashSet<WeakMember<FrameVisibilityObserver>> frame_visibility_observers_;
+
   void OnStorageAccessCallback(base::OnceCallback<void(bool)> callback,
                                mojom::blink::StorageTypeAccessed storage_type,
                                bool isAllowed);
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index a719ef5..a177acf 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -2326,7 +2326,7 @@
     // RunPostLayoutIntersectionObserverSteps will return true if any
     // observations led to content-visibility intersection changing visibility
     // state synchronously (which happens on the first intersection
-    // observeration of a context).
+    // observation of a context).
     //
     // Note that we run the content-visibility intersection observation first.
     // The idea is that we want to synchronously determine the initial,
@@ -4376,6 +4376,8 @@
     frame_->Client()->GetWebFrame()->Client()->OnFrameVisibilityChanged(
         visibility);
   }
+
+  frame_->NotifyFrameVisibilityChanged(visibility);
 }
 
 void LocalFrameView::RenderThrottlingStatusChanged() {
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
index 06ab196..01c0086 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
@@ -180,9 +180,7 @@
 
   virtual SkColorInfo CanvasRenderingContextSkColorInfo() const = 0;
   virtual SkAlphaType GetAlphaType() const = 0;
-  SkColorType GetSkColorType() const {
-    return CanvasRenderingContextSkColorInfo().colorType();
-  }
+  virtual SkColorType GetSkColorType() const = 0;
   virtual sk_sp<SkColorSpace> GetSkColorSpace() const = 0;
 
   virtual scoped_refptr<StaticBitmapImage> GetImage(FlushReason) = 0;
diff --git a/third_party/blink/renderer/core/html/html_script_element.cc b/third_party/blink/renderer/core/html/html_script_element.cc
index 9e04983..e47cf6e 100644
--- a/third_party/blink/renderer/core/html/html_script_element.cc
+++ b/third_party/blink/renderer/core/html/html_script_element.cc
@@ -38,6 +38,7 @@
 #include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/core/html_names.h"
 #include "third_party/blink/renderer/core/loader/render_blocking_resource_manager.h"
+#include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/core/script/script_loader.h"
 #include "third_party/blink/renderer/core/script/script_runner.h"
 #include "third_party/blink/renderer/core/script_type_names.h"
@@ -54,7 +55,11 @@
     : HTMLElement(html_names::kScriptTag, document),
       children_changed_by_api_(false),
       blocking_attribute_(MakeGarbageCollected<BlockingAttribute>(this)),
-      loader_(InitializeScriptLoader(flags)) {}
+      loader_(InitializeScriptLoader(flags)) {
+  if (!flags.IsCreatedByParser()) {
+    async_task_context_.Schedule(document.GetExecutionContext(), localName());
+  }
+}
 
 const AttrNameToTrustedType& HTMLScriptElement::GetCheckedAttributeTypes()
     const {
@@ -335,10 +340,12 @@
 }
 
 void HTMLScriptElement::DispatchLoadEvent() {
+  probe::AsyncTask async_task(GetExecutionContext(), &async_task_context_);
   DispatchEvent(*Event::Create(event_type_names::kLoad));
 }
 
 void HTMLScriptElement::DispatchErrorEvent() {
+  probe::AsyncTask async_task(GetExecutionContext(), &async_task_context_);
   DispatchEvent(*Event::Create(event_type_names::kError));
 }
 
diff --git a/third_party/blink/renderer/core/html/html_script_element.h b/third_party/blink/renderer/core/html/html_script_element.h
index 8f6fedc6..e11ef446 100644
--- a/third_party/blink/renderer/core/html/html_script_element.h
+++ b/third_party/blink/renderer/core/html/html_script_element.h
@@ -29,6 +29,7 @@
 #include "third_party/blink/renderer/core/dom/create_element_flags.h"
 #include "third_party/blink/renderer/core/html/blocking_attribute.h"
 #include "third_party/blink/renderer/core/html/html_element.h"
+#include "third_party/blink/renderer/core/probe/async_task_context.h"
 #include "third_party/blink/renderer/core/script/script_element_base.h"
 #include "third_party/blink/renderer/core/script/script_loader.h"
 #include "third_party/blink/renderer/platform/bindings/parkable_string.h"
@@ -131,6 +132,8 @@
 
   Member<BlockingAttribute> blocking_attribute_;
   Member<ScriptLoader> loader_;
+
+  probe::AsyncTaskContext async_task_context_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/anchor_evaluator_impl.cc b/third_party/blink/renderer/core/layout/anchor_evaluator_impl.cc
index 87287c9..35892ce8 100644
--- a/third_party/blink/renderer/core/layout/anchor_evaluator_impl.cc
+++ b/third_party/blink/renderer/core/layout/anchor_evaluator_impl.cc
@@ -310,7 +310,12 @@
     const PhysicalOffset& offset_to_padding_box,
     bool is_y_axis,
     bool is_right_or_bottom) const {
-  const PhysicalRect anchor = container_converter.ToPhysical(reference.rect);
+  PhysicalRect anchor_rect = container_converter.ToPhysical(reference.rect);
+  // Make the offset relative to the padding box, because the containing block
+  // is formed by the padding edge.
+  // https://www.w3.org/TR/CSS21/visudet.html#containing-block-details
+  anchor_rect.offset -= offset_to_padding_box;
+
   anchor_value = PhysicalAnchorValueFromLogicalOrAuto(
       anchor_value, container_converter.GetWritingDirection(),
       self_writing_direction, is_y_axis);
@@ -319,54 +324,45 @@
   LayoutUnit value;
   switch (anchor_value) {
     case CSSAnchorValue::kCenter: {
-      const LayoutUnit start = is_y_axis
-                                   ? anchor.Y() - offset_to_padding_box.top
-                                   : anchor.X() - offset_to_padding_box.left;
-      const LayoutUnit end = is_y_axis
-                                 ? anchor.Bottom() - offset_to_padding_box.top
-                                 : anchor.Right() - offset_to_padding_box.left;
+      const LayoutUnit start = is_y_axis ? anchor_rect.Y() : anchor_rect.X();
+      const LayoutUnit end =
+          is_y_axis ? anchor_rect.Bottom() : anchor_rect.Right();
       value = start + LayoutUnit::FromFloatRound((end - start) * 0.5);
       break;
     }
     case CSSAnchorValue::kLeft:
       if (is_y_axis)
         return std::nullopt;  // Wrong axis.
-      // Make the offset relative to the padding box, because the containing
-      // block is formed by the padding edge.
-      // https://www.w3.org/TR/CSS21/visudet.html#containing-block-details
-      value = anchor.X() - offset_to_padding_box.left;
+      value = anchor_rect.X();
       break;
     case CSSAnchorValue::kRight:
       if (is_y_axis)
         return std::nullopt;  // Wrong axis.
-      // See |CSSAnchorValue::kLeft|.
-      value = anchor.Right() - offset_to_padding_box.left;
+      value = anchor_rect.Right();
       break;
     case CSSAnchorValue::kTop:
       if (!is_y_axis)
         return std::nullopt;  // Wrong axis.
-      // See |CSSAnchorValue::kLeft|.
-      value = anchor.Y() - offset_to_padding_box.top;
+      value = anchor_rect.Y();
       break;
     case CSSAnchorValue::kBottom:
       if (!is_y_axis)
         return std::nullopt;  // Wrong axis.
-      // See |CSSAnchorValue::kLeft|.
-      value = anchor.Bottom() - offset_to_padding_box.top;
+      value = anchor_rect.Bottom();
       break;
     case CSSAnchorValue::kPercentage: {
       LayoutUnit size;
       if (is_y_axis) {
-        value = anchor.Y() - offset_to_padding_box.top;
-        size = anchor.Height();
+        value = anchor_rect.Y();
+        size = anchor_rect.Height();
         // The percentage is logical, between the `start` and `end` sides.
         // Convert to the physical percentage.
         // https://drafts.csswg.org/css-anchor-1/#anchor-pos
         if (container_converter.GetWritingDirection().IsFlippedY())
           percentage = 100 - percentage;
       } else {
-        value = anchor.X() - offset_to_padding_box.left;
-        size = anchor.Width();
+        value = anchor_rect.X();
+        size = anchor_rect.Width();
         // Convert the logical percentage to physical. See above.
         if (container_converter.GetWritingDirection().IsFlippedX())
           percentage = 100 - percentage;
diff --git a/third_party/blink/renderer/core/layout/box_fragment_builder.h b/third_party/blink/renderer/core/layout/box_fragment_builder.h
index d1ab545..d530700 100644
--- a/third_party/blink/renderer/core/layout/box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/box_fragment_builder.h
@@ -16,6 +16,7 @@
 #include "third_party/blink/renderer/core/layout/flex/devtools_flex_info.h"
 #include "third_party/blink/renderer/core/layout/fragment_builder.h"
 #include "third_party/blink/renderer/core/layout/frame_set_layout_data.h"
+#include "third_party/blink/renderer/core/layout/gap_fragment_data.h"
 #include "third_party/blink/renderer/core/layout/geometry/box_sides.h"
 #include "third_party/blink/renderer/core/layout/geometry/box_strut.h"
 #include "third_party/blink/renderer/core/layout/geometry/fragment_geometry.h"
@@ -574,6 +575,11 @@
     use_last_baseline_for_inline_baseline_ = true;
   }
 
+  void SetGapGeometry(
+      std::unique_ptr<GapFragmentData::GapGeometry> gap_geometry) {
+    gap_geometry_ = std::move(gap_geometry);
+  }
+
   void SetTableGridRect(const LogicalRect& table_grid_rect) {
     table_grid_rect_ = table_grid_rect;
   }
@@ -750,6 +756,8 @@
   std::optional<LayoutUnit> last_baseline_;
   LayoutUnit math_italic_correction_;
 
+  std::unique_ptr<GapFragmentData::GapGeometry> gap_geometry_;
+
   // Table specific types.
   std::optional<LogicalRect> table_grid_rect_;
   TableFragmentData::ColumnGeometries table_column_geometries_;
diff --git a/third_party/blink/renderer/core/layout/build.gni b/third_party/blink/renderer/core/layout/build.gni
index d40038d..e73db76 100644
--- a/third_party/blink/renderer/core/layout/build.gni
+++ b/third_party/blink/renderer/core/layout/build.gni
@@ -150,6 +150,7 @@
   "frame_set_layout_algorithm.cc",
   "frame_set_layout_algorithm.h",
   "frame_set_layout_data.h",
+  "gap_fragment_data.h",
   "generated_children.h",
   "geometry/axis.h",
   "geometry/bfc_offset.cc",
diff --git a/third_party/blink/renderer/core/layout/exclusions/exclusion_area.cc b/third_party/blink/renderer/core/layout/exclusions/exclusion_area.cc
index 3feafc1d..c6ef93ec 100644
--- a/third_party/blink/renderer/core/layout/exclusions/exclusion_area.cc
+++ b/third_party/blink/renderer/core/layout/exclusions/exclusion_area.cc
@@ -26,14 +26,13 @@
 };
 
 std::ostream& operator<<(std::ostream& os, const PrintableEFloat& printable) {
-  const char* kStrings[] = {
+  std::array<const char*, 5> kStrings = {
       "kNone", "kLeft", "kRight", "kInlineStart", "kInlineEnd",
   };
   const unsigned index = static_cast<unsigned>(printable.value);
   if (index >= std::size(kStrings))
     return os << "EFloat::" << index;
-  // TODO(crbug.com/351564777): Resolve a buffer safety issue.
-  return os << "EFloat::" << UNSAFE_TODO(kStrings[index]);
+  return os << "EFloat::" << kStrings[index];
 }
 
 struct PrintableKind {
@@ -42,15 +41,14 @@
 };
 
 std::ostream& operator<<(std::ostream& os, const PrintableKind& printable) {
-  const char* kStrings[] = {
+  std::array<const char*, 2> kStrings = {
       "kFloat",
       "kInitialLetterBox",
   };
   const unsigned index = static_cast<unsigned>(printable.value);
   if (index >= std::size(kStrings))
     return os << "Kind::" << index;
-  // TODO(crbug.com/351564777): Resolve a buffer safety issue.
-  return os << UNSAFE_TODO(kStrings[index]);
+  return os << kStrings[index];
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/core/layout/flex/flexible_box_algorithm.cc b/third_party/blink/renderer/core/layout/flex/flexible_box_algorithm.cc
index 14a69f14..c695b35 100644
--- a/third_party/blink/renderer/core/layout/flex/flexible_box_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/flex/flexible_box_algorithm.cc
@@ -117,31 +117,27 @@
   } else {
     position =
         style.ResolvedJustifyContentPosition(ContentAlignmentNormalBehavior());
-  }
-  if (position == ContentPosition::kLeft ||
-      position == ContentPosition::kRight) {
-    if (IsColumnFlow(style)) {
-      if (style.IsHorizontalWritingMode()) {
-        // Main axis is perpendicular to both the physical left<->right and
-        // inline start<->end axes, so kLeft and kRight behave as kStart.
-        position = ContentPosition::kStart;
-      } else if ((position == ContentPosition::kLeft &&
-                  style.IsFlippedBlocksWritingMode()) ||
-                 (position == ContentPosition::kRight &&
-                  style.GetWritingDirection().BlockEnd() ==
-                      PhysicalDirection::kRight)) {
-        position = ContentPosition::kEnd;
+
+    const auto writing_direction = style.GetWritingDirection();
+    if (position == ContentPosition::kLeft ||
+        position == ContentPosition::kRight) {
+      if (IsColumnFlow(style)) {
+        if (writing_direction.IsHorizontal()) {
+          // The main-axis is in the top-down direction, fallback to start.
+          position = ContentPosition::kStart;
+        } else {
+          LogicalToPhysical physical(
+              writing_direction, ContentPosition::kStart, ContentPosition::kEnd,
+              ContentPosition::kStart, ContentPosition::kEnd);
+          position = position == ContentPosition::kLeft ? physical.Left()
+                                                        : physical.Right();
+        }
       } else {
-        position = ContentPosition::kStart;
+        position =
+            ((position == ContentPosition::kLeft) == writing_direction.IsLtr())
+                ? ContentPosition::kStart
+                : ContentPosition::kEnd;
       }
-    } else if ((position == ContentPosition::kLeft &&
-                !style.IsLeftToRightDirection()) ||
-               (position == ContentPosition::kRight &&
-                style.IsLeftToRightDirection())) {
-      DCHECK(!FlexibleBoxAlgorithm::IsColumnFlow(style));
-      position = ContentPosition::kEnd;
-    } else {
-      position = ContentPosition::kStart;
     }
   }
   DCHECK_NE(position, ContentPosition::kLeft);
@@ -197,14 +193,10 @@
     return ItemPosition::kFlexEnd;
 
   if (align == ItemPosition::kSelfStart || align == ItemPosition::kSelfEnd) {
-    LogicalToPhysical<ItemPosition> physical(
-        child_style.GetWritingDirection(), ItemPosition::kFlexStart,
-        ItemPosition::kFlexEnd, ItemPosition::kFlexStart,
-        ItemPosition::kFlexEnd);
-
-    PhysicalToLogical<ItemPosition> logical(flexbox_style.GetWritingDirection(),
-                                            physical.Top(), physical.Right(),
-                                            physical.Bottom(), physical.Left());
+    LogicalToLogical<ItemPosition> logical(
+        child_style.GetWritingDirection(), flexbox_style.GetWritingDirection(),
+        ItemPosition::kFlexStart, ItemPosition::kFlexEnd,
+        ItemPosition::kFlexStart, ItemPosition::kFlexEnd);
 
     if (flexbox_style.ResolvedIsColumnFlexDirection()) {
       return align == ItemPosition::kSelfStart ? logical.InlineStart()
diff --git a/third_party/blink/renderer/core/layout/gap_fragment_data.h b/third_party/blink/renderer/core/layout/gap_fragment_data.h
new file mode 100644
index 0000000..45efe94
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/gap_fragment_data.h
@@ -0,0 +1,64 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GAP_FRAGMENT_DATA_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GAP_FRAGMENT_DATA_H_
+
+#include <optional>
+
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
+
+namespace blink {
+
+class GapFragmentData {
+ public:
+  // GapBoundary represents the start and end offsets of a single gap.
+  // A fragment can contain the start offset, the end offset, or both,
+  // indicating the boundaries of the gap. When a grid container is fragmented,
+  // it is possible to have only the start/end offsets for a given row gap in a
+  // fragment. Example: Consider a grid container fragmented into two parts. The
+  // gap between rows might be represented as follows:
+  //
+  // Fragment 1:                     Fragment 2:
+  // +-----------------+          +-------------------+
+  // | Item 1| |Item 2 |          |                   |
+  // |       | |       |          | Gap End           |
+  // |_______| |_______|          |________   ________|
+  // | Gap Start       |          | Item 3 | | Item 4 |
+  // |                 |          |        | |        |
+  // +-----------------+          +-------------------+
+  struct GapBoundary {
+    DISALLOW_NEW();
+
+   public:
+    GapBoundary(wtf_size_t index,
+                std::optional<LayoutUnit> start_offset = std::nullopt,
+                std::optional<LayoutUnit> end_offset = std::nullopt)
+        : index(index), start_offset(start_offset), end_offset(end_offset) {}
+
+    wtf_size_t index;
+    std::optional<LayoutUnit> start_offset;
+    std::optional<LayoutUnit> end_offset;
+  };
+
+  using GapBoundaries = HeapVector<GapBoundary>;
+
+  // Gap locations are used for painting gap decorations.
+  struct GapGeometry {
+    USING_FAST_MALLOC(GapGeometry);
+
+   public:
+    GapBoundaries columns;
+    GapBoundaries rows;
+
+    void Trace(Visitor* visitor) const {
+      visitor->Trace(rows);
+      visitor->Trace(columns);
+    }
+  };
+};
+
+}  // namespace blink
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GAP_DECORATIONS_FRAGMENT_GEOMETRY_H_
diff --git a/third_party/blink/renderer/core/layout/inline/offset_mapping.cc b/third_party/blink/renderer/core/layout/inline/offset_mapping.cc
index 6c8f995..0db5a53 100644
--- a/third_party/blink/renderer/core/layout/inline/offset_mapping.cc
+++ b/third_party/blink/renderer/core/layout/inline/offset_mapping.cc
@@ -297,15 +297,15 @@
   if (range_start == range_end || units_[range_start].DOMStart() > offset)
     return nullptr;
   // Find the last unit where unit.dom_start <= offset
-  // TODO(crbug.com/351564777): Resolve a buffer safety issue.
-  auto unit = std::prev(UNSAFE_TODO(std::upper_bound(
-      units_.begin() + range_start, units_.begin() + range_end, offset,
-      [](unsigned offset, const OffsetMappingUnit& unit) {
+  auto range = base::span(units_).subspan(range_start, range_end - range_start);
+  auto i = base::ranges::upper_bound(
+      range, offset, [](unsigned offset, const OffsetMappingUnit& unit) {
         return offset < unit.DOMStart();
-      })));
+      });
+  const OffsetMappingUnit* unit = &range[std::distance(range.begin(), i) - 1];
   if (unit->DOMEnd() < offset)
     return nullptr;
-  return &*unit;
+  return unit;
 }
 
 OffsetMapping::UnitVector OffsetMapping::GetMappingUnitsForDOMRange(
@@ -328,25 +328,30 @@
     return UnitVector();
 
   // Find the first unit where unit.dom_end >= start_offset
-  // TODO(crbug.com/351564777): Resolve a buffer safety issue.
-  auto result_begin = UNSAFE_TODO(std::lower_bound(
-      units_.begin() + range_start, units_.begin() + range_end, start_offset,
-      [](const OffsetMappingUnit& unit, unsigned offset) {
-        return unit.DOMEnd() < offset;
-      }));
+  auto span1 = base::span(units_).subspan(range_start, range_end - range_start);
+  size_t result_begin =
+      range_start +
+      std::distance(span1.begin(),
+                    base::ranges::lower_bound(
+                        span1, start_offset,
+                        [](const OffsetMappingUnit& unit, unsigned offset) {
+                          return unit.DOMEnd() < offset;
+                        }));
 
   // Find the next of the last unit where unit.dom_start <= end_offset
-  // TODO(crbug.com/351564777): Resolve a buffer safety issue.
-  auto result_end = UNSAFE_TODO(
-      std::upper_bound(result_begin, units_.begin() + range_end, end_offset,
-                       [](unsigned offset, const OffsetMappingUnit& unit) {
-                         return offset < unit.DOMStart();
-                       }));
+  auto span2 =
+      base::span(units_).subspan(result_begin, range_end - result_begin);
+  size_t result_size = std::distance(
+      span2.begin(), base::ranges::upper_bound(
+                         span2, end_offset,
+                         [](unsigned offset, const OffsetMappingUnit& unit) {
+                           return offset < unit.DOMStart();
+                         }));
 
   UnitVector result;
-  result.reserve(base::checked_cast<wtf_size_t>(result_end - result_begin));
-  // TODO(crbug.com/351564777): Resolve a buffer safety issue.
-  for (const auto& unit : UNSAFE_TODO(base::span(result_begin, result_end))) {
+  result.reserve(base::checked_cast<wtf_size_t>(result_size));
+  for (const auto& unit :
+       base::span(units_).subspan(result_begin, result_size)) {
     // If the unit isn't fully within the range, create a new unit that's
     // within the range.
     const unsigned clamped_start = std::max(unit.DOMStart(), start_offset);
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 108dc1d..1e6c63c 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -2697,8 +2697,6 @@
 
 void LayoutBox::RebuildFragmentTreeSpine() {
   DCHECK(PhysicalFragmentCount());
-  SCOPED_BLINK_UMA_HISTOGRAM_TIMER_HIGHRES(
-      "Blink.Layout.RebuildFragmentTreeSpine");
   // If this box has an associated layout-result, rebuild the spine of the
   // fragment-tree to ensure consistency.
   LayoutBox* container = this;
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 846d6d45..486ac54 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -758,6 +758,17 @@
   children->RemoveChildNode(this, old_child);
 }
 
+bool LayoutObject::IsInTopOrViewTransitionLayer() const {
+  NOT_DESTROYED();
+  if (IsViewTransitionRoot()) {
+    return true;
+  }
+  if (Element* element = DynamicTo<Element>(GetNode())) {
+    return StyleRef().IsRenderedInTopLayer(*element);
+  }
+  return false;
+}
+
 void LayoutObject::NotifyPriorityScrollAnchorStatusChanged() {
   NOT_DESTROYED();
   if (!Parent())
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 40314c8..524b763e 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -732,16 +732,7 @@
   // Returns true if the LayoutObject is rendered in the top layer or the layer
   // for view transitions. Such objects are rendered as subsequent siblings of
   // the root element box and have specific stacking requirements.
-  bool IsInTopOrViewTransitionLayer() const {
-    NOT_DESTROYED();
-    if (IsViewTransitionRoot()) {
-      return true;
-    }
-    if (Element* element = DynamicTo<Element>(GetNode())) {
-      return StyleRef().IsRenderedInTopLayer(*element);
-    }
-    return false;
-  }
+  bool IsInTopOrViewTransitionLayer() const;
 
   void NotifyPriorityScrollAnchorStatusChanged();
 
diff --git a/third_party/blink/renderer/core/layout/physical_box_fragment.cc b/third_party/blink/renderer/core/layout/physical_box_fragment.cc
index f2fe692..d3b2569 100644
--- a/third_party/blink/renderer/core/layout/physical_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/physical_box_fragment.cc
@@ -334,7 +334,7 @@
       has_scrollable_overflow + !!builder->frame_set_layout_data_ +
       !!builder->mathml_paint_info_ + !!builder->table_grid_rect_ +
       !!builder->table_collapsed_borders_ +
-      !!builder->table_collapsed_borders_geometry_ +
+      !!builder->table_collapsed_borders_geometry_ + !!builder->gap_geometry_ +
       !!builder->table_cell_column_index_ +
       (builder->table_section_row_offsets_.empty() ? 0 : 2) +
       !!builder->page_name_ + !!borders + !!scrollbar + !!padding +
diff --git a/third_party/blink/renderer/core/layout/physical_box_fragment.h b/third_party/blink/renderer/core/layout/physical_box_fragment.h
index 5bc6cdfa..60ae7dfb 100644
--- a/third_party/blink/renderer/core/layout/physical_box_fragment.h
+++ b/third_party/blink/renderer/core/layout/physical_box_fragment.h
@@ -10,6 +10,7 @@
 #include "base/dcheck_is_on.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/block_break_token.h"
+#include "third_party/blink/renderer/core/layout/gap_fragment_data.h"
 #include "third_party/blink/renderer/core/layout/geometry/box_sides.h"
 #include "third_party/blink/renderer/core/layout/geometry/box_strut.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
@@ -171,6 +172,13 @@
            !Style().ShouldIgnoreOverflowPropertyForInlineBlockBaseline();
   }
 
+  const GapFragmentData::GapGeometry* GapGeometry() const {
+    if (const auto* field = GetRareField(FieldId::kGapGeometry)) {
+      return field->gap_geometry.get();
+    }
+    return nullptr;
+  }
+
   LogicalRect TableGridRect() const {
     return rare_data_->GetField(FieldId::kTableGridRect)->table_grid_rect;
   }
diff --git a/third_party/blink/renderer/core/layout/physical_fragment_rare_data.cc b/third_party/blink/renderer/core/layout/physical_fragment_rare_data.cc
index ac215f8..11297f4a 100644
--- a/third_party/blink/renderer/core/layout/physical_fragment_rare_data.cc
+++ b/third_party/blink/renderer/core/layout/physical_fragment_rare_data.cc
@@ -53,6 +53,10 @@
     SetField(FieldId::kFrameSetLayoutData).frame_set_layout_data =
         std::move(builder.frame_set_layout_data_);
   }
+  if (builder.gap_geometry_) {
+    SetField(FieldId::kGapGeometry).gap_geometry =
+        std::move(builder.gap_geometry_);
+  }
   if (builder.table_grid_rect_) {
     SetField(FieldId::kTableGridRect).table_grid_rect =
         *builder.table_grid_rect_;
@@ -112,6 +116,7 @@
   SET_IF_EXISTS(kPadding, padding, other);
   SET_IF_EXISTS(kInflowBounds, inflow_bounds, other);
   CLONE_IF_EXISTS(kFrameSetLayoutData, frame_set_layout_data, other);
+  CLONE_IF_EXISTS(kGapGeometry, gap_geometry, other);
   SET_IF_EXISTS(kTableGridRect, table_grid_rect, other);
   CLONE_IF_EXISTS(kTableCollapsedBordersGeometry,
                   table_collapsed_borders_geometry, other);
@@ -147,6 +152,7 @@
     FUNC(kTableSectionRowOffsets, table_section_row_offsets);               \
     FUNC(kPageName, page_name);                                             \
     FUNC(kMargins, margins);                                                \
+    FUNC(kGapGeometry, gap_geometry);                                       \
   }
 
 #define CONSTRUCT_UNION_MEMBER(id, name) \
diff --git a/third_party/blink/renderer/core/layout/physical_fragment_rare_data.h b/third_party/blink/renderer/core/layout/physical_fragment_rare_data.h
index e73c984..adae6cd3 100644
--- a/third_party/blink/renderer/core/layout/physical_fragment_rare_data.h
+++ b/third_party/blink/renderer/core/layout/physical_fragment_rare_data.h
@@ -7,6 +7,7 @@
 
 #include <climits>
 
+#include "third_party/blink/renderer/core/layout/gap_fragment_data.h"
 #include "third_party/blink/renderer/core/layout/geometry/logical_rect.h"
 #include "third_party/blink/renderer/core/layout/table/table_fragment_data.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
@@ -73,8 +74,9 @@
     kTableSectionRowOffsets,
     kPageName,
     kMargins,
+    kGapGeometry,
 
-    kMaxValue = kMargins,
+    kMaxValue = kGapGeometry,
   };
   static_assert(sizeof(RareBitFieldType) * CHAR_BIT >
                     static_cast<unsigned>(FieldId::kMaxValue),
@@ -92,6 +94,7 @@
       scoped_refptr<const TableBorders> table_collapsed_borders;
       std::unique_ptr<TableFragmentData::CollapsedBordersGeometry>
           table_collapsed_borders_geometry;
+      std::unique_ptr<GapFragmentData::GapGeometry> gap_geometry;
       wtf_size_t table_cell_column_index;
       wtf_size_t table_section_start_row_index;
       Vector<LayoutUnit> table_section_row_offsets;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc
index fe74f9c..3b7a5fc 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc
@@ -91,13 +91,17 @@
 
 gfx::RectF LayoutSVGInline::ObjectBoundingBox() const {
   NOT_DESTROYED();
-  gfx::RectF bounds;
-  if (IsInLayoutNGInlineFormattingContext()) {
-    InlineCursor cursor;
-    cursor.MoveToIncludingCulledInline(*this);
-    ObjectBoundingBoxForCursor(cursor, bounds);
+  if (!RuntimeEnabledFeatures::SvgTspanBboxCacheEnabled() ||
+      needs_update_bounding_box_) {
+    needs_update_bounding_box_ = false;
+    bounding_box_ = gfx::RectF();
+    if (IsInLayoutNGInlineFormattingContext()) {
+      InlineCursor cursor;
+      cursor.MoveToIncludingCulledInline(*this);
+      ObjectBoundingBoxForCursor(cursor, bounding_box_);
+    }
   }
-  return bounds;
+  return bounding_box_;
 }
 
 gfx::RectF LayoutSVGInline::DecoratedBoundingBox() const {
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_inline.h b/third_party/blink/renderer/core/layout/svg/layout_svg_inline.h
index 69eb19a0..827a10c 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_inline.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_inline.h
@@ -65,6 +65,11 @@
                        const PhysicalOffset& additional_offset,
                        OutlineType) const final;
 
+  void InvalidateObjectBoundingBox() {
+    NOT_DESTROYED();
+    needs_update_bounding_box_ = true;
+  }
+
  private:
   void WillBeDestroyed() final;
   void StyleDidChange(StyleDifference, const ComputedStyle* old_style) final;
@@ -76,10 +81,18 @@
   void InsertedIntoTree() override;
   void WillBeRemovedFromTree() override;
 
+  // Return true if this can have an object bounding box.
+  // bounding_box_ can be dirty even if this flag is true.
   bool IsObjectBoundingBoxValid() const;
 
   static void ObjectBoundingBoxForCursor(InlineCursor& cursor,
                                          gfx::RectF& bounds);
+
+  // `bounding_box_` and `needs_update_bounding_box_` are mutable for
+  // on-demand computation of bounding_box_.
+  mutable gfx::RectF bounding_box_;
+  // True if we need to update bounding_box_.
+  mutable bool needs_update_bounding_box_ = true;
 };
 
 template <>
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
index 31d741e4..151c2db 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/layout/constraint_space_builder.h"
 #include "third_party/blink/renderer/core/layout/inline/fragment_item.h"
 #include "third_party/blink/renderer/core/layout/physical_box_fragment.h"
+#include "third_party/blink/renderer/core/layout/svg/layout_svg_inline.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
@@ -245,6 +246,9 @@
   BlockNode(this).Layout(builder.ToConstraintSpace());
 
   needs_update_bounding_box_ = true;
+  if (RuntimeEnabledFeatures::SvgTspanBboxCacheEnabled()) {
+    InvalidateDescendantObjectBoundingBoxes();
+  }
 
   const gfx::RectF boundaries = ObjectBoundingBox();
   const bool bounds_changed = old_boundaries != boundaries;
@@ -406,6 +410,16 @@
   return needs_text_metrics_update_;
 }
 
+void LayoutSVGText::InvalidateDescendantObjectBoundingBoxes() {
+  NOT_DESTROYED();
+  for (LayoutObject* object = NextInPreOrder(this); object;
+       object = object->NextInPreOrder(this)) {
+    if (auto* svg_inline = DynamicTo<LayoutSVGInline>(object)) {
+      svg_inline->InvalidateObjectBoundingBox();
+    }
+  }
+}
+
 LayoutSVGText* LayoutSVGText::LocateLayoutSVGTextAncestor(LayoutObject* start) {
   return const_cast<LayoutSVGText*>(FindTextRoot(start));
 }
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_text.h b/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
index be05650b..8143fc6f 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
@@ -74,6 +74,7 @@
 
   void UpdateFont();
   void UpdateTransformAffectsVectorEffect();
+  void InvalidateDescendantObjectBoundingBoxes();
 
   // bounding_box_* are mutable for on-demand computation in a const method.
   mutable gfx::RectF bounding_box_;
diff --git a/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc b/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc
index 852814c9..69c5eb36 100644
--- a/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc
+++ b/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc
@@ -506,9 +506,6 @@
   if (trial_name == "AdInterestGroupAPI")
     return base::FeatureList::IsEnabled(features::kInterestGroupStorage);
 
-  if (trial_name == "TrustTokens")
-    return base::FeatureList::IsEnabled(network::features::kFledgePst);
-
   if (trial_name == "SpeculationRulesPrefetchFuture") {
     return base::FeatureList::IsEnabled(
         features::kSpeculationRulesPrefetchFuture);
diff --git a/third_party/blink/renderer/core/page/focus_controller.cc b/third_party/blink/renderer/core/page/focus_controller.cc
index 924f171..38f4356 100644
--- a/third_party/blink/renderer/core/page/focus_controller.cc
+++ b/third_party/blink/renderer/core/page/focus_controller.cc
@@ -1782,12 +1782,12 @@
   return true;
 }
 
-Element* FocusController::FindFocusableElement(mojom::blink::FocusType type,
-                                               Element& element,
-                                               OwnerMap& owner_map) {
-  // FIXME: No spacial navigation code yet.
-  DCHECK(type == mojom::blink::FocusType::kForward ||
-         type == mojom::blink::FocusType::kBackward);
+Element* FocusController::FindFocusableElementForImeAutofillAndTesting(
+    mojom::blink::FocusType type,
+    Element& element,
+    OwnerMap& owner_map) {
+  CHECK(type == mojom::blink::FocusType::kForward ||
+        type == mojom::blink::FocusType::kBackward);
   ScopedFocusNavigation scope =
       ScopedFocusNavigation::CreateFor(element, owner_map);
   return FindFocusableElementAcrossFocusScopes(type, scope, owner_map);
@@ -1795,7 +1795,7 @@
 
 Element* FocusController::NextFocusableElementForImeAndAutofill(
     Element* element,
-    mojom::blink::FocusType focus_type) {
+    const mojom::blink::FocusType focus_type) {
   // TODO(ajith.v) Due to crbug.com/781026 when next/previous element is far
   // from current element in terms of tabindex, then it's signalling CPU load.
   // Will investigate further for a proper solution later.
@@ -1816,11 +1816,12 @@
     form_owner = form_control_element->formOwner();
 
   OwnerMap owner_map;
-  Element* next_element = FindFocusableElement(focus_type, *element, owner_map);
+  Element* next_element = FindFocusableElementForImeAutofillAndTesting(
+      focus_type, *element, owner_map);
   int traversal = 0;
   for (; next_element && traversal < kFocusTraversalThreshold;
-       next_element =
-           FindFocusableElement(focus_type, *next_element, owner_map),
+       next_element = FindFocusableElementForImeAutofillAndTesting(
+           focus_type, *next_element, owner_map),
        ++traversal) {
     auto* next_html_element = DynamicTo<HTMLElement>(next_element);
     if (!next_html_element)
@@ -1913,18 +1914,6 @@
   return nullptr;
 }
 
-Element* FocusController::FindFocusableElementAfter(
-    Element& element,
-    mojom::blink::FocusType type) {
-  if (type != mojom::blink::FocusType::kForward &&
-      type != mojom::blink::FocusType::kBackward)
-    return nullptr;
-  element.GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kFocus);
-
-  OwnerMap owner_map;
-  return FindFocusableElement(type, element, owner_map);
-}
-
 static bool RelinquishesEditingFocus(const Element& element) {
   DCHECK(IsEditable(element));
   return element.GetDocument().GetFrame() && RootEditableElement(element);
diff --git a/third_party/blink/renderer/core/page/focus_controller.h b/third_party/blink/renderer/core/page/focus_controller.h
index 7ee1ac1..65f9d74 100644
--- a/third_party/blink/renderer/core/page/focus_controller.h
+++ b/third_party/blink/renderer/core/page/focus_controller.h
@@ -98,7 +98,9 @@
   // next focusable element.
   Element* NextFocusableElementForImeAndAutofill(Element*,
                                                  mojom::blink::FocusType);
-  Element* FindFocusableElementAfter(Element& element, mojom::blink::FocusType);
+  Element* FindFocusableElementForImeAutofillAndTesting(mojom::blink::FocusType,
+                                                        Element&,
+                                                        OwnerMap&);
 
   bool SetFocusedElement(Element*, Frame*, const FocusParams&);
   // |setFocusedElement| variant with SelectionBehaviorOnFocus::None,
@@ -120,8 +122,6 @@
   void Trace(Visitor*) const;
 
  private:
-  Element* FindFocusableElement(mojom::blink::FocusType, Element&, OwnerMap&);
-
   bool AdvanceFocus(mojom::blink::FocusType,
                     bool initial_focus,
                     InputDeviceCapabilities* source_capabilities = nullptr);
diff --git a/third_party/blink/renderer/core/page/focus_controller_test.cc b/third_party/blink/renderer/core/page/focus_controller_test.cc
index 5ef7908..d26e5de5 100644
--- a/third_party/blink/renderer/core/page/focus_controller_test.cc
+++ b/third_party/blink/renderer/core/page/focus_controller_test.cc
@@ -22,6 +22,19 @@
 namespace blink {
 
 class FocusControllerTest : public PageTestBase {
+ public:
+  Element* FindFocusableElementAfter(Element& element,
+                                     mojom::blink::FocusType type) {
+    if (type != mojom::blink::FocusType::kForward &&
+        type != mojom::blink::FocusType::kBackward) {
+      return nullptr;
+    }
+    element.GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kFocus);
+    FocusController::OwnerMap owner_map;
+    return GetFocusController().FindFocusableElementForImeAutofillAndTesting(
+        type, element, owner_map);
+  }
+
  private:
   void SetUp() override { PageTestBase::SetUp(gfx::Size()); }
 };
@@ -121,26 +134,26 @@
   Element* second = GetElementById("second");
   Element* third = GetElementById("third");
   Element* fourth = GetElementById("fourth");
-  EXPECT_EQ(third, GetFocusController().FindFocusableElementAfter(
+  EXPECT_EQ(third, FindFocusableElementAfter(
                        *first, mojom::blink::FocusType::kForward));
-  EXPECT_EQ(third, GetFocusController().FindFocusableElementAfter(
+  EXPECT_EQ(third, FindFocusableElementAfter(
                        *second, mojom::blink::FocusType::kForward));
-  EXPECT_EQ(fourth, GetFocusController().FindFocusableElementAfter(
+  EXPECT_EQ(fourth, FindFocusableElementAfter(
                         *third, mojom::blink::FocusType::kForward));
-  EXPECT_EQ(nullptr, GetFocusController().FindFocusableElementAfter(
+  EXPECT_EQ(nullptr, FindFocusableElementAfter(
                          *fourth, mojom::blink::FocusType::kForward));
 
-  EXPECT_EQ(nullptr, GetFocusController().FindFocusableElementAfter(
+  EXPECT_EQ(nullptr, FindFocusableElementAfter(
                          *first, mojom::blink::FocusType::kBackward));
-  EXPECT_EQ(first, GetFocusController().FindFocusableElementAfter(
+  EXPECT_EQ(first, FindFocusableElementAfter(
                        *second, mojom::blink::FocusType::kBackward));
-  EXPECT_EQ(first, GetFocusController().FindFocusableElementAfter(
+  EXPECT_EQ(first, FindFocusableElementAfter(
                        *third, mojom::blink::FocusType::kBackward));
-  EXPECT_EQ(third, GetFocusController().FindFocusableElementAfter(
+  EXPECT_EQ(third, FindFocusableElementAfter(
                        *fourth, mojom::blink::FocusType::kBackward));
 
-  EXPECT_EQ(nullptr, GetFocusController().FindFocusableElementAfter(
-                         *first, mojom::blink::FocusType::kNone));
+  EXPECT_EQ(nullptr,
+            FindFocusableElementAfter(*first, mojom::blink::FocusType::kNone));
 }
 
 TEST_F(FocusControllerTest, NextFocusableElementForImeAndAutofill) {
@@ -486,11 +499,11 @@
                                     post_input};
 
   for (std::size_t i = 0u; i < order.size() - 1; ++i) {
-    EXPECT_EQ(order[i + 1], GetFocusController().FindFocusableElementAfter(
+    EXPECT_EQ(order[i + 1], FindFocusableElementAfter(
                                 *order[i], mojom::blink::FocusType::kForward));
   }
   for (std::size_t i = 0u; i < order.size() - 1; ++i) {
-    EXPECT_EQ(order[i], GetFocusController().FindFocusableElementAfter(
+    EXPECT_EQ(order[i], FindFocusableElementAfter(
                             *order[i + 1], mojom::blink::FocusType::kBackward));
   }
 
@@ -502,14 +515,12 @@
   const auto* style = before_second_scroll_marker->GetComputedStyle();
   EXPECT_TRUE(before_second_scroll_marker->IsFocused());
   EXPECT_EQ(0.5, style->Opacity());
-  EXPECT_EQ(
-      before_second_scroll_marker,
-      GetFocusController().FindFocusableElementAfter(
-          *before_scroll_marker_group, mojom::blink::FocusType::kForward));
-  EXPECT_EQ(
-      before_block_start_button,
-      GetFocusController().FindFocusableElementAfter(
-          *before_second_scroll_marker, mojom::blink::FocusType::kForward));
+  EXPECT_EQ(before_second_scroll_marker,
+            FindFocusableElementAfter(*before_scroll_marker_group,
+                                      mojom::blink::FocusType::kForward));
+  EXPECT_EQ(before_block_start_button,
+            FindFocusableElementAfter(*before_second_scroll_marker,
+                                      mojom::blink::FocusType::kForward));
 }
 
 TEST_F(FocusControllerTest, CarouselWithOnlyButtonsFocusOrder) {
@@ -590,11 +601,11 @@
                                     post_input};
 
   for (std::size_t i = 0u; i < order.size() - 1; ++i) {
-    EXPECT_EQ(order[i + 1], GetFocusController().FindFocusableElementAfter(
+    EXPECT_EQ(order[i + 1], FindFocusableElementAfter(
                                 *order[i], mojom::blink::FocusType::kForward));
   }
   for (std::size_t i = 0u; i < order.size() - 1; ++i) {
-    EXPECT_EQ(order[i], GetFocusController().FindFocusableElementAfter(
+    EXPECT_EQ(order[i], FindFocusableElementAfter(
                             *order[i + 1], mojom::blink::FocusType::kBackward));
   }
 
@@ -670,11 +681,11 @@
                                     post_input};
 
   for (std::size_t i = 0u; i < order.size() - 1; ++i) {
-    EXPECT_EQ(order[i + 1], GetFocusController().FindFocusableElementAfter(
+    EXPECT_EQ(order[i + 1], FindFocusableElementAfter(
                                 *order[i], mojom::blink::FocusType::kForward));
   }
   for (std::size_t i = 0u; i < order.size() - 1; ++i) {
-    EXPECT_EQ(order[i], GetFocusController().FindFocusableElementAfter(
+    EXPECT_EQ(order[i], FindFocusableElementAfter(
                             *order[i + 1], mojom::blink::FocusType::kBackward));
   }
 }
@@ -730,11 +741,11 @@
       post_input};
 
   for (std::size_t i = 0u; i < order.size() - 1; ++i) {
-    EXPECT_EQ(order[i + 1], GetFocusController().FindFocusableElementAfter(
+    EXPECT_EQ(order[i + 1], FindFocusableElementAfter(
                                 *order[i], mojom::blink::FocusType::kForward));
   }
   for (std::size_t i = 0u; i < order.size() - 1; ++i) {
-    EXPECT_EQ(order[i], GetFocusController().FindFocusableElementAfter(
+    EXPECT_EQ(order[i], FindFocusableElementAfter(
                             *order[i + 1], mojom::blink::FocusType::kBackward));
   }
 }
@@ -771,11 +782,11 @@
       after_scroller, after_scroll_marker_group,  post_input};
 
   for (std::size_t i = 0u; i < order.size() - 1; ++i) {
-    EXPECT_EQ(order[i + 1], GetFocusController().FindFocusableElementAfter(
+    EXPECT_EQ(order[i + 1], FindFocusableElementAfter(
                                 *order[i], mojom::blink::FocusType::kForward));
   }
   for (std::size_t i = 0u; i < order.size() - 1; ++i) {
-    EXPECT_EQ(order[i], GetFocusController().FindFocusableElementAfter(
+    EXPECT_EQ(order[i], FindFocusableElementAfter(
                             *order[i + 1], mojom::blink::FocusType::kBackward));
   }
 }
@@ -880,11 +891,11 @@
                                     post_input};
 
   for (std::size_t i = 0u; i < order.size() - 1; ++i) {
-    EXPECT_EQ(order[i + 1], GetFocusController().FindFocusableElementAfter(
+    EXPECT_EQ(order[i + 1], FindFocusableElementAfter(
                                 *order[i], mojom::blink::FocusType::kForward));
   }
   for (std::size_t i = 0u; i < order.size() - 1; ++i) {
-    EXPECT_EQ(order[i], GetFocusController().FindFocusableElementAfter(
+    EXPECT_EQ(order[i], FindFocusableElementAfter(
                             *order[i + 1], mojom::blink::FocusType::kBackward));
   }
 }
diff --git a/third_party/blink/renderer/core/streams/byte_length_queuing_strategy.idl b/third_party/blink/renderer/core/streams/byte_length_queuing_strategy.idl
index 4010a9f..1456cdf 100644
--- a/third_party/blink/renderer/core/streams/byte_length_queuing_strategy.idl
+++ b/third_party/blink/renderer/core/streams/byte_length_queuing_strategy.idl
@@ -5,7 +5,7 @@
 // https://streams.spec.whatwg.org/#blqs-class
 
 [
-    Exposed=(Window,Worker,Worklet)
+    Exposed=*
 ] interface ByteLengthQueuingStrategy {
     [CallWith=ScriptState, MeasureAs=ByteLengthQueuingStrategyConstructor] constructor(QueuingStrategyInit init);
     readonly attribute unrestricted double highWaterMark;
diff --git a/third_party/blink/renderer/core/streams/count_queuing_strategy.idl b/third_party/blink/renderer/core/streams/count_queuing_strategy.idl
index a0b8ded..5d47e8f 100644
--- a/third_party/blink/renderer/core/streams/count_queuing_strategy.idl
+++ b/third_party/blink/renderer/core/streams/count_queuing_strategy.idl
@@ -5,7 +5,7 @@
 // https://streams.spec.whatwg.org/#cqs-class
 
 [
-    Exposed=(Window,Worker,Worklet)
+    Exposed=*
 ] interface CountQueuingStrategy {
     [CallWith=ScriptState, MeasureAs=CountQueuingStrategyConstructor] constructor(QueuingStrategyInit init);
     readonly attribute unrestricted double highWaterMark;
diff --git a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.idl b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.idl
index 30ee973..d4ba351 100644
--- a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.idl
+++ b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.idl
@@ -4,7 +4,7 @@
 
 // https://streams.spec.whatwg.org/#rbs-controller-class-definition
 [
-    Exposed=(Window,Worker,Worklet)
+    Exposed=*
 ] interface ReadableByteStreamController {
     readonly attribute ReadableStreamBYOBRequest? byobRequest;
     readonly attribute double? desiredSize;
diff --git a/third_party/blink/renderer/core/streams/readable_stream.idl b/third_party/blink/renderer/core/streams/readable_stream.idl
index affe0f0..d5f1bc5f 100644
--- a/third_party/blink/renderer/core/streams/readable_stream.idl
+++ b/third_party/blink/renderer/core/streams/readable_stream.idl
@@ -10,7 +10,7 @@
 enum ReadableStreamType { "bytes" };
 
 [
-    Exposed=(Window,Worker,Worklet)
+    Exposed=*
 ] interface ReadableStream {
     [RuntimeEnabled=ReadableStreamAsyncIterable, HasAsyncIteratorReturnAlgorithm] async iterable<any>(optional ReadableStreamIteratorOptions options = {});
 
diff --git a/third_party/blink/renderer/core/streams/readable_stream_byob_reader.idl b/third_party/blink/renderer/core/streams/readable_stream_byob_reader.idl
index 7907190..fee1494d 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_byob_reader.idl
+++ b/third_party/blink/renderer/core/streams/readable_stream_byob_reader.idl
@@ -4,7 +4,7 @@
 
 // https://streams.spec.whatwg.org/#byob-reader-class-definition
 [
-    Exposed=(Window,Worker,Worklet)
+    Exposed=*
 ] interface ReadableStreamBYOBReader {
     [CallWith=ScriptState, RaisesException] constructor(ReadableStream stream);
 
diff --git a/third_party/blink/renderer/core/streams/readable_stream_byob_request.idl b/third_party/blink/renderer/core/streams/readable_stream_byob_request.idl
index a5101f6a..727cfad 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_byob_request.idl
+++ b/third_party/blink/renderer/core/streams/readable_stream_byob_request.idl
@@ -4,7 +4,7 @@
 
 // https://streams.spec.whatwg.org/#readablestreambyobrequest
 [
-    Exposed=(Window,Worker,Worklet)
+    Exposed=*
 ] interface ReadableStreamBYOBRequest {
     readonly attribute ArrayBufferView? view;
 
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl b/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl
index ab81ed9..61ad2d4 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl
@@ -4,7 +4,7 @@
 
 // https://streams.spec.whatwg.org/#rs-default-controller-class-definition
 [
-    Exposed=(Window,Worker,Worklet)
+    Exposed=*
 ]
 interface ReadableStreamDefaultController {
     readonly attribute double? desiredSize;
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl b/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl
index 9fe0981..16abf83 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl
@@ -4,7 +4,7 @@
 
 // https://streams.spec.whatwg.org/#default-reader-class-definition
 [
-    Exposed=(Window,Worker,Worklet),
+    Exposed=*,
     ActiveScriptWrappable
 ] interface ReadableStreamDefaultReader {
     [CallWith=ScriptState, RaisesException] constructor(ReadableStream stream);
diff --git a/third_party/blink/renderer/core/streams/readable_stream_generic_reader.idl b/third_party/blink/renderer/core/streams/readable_stream_generic_reader.idl
index bde6f558..6b5b9348 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_generic_reader.idl
+++ b/third_party/blink/renderer/core/streams/readable_stream_generic_reader.idl
@@ -4,7 +4,7 @@
 
 // https://streams.spec.whatwg.org/#readablestreamgenericreader
 [
-    Exposed=(Window,Worker,Worklet)
+    Exposed=*
 ] interface mixin ReadableStreamGenericReader {
     [CallWith=ScriptState] readonly attribute Promise<undefined> closed;
     [CallWith=ScriptState, RaisesException] Promise<undefined> cancel(optional any reason);
diff --git a/third_party/blink/renderer/core/streams/transform_stream.idl b/third_party/blink/renderer/core/streams/transform_stream.idl
index c8830b6..0878a92 100644
--- a/third_party/blink/renderer/core/streams/transform_stream.idl
+++ b/third_party/blink/renderer/core/streams/transform_stream.idl
@@ -4,7 +4,7 @@
 
 // https://streams.spec.whatwg.org/#ts-class
 [
-    Exposed=(Window,Worker,Worklet)
+    Exposed=*
 ] interface TransformStream {
     [CallWith=ScriptState, RaisesException] constructor(optional any transformer,
                 optional any writableStrategy,
diff --git a/third_party/blink/renderer/core/streams/transform_stream_default_controller.idl b/third_party/blink/renderer/core/streams/transform_stream_default_controller.idl
index 31a8a07..1a40138 100644
--- a/third_party/blink/renderer/core/streams/transform_stream_default_controller.idl
+++ b/third_party/blink/renderer/core/streams/transform_stream_default_controller.idl
@@ -4,7 +4,7 @@
 
 // https://streams.spec.whatwg.org/#ts-default-controller-class-definition
 [
-    Exposed=(Window,Worker,Worklet)
+    Exposed=*
 ]interface TransformStreamDefaultController {
     readonly attribute unrestricted double? desiredSize;
     [CallWith=ScriptState, RaisesException] void enqueue(
diff --git a/third_party/blink/renderer/core/streams/writable_stream.idl b/third_party/blink/renderer/core/streams/writable_stream.idl
index 70338f1..cc93364 100644
--- a/third_party/blink/renderer/core/streams/writable_stream.idl
+++ b/third_party/blink/renderer/core/streams/writable_stream.idl
@@ -4,7 +4,7 @@
 
 // https://streams.spec.whatwg.org/#ws-class
 [
-    Exposed=(Window,Worker,Worklet)
+    Exposed=*
 ] interface WritableStream {
     [CallWith=ScriptState, RaisesException, MeasureAs=WritableStreamConstructor] constructor(optional any underlyingSink, optional any strategy);
     readonly attribute boolean locked;
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_controller.idl b/third_party/blink/renderer/core/streams/writable_stream_default_controller.idl
index aea0822..fb362a5 100644
--- a/third_party/blink/renderer/core/streams/writable_stream_default_controller.idl
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_controller.idl
@@ -4,7 +4,7 @@
 
 // https://streams.spec.whatwg.org/#ws-default-controller-class-definition
 [
-    Exposed=(Window,Worker,Worklet)
+    Exposed=*
 ]
 interface WritableStreamDefaultController {
     readonly attribute AbortSignal signal;
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_writer.idl b/third_party/blink/renderer/core/streams/writable_stream_default_writer.idl
index 6515199..2c1ad0b 100644
--- a/third_party/blink/renderer/core/streams/writable_stream_default_writer.idl
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_writer.idl
@@ -6,7 +6,7 @@
 
 // https://streams.spec.whatwg.org/#default-writer-class-definition
 [
-    Exposed=(Window,Worker,Worklet)
+    Exposed=*
 ] interface WritableStreamDefaultWriter {
     [CallWith=ScriptState, RaisesException] constructor(WritableStream stream);
     [CallWith=ScriptState] readonly attribute Promise<undefined>
diff --git a/third_party/blink/renderer/core/url/url.idl b/third_party/blink/renderer/core/url/url.idl
index bf9f75d..54aae2ed 100644
--- a/third_party/blink/renderer/core/url/url.idl
+++ b/third_party/blink/renderer/core/url/url.idl
@@ -27,7 +27,7 @@
 // https://url.spec.whatwg.org/#url
 
 [
-    Exposed=(Window,Worker),
+    Exposed=(Window,Worker,ShadowRealm), // TODO(crbug.com/41480387): This should be Exposed=*
     ImplementedAs=DOMURL,
     LegacyWindowAlias=webkitURL
 ] interface URL {
diff --git a/third_party/blink/renderer/core/url/url_search_params.idl b/third_party/blink/renderer/core/url/url_search_params.idl
index 2a55e58..2ac09cb 100644
--- a/third_party/blink/renderer/core/url/url_search_params.idl
+++ b/third_party/blink/renderer/core/url/url_search_params.idl
@@ -5,7 +5,7 @@
 // https://url.spec.whatwg.org/#interface-urlsearchparams
 
 [
-    Exposed=(Window,Worker)
+    Exposed=(Window,Worker,ShadowRealm) // TODO(crbug.com/41480387): This should be Exposed=*
 ] interface URLSearchParams {
     [RaisesException] constructor(optional (sequence<sequence<USVString>> or record<USVString, USVString> or USVString) init = "");
     readonly attribute unsigned long size;
diff --git a/third_party/blink/renderer/core/url_pattern/url_pattern.idl b/third_party/blink/renderer/core/url_pattern/url_pattern.idl
index a96991e..437195f 100644
--- a/third_party/blink/renderer/core/url_pattern/url_pattern.idl
+++ b/third_party/blink/renderer/core/url_pattern/url_pattern.idl
@@ -10,7 +10,7 @@
 
 // https://wicg.github.io/urlpattern/
 [
-  Exposed=(Window,Worker)
+  Exposed=(Window,Worker,ShadowRealm) // TODO(crbug.com/41480387): This should be Exposed=*
 ] interface URLPattern {
   [RaisesException, CallWith=Isolate, Measure]
   constructor(URLPatternInput input, USVString baseURL, optional URLPatternOptions options = {});
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
index b453894..7139b0b 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
@@ -197,6 +197,9 @@
   SkAlphaType GetAlphaType() const override {
     return color_params_.GetAlphaType();
   }
+  SkColorType GetSkColorType() const override {
+    return CanvasRenderingContextSkColorInfo().colorType();
+  }
   sk_sp<SkColorSpace> GetSkColorSpace() const override {
     return color_params_.GetSkColorSpace();
   }
diff --git a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.h b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.h
index 48c77e3..9115b3a 100644
--- a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.h
+++ b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.h
@@ -47,6 +47,7 @@
                        SkColorSpace::MakeSRGB());
   }
   SkAlphaType GetAlphaType() const override { return kPremul_SkAlphaType; }
+  SkColorType GetSkColorType() const override { return kN32_SkColorType; }
   sk_sp<SkColorSpace> GetSkColorSpace() const override {
     return SkColorSpace::MakeSRGB();
   }
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
index 5e8d44f..2ac3be9 100644
--- a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
+++ b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
@@ -67,6 +67,9 @@
   SkAlphaType GetAlphaType() const override {
     return color_params_.GetAlphaType();
   }
+  SkColorType GetSkColorType() const override {
+    return CanvasRenderingContextSkColorInfo().colorType();
+  }
   sk_sp<SkColorSpace> GetSkColorSpace() const override {
     return color_params_.GetSkColorSpace();
   }
diff --git a/third_party/blink/renderer/modules/content_extraction/ai_page_content_agent.cc b/third_party/blink/renderer/modules/content_extraction/ai_page_content_agent.cc
index 0fe97de..374e80a 100644
--- a/third_party/blink/renderer/modules/content_extraction/ai_page_content_agent.cc
+++ b/third_party/blink/renderer/modules/content_extraction/ai_page_content_agent.cc
@@ -109,6 +109,26 @@
   return DynamicTo<LayoutIFrame>(object);
 }
 
+bool IsGenericContainer(const LayoutObject& object) {
+  if (object.Style()->GetPosition() == EPosition::kFixed) {
+    return true;
+  }
+
+  if (object.Style()->GetPosition() == EPosition::kSticky) {
+    return true;
+  }
+
+  if (object.Style()->ScrollsOverflow()) {
+    return true;
+  }
+
+  if (object.IsInTopOrViewTransitionLayer()) {
+    return true;
+  }
+
+  return false;
+}
+
 std::optional<mojom::blink::AIPageContentAttributeType> GetAttributeType(
     const LayoutObject& object) {
   if (GetIFrame(object)) {
@@ -199,12 +219,8 @@
 
   // TODO: Add FormData for attribute_type = FORM.
 
-  // If an object is fixed or sticky position or scrolls, set it as its own
-  // container. Keep container at the bottom of the list as it is the least
-  // specific.
-  if (object.Style()->GetPosition() == EPosition::kFixed ||
-      object.Style()->GetPosition() == EPosition::kSticky ||
-      object.Style()->ScrollsOverflow()) {
+  // Keep container at the bottom of the list as it is the least specific.
+  if (IsGenericContainer(object)) {
     return mojom::blink::AIPageContentAttributeType::kContainer;
   }
 
diff --git a/third_party/blink/renderer/modules/content_extraction/ai_page_content_agent_unittest.cc b/third_party/blink/renderer/modules/content_extraction/ai_page_content_agent_unittest.cc
index 13e9ec64..2d038ef 100644
--- a/third_party/blink/renderer/modules/content_extraction/ai_page_content_agent_unittest.cc
+++ b/third_party/blink/renderer/modules/content_extraction/ai_page_content_agent_unittest.cc
@@ -1064,5 +1064,37 @@
             mojom::blink::AIPageContentAnchorRel::kRelationNoReferrer);
 }
 
+TEST_F(AIPageContentAgentTest, TopLayerContainer) {
+  frame_test_helpers::LoadHTMLString(
+      helper_.LocalMainFrame(),
+      "<body>"
+      "  <dialog id='welcomeDialog' style='position: absolute; overflow: "
+      "visible;'>"
+      "    This is a dialog."
+      "  </dialog>"
+      "  <script>"
+      "    const dialog = document.getElementById('welcomeDialog');"
+      "    dialog.showModal();"
+      "  </script>"
+      "</body>",
+      url_test_helpers::ToKURL("http://foobar.com"));
+
+  auto* agent = AIPageContentAgent::GetOrCreateForTesting(
+      *helper_.LocalMainFrame()->GetFrame()->GetDocument());
+  ASSERT_TRUE(agent);
+
+  auto content = agent->GetAIPageContentSync();
+  ASSERT_TRUE(content);
+  ASSERT_TRUE(content->root_node);
+
+  const auto& root = *content->root_node;
+  EXPECT_EQ(root.children_nodes.size(), 1u);
+
+  const auto& dialog = root.children_nodes.at(0);
+  EXPECT_EQ(dialog->content_attributes->attribute_type,
+            mojom::blink::AIPageContentAttributeType::kContainer);
+  EXPECT_TRUE(dialog->children_nodes.empty());
+}
+
 }  // namespace
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/credentialmanagement/identity_provider_config.idl b/third_party/blink/renderer/modules/credentialmanagement/identity_provider_config.idl
index 968ed92..0dd1af2e 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/identity_provider_config.idl
+++ b/third_party/blink/renderer/modules/credentialmanagement/identity_provider_config.idl
@@ -31,5 +31,5 @@
   [RuntimeEnabled=FedCmDomainHint] DOMString domainHint;
   [RuntimeEnabled=FedCmAuthz] sequence<(USVString or IdentityProviderField)> fields;
   [RuntimeEnabled=FedCmAuthz] any params;
-  [RuntimeEnabled=FedCmIdPRegistration] IdentityProviderRequestOptionsFormat format;
+  [RuntimeEnabled=FedCmDelegation] IdentityProviderRequestOptionsFormat format;
 };
diff --git a/third_party/blink/renderer/modules/mediastream/web_media_player_ms.cc b/third_party/blink/renderer/modules/mediastream/web_media_player_ms.cc
index 21d4877..b825da9 100644
--- a/third_party/blink/renderer/modules/mediastream/web_media_player_ms.cc
+++ b/third_party/blink/renderer/modules/mediastream/web_media_player_ms.cc
@@ -1239,7 +1239,8 @@
 }
 
 void WebMediaPlayerMS::SetVolumeMultiplier(double multiplier) {
-  // TODO(perkj, magjed): See TODO in OnPlay().
+  volume_multiplier_ = multiplier;
+  SetVolume(volume_);
 }
 
 void WebMediaPlayerMS::ActivateSurfaceLayerForVideo(
diff --git a/third_party/blink/renderer/modules/mediastream/web_media_player_ms_test.cc b/third_party/blink/renderer/modules/mediastream/web_media_player_ms_test.cc
index a379be1..bd47a05 100644
--- a/third_party/blink/renderer/modules/mediastream/web_media_player_ms_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/web_media_player_ms_test.cc
@@ -267,7 +267,7 @@
   void Stop() override {}
   void Play() override {}
   void Pause() override {}
-  void SetVolume(float volume) override {}
+  MOCK_METHOD(void, SetVolume, (float volume));
 
   void SwitchOutputDevice(const std::string& device_id,
                           media::OutputDeviceStatusCB callback) override {}
@@ -1762,6 +1762,37 @@
   EXPECT_NE(gpu_frame, compositor_->GetCurrentFrame());
 }
 
+TEST_P(WebMediaPlayerMSTest, VolumeMultiplierAdjustsOutputVolume) {
+  InitializeWebMediaPlayerMS();
+  is_audio_element_ = true;
+  auto audio_renderer = base::MakeRefCounted<MockMediaStreamAudioRenderer>();
+  render_factory_->set_audio_renderer(audio_renderer);
+
+  player_->Load(WebMediaPlayer::kLoadTypeURL, WebMediaPlayerSource(),
+                WebMediaPlayer::kCorsModeUnspecified,
+                /*is_cache_disabled=*/false);
+
+  message_loop_controller_.RunAndWaitForStatus(media::PIPELINE_OK);
+
+  // Setting the volume multiplier should adjust the volume sent to the audio
+  // renderer.
+  EXPECT_CALL(*audio_renderer, SetVolume(0.2));
+  player_->SetVolumeMultiplier(0.2);
+  testing::Mock::VerifyAndClearExpectations(audio_renderer.get());
+
+  // Setting the volume after the multiplier should still take the multiplier
+  // into account.
+  EXPECT_CALL(*audio_renderer, SetVolume(0.1));
+  player_->SetVolume(0.5);
+  testing::Mock::VerifyAndClearExpectations(audio_renderer.get());
+
+  // Resetting the multiplier should take the previously set volume into
+  // account.
+  EXPECT_CALL(*audio_renderer, SetVolume(0.5));
+  player_->SetVolumeMultiplier(1.0);
+  testing::Mock::VerifyAndClearExpectations(audio_renderer.get());
+}
+
 INSTANTIATE_TEST_SUITE_P(All,
                          WebMediaPlayerMSTest,
                          ::testing::Combine(::testing::Bool(),
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context.cc b/third_party/blink/renderer/modules/webaudio/audio_context.cc
index 7056ad0b..60cd8c6 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_context.cc
@@ -253,6 +253,7 @@
                            WebAudioSinkDescriptor sink_descriptor,
                            bool update_echo_cancellation_on_first_start)
     : BaseAudioContext(&window, kRealtimeContext),
+      FrameVisibilityObserver(GetLocalFrame()),
       context_id_(context_id++),
       audio_context_manager_(&window),
       permission_service_(&window),
@@ -261,7 +262,15 @@
       v8_sink_id_(
           MakeGarbageCollected<V8UnionAudioSinkInfoOrString>(g_empty_string)),
       media_device_service_(&window),
-      media_device_service_receiver_(this, &window) {
+      media_device_service_receiver_(this, &window),
+      should_interrupt_when_frame_is_hidden_(
+          RuntimeEnabledFeatures::
+              MediaPlaybackWhileNotVisiblePermissionPolicyEnabled() &&
+          RuntimeEnabledFeatures::AudioContextInterruptedStateEnabled() &&
+          !GetExecutionContext()->IsFeatureEnabled(
+              mojom::blink::PermissionsPolicyFeature::
+                  kMediaPlaybackWhileNotVisible,
+              ReportOptions::kDoNotReport)) {
   RecordAudioContextOperation(AudioContextOperation::kCreate);
   SendLogMessage(__func__, GetAudioContextLogString(latency_hint, sample_rate));
 
@@ -378,6 +387,7 @@
   visitor->Trace(media_device_service_receiver_);
   visitor->Trace(v8_sink_id_);
   BaseAudioContext::Trace(visitor);
+  FrameVisibilityObserver::Trace(visitor);
 }
 
 ScriptPromise<IDLUndefined> AudioContext::suspendContext(
@@ -431,6 +441,8 @@
         script_state, MakeGarbageCollected<DOMException>(
                           DOMExceptionCode::kInvalidStateError,
                           "Cannot resume an interrupted AudioContext."));
+  } else if (is_frame_hidden_ && should_interrupt_when_frame_is_hidden_) {
+    StartContextInterruption();
   }
 
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver<IDLUndefined>>(
@@ -1210,6 +1222,31 @@
   }
 }
 
+void AudioContext::FrameVisibilityChanged(
+    mojom::blink::FrameVisibility frame_visibility) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_);
+
+  bool is_frame_hidden =
+      (frame_visibility == mojom::blink::FrameVisibility::kNotRendered);
+  if (is_frame_hidden == is_frame_hidden_) {
+    return;
+  }
+
+  is_frame_hidden_ = is_frame_hidden;
+
+  if (!should_interrupt_when_frame_is_hidden_) {
+    return;
+  }
+
+  if (is_frame_hidden_) {
+    // The frame is not rendered, so the audio context should be suspended.
+    StartContextInterruption();
+  } else {
+    // The frame is rendered, so the audio context should be resumed.
+    EndContextInterruption();
+  }
+}
+
 void AudioContext::UninitializeMediaDeviceService() {
   if (media_device_service_.is_bound()) {
     media_device_service_.reset();
@@ -1370,4 +1407,13 @@
           .Utf8());
 }
 
+LocalFrame* AudioContext::GetLocalFrame() const {
+  LocalDOMWindow* window = GetWindow();
+  if (!window) {
+    return nullptr;
+  }
+
+  return window->GetFrame();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context.h b/third_party/blink/renderer/modules/webaudio/audio_context.h
index ceb5d79..7706e55 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_context.h
@@ -16,6 +16,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_context_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_union_audiosinkinfo_string.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_union_audiosinkoptions_string.h"
+#include "third_party/blink/renderer/core/frame/frame_visibility_observer.h"
 #include "third_party/blink/renderer/core/html/media/autoplay_policy.h"
 #include "third_party/blink/renderer/modules/webaudio/base_audio_context.h"
 #include "third_party/blink/renderer/modules/webaudio/setsinkid_resolver.h"
@@ -49,7 +50,8 @@
 class MODULES_EXPORT AudioContext final
     : public BaseAudioContext,
       public mojom::blink::PermissionObserver,
-      public mojom::blink::MediaDevicesListener {
+      public mojom::blink::MediaDevicesListener,
+      public FrameVisibilityObserver {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
@@ -99,6 +101,10 @@
   void OnDevicesChanged(mojom::blink::MediaDeviceType,
                         const Vector<WebMediaDeviceInfo>&) override;
 
+  // FrameVisibilityObserver
+  void FrameVisibilityChanged(
+      mojom::blink::FrameVisibility frame_visibility) override;
+
   // https://webaudio.github.io/web-audio-api/#AudioContext
   double baseLatency() const;
   double outputLatency() const;
@@ -276,6 +282,8 @@
   // https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/media/capture/README.md#logs
   void SendLogMessage(const char* const function_name, const String& message);
 
+  LocalFrame* GetLocalFrame() const;
+
   // https://webaudio.github.io/web-audio-api/#dom-audiocontext-suspended-by-user-slot
   bool suspended_by_user_ = false;
 
@@ -387,6 +395,14 @@
   // ends.
   bool should_transition_to_running_after_interruption_ = false;
 
+  // True if the context should be interrupted when the frame is hidden.
+  const bool should_interrupt_when_frame_is_hidden_;
+
+  // True if the host frame's:
+  // - 'display' property is set to 'none';
+  // - 'visibility' property is set to 'hidden';
+  bool is_frame_hidden_ = false;
+
   // The number of pending device list updates, to allow waiting until the
   // device list is refrehsed before using it.  A value of 0 means no updates
   // are pending.
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index 1a50e49..bd0b8d0 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -5635,6 +5635,10 @@
   return CreationAttributes().alpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
 }
 
+SkColorType WebGLRenderingContextBase::GetSkColorType() const {
+  return CanvasRenderingContextSkColorInfo().colorType();
+}
+
 sk_sp<SkColorSpace> WebGLRenderingContextBase::GetSkColorSpace() const {
   return PredefinedColorSpaceToSkColorSpace(drawing_buffer_color_space_);
 }
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
index f28c157..c52e939 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
@@ -636,6 +636,7 @@
   // contexts, and should be removed.
   SkColorInfo CanvasRenderingContextSkColorInfo() const override;
   SkAlphaType GetAlphaType() const override;
+  SkColorType GetSkColorType() const override;
   sk_sp<SkColorSpace> GetSkColorSpace() const override;
   scoped_refptr<StaticBitmapImage> GetImage(FlushReason) override;
   void SetHdrMetadata(const gfx::HDRMetadata& hdr_metadata) override;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
index 46312f0a..caded933 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
@@ -107,9 +107,7 @@
     return SkColorInfo(kN32_SkColorType, kPremul_SkAlphaType,
                        SkColorSpace::MakeSRGB());
   }
-  return SkColorInfo(viz::ToClosestSkColorType(
-                         /*gpu_compositing=*/true, swap_buffers_->Format()),
-                     GetAlphaType(), GetSkColorSpace());
+  return SkColorInfo(GetSkColorType(), GetAlphaType(), GetSkColorSpace());
 }
 
 SkAlphaType GPUCanvasContext::GetAlphaType() const {
@@ -118,6 +116,14 @@
              : kPremul_SkAlphaType;
 }
 
+SkColorType GPUCanvasContext::GetSkColorType() const {
+  if (!swap_buffers_) {
+    return kN32_SkColorType;
+  }
+  return viz::ToClosestSkColorType(
+      /*gpu_compositing=*/true, swap_buffers_->Format());
+}
+
 sk_sp<SkColorSpace> GPUCanvasContext::GetSkColorSpace() const {
   if (!swap_buffers_) {
     return SkColorSpace::MakeSRGB();
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h
index 3653d91..0ced6cb5 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h
@@ -64,6 +64,7 @@
   V8OffscreenRenderingContext* AsV8OffscreenRenderingContext() final;
   SkColorInfo CanvasRenderingContextSkColorInfo() const override;
   SkAlphaType GetAlphaType() const override;
+  SkColorType GetSkColorType() const override;
   sk_sp<SkColorSpace> GetSkColorSpace() const override;
   // Produces a snapshot of the current contents of the swap chain if possible.
   // If that texture has already been sent to the compositor, will produce a
diff --git a/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.cc b/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.cc
index b056386..db00d061 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.cc
@@ -6,6 +6,7 @@
 
 #include "base/feature_list.h"
 #include "base/memory/post_delayed_memory_reduction_task.h"
+#include "base/strings/stringprintf.h"
 #include "base/timer/elapsed_timer.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/memory_dump_request_args.h"
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.cc b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
index bc177a1..f925749 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
@@ -9,6 +9,7 @@
 
 #include "base/functional/callback_helpers.h"
 #include "base/memory/read_only_shared_memory_region.h"
+#include "base/strings/stringprintf.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
diff --git a/third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h b/third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h
index d11e345..38333da 100644
--- a/third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h
+++ b/third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h
@@ -45,4 +45,17 @@
 
 }  // namespace blink
 
+namespace WTF {
+
+template <typename ValueArg, typename TraitsArg, typename VectorType>
+inline void CopyToVector(const blink::HeapHashSet<ValueArg, TraitsArg>& set,
+                         VectorType& vector) {
+  CopyToVector(
+      static_cast<const HashSet<ValueArg, TraitsArg, blink::HeapAllocator>&>(
+          set),
+      vector);
+}
+
+}  //  namespace WTF
+
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_SET_H_
diff --git a/third_party/blink/renderer/platform/heap/test/heap_test.cc b/third_party/blink/renderer/platform/heap/test/heap_test.cc
index 32f494d..dcb2855 100644
--- a/third_party/blink/renderer/platform/heap/test/heap_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/heap_test.cc
@@ -2078,6 +2078,41 @@
     EXPECT_TRUE(i->Value() == 1 || i->Value() == 2);
 }
 
+TEST_F(HeapTest, HeapHashSetToVector) {
+  HeapHashSet<Member<IntWrapper>> set;
+  HeapVector<Member<IntWrapper>> vector;
+  set.insert(MakeGarbageCollected<IntWrapper>(1));
+  set.insert(MakeGarbageCollected<IntWrapper>(1));
+  set.insert(MakeGarbageCollected<IntWrapper>(2));
+
+  CopyToVector(set, vector);
+  EXPECT_EQ(3u, vector.size());
+
+  Vector<int> int_vector;
+  for (const auto& i : vector) {
+    int_vector.push_back(i->Value());
+  }
+  std::sort(int_vector.begin(), int_vector.end());
+  ASSERT_EQ(3u, int_vector.size());
+  EXPECT_EQ(1, int_vector[0]);
+  EXPECT_EQ(1, int_vector[1]);
+  EXPECT_EQ(2, int_vector[2]);
+}
+
+TEST_F(HeapTest, WeakHeapHashSetToVector) {
+  HeapHashSet<WeakMember<IntWrapper>> set;
+  HeapVector<Member<IntWrapper>> vector;
+  set.insert(MakeGarbageCollected<IntWrapper>(1));
+  set.insert(MakeGarbageCollected<IntWrapper>(1));
+  set.insert(MakeGarbageCollected<IntWrapper>(2));
+
+  CopyToVector(set, vector);
+  EXPECT_EQ(3u, vector.size());
+  for (const auto& i : vector) {
+    EXPECT_TRUE(i->Value() == 1 || i->Value() == 2);
+  }
+}
+
 TEST_F(HeapTest, RefCountedGarbageCollected) {
   RefCountedAndGarbageCollected::destructor_calls_ = 0;
   {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index 96be4c8..1759495e 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -602,9 +602,7 @@
   // the placement of this code, together with the //net counterpart.
   if (removed_headers) {
     // Step 13 of https://fetch.spec.whatwg.org/#http-redirect-fetch
-    if (base::FeatureList::IsEnabled(
-            features::kRemoveAuthroizationOnCrossOriginRedirect) &&
-        !SecurityOrigin::AreSameOrigin(resource_->LastResourceRequest().Url(),
+    if (!SecurityOrigin::AreSameOrigin(resource_->LastResourceRequest().Url(),
                                        new_url)) {
       removed_headers->push_back(net::HttpRequestHeaders::kAuthorization);
     }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index b1bd6e5..5a9b3466 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1781,6 +1781,13 @@
       origin_trial_allows_third_party: true,
     },
     {
+      name: "FedCmDelegation",
+      depends_on: ["FedCm"],
+      public: true,
+      status: "test",
+      base_feature: "none",
+    },
+    {
       name: "FedCmDisconnect",
       depends_on: ["FedCm"],
       base_feature: "none",
@@ -3362,10 +3369,8 @@
     },
     {
       name: "PrivateStateTokens",
-      // status: "test",
+      status: "stable",
       base_feature: "none",
-      origin_trial_feature_name: "TrustTokens",
-      origin_trial_allows_third_party: true,
       public: true,
     },
     {
@@ -4111,6 +4116,11 @@
       status: "stable",
     },
     {
+      // crbug.com/40890818
+      name: "SvgTspanBboxCache",
+      status: "stable",
+    },
+    {
       name: "SynthesizedKeyboardEventsForAccessibilityActions",
       status: "experimental",
     },
diff --git a/third_party/blink/renderer/platform/wtf/hash_set.h b/third_party/blink/renderer/platform/wtf/hash_set.h
index 77c222a..247e61b 100644
--- a/third_party/blink/renderer/platform/wtf/hash_set.h
+++ b/third_party/blink/renderer/platform/wtf/hash_set.h
@@ -378,6 +378,25 @@
   return Take(begin());
 }
 
+template <typename Value,
+          typename Traits,
+          typename Allocator,
+          typename VectorType>
+inline void CopyToVector(const HashSet<Value, Traits, Allocator>& collection,
+                         VectorType& vector) {
+  {
+    // Disallow GC across resize allocation, see crbug.com/568173
+    typename VectorType::GCForbiddenScope scope;
+    vector.resize(collection.size());
+  }
+
+  auto it = collection.begin();
+  auto end = collection.end();
+  for (unsigned i = 0; it != end; ++it, ++i) {
+    vector[i] = (*it);
+  }
+}
+
 }  // namespace WTF
 
 using WTF::HashSet;
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index b3f1c8f..cc45b28 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -3267,10 +3267,6 @@
 crbug.com/331915503 [ Mac11 ] virtual/fenced-frame-mparch/external/wpt/fenced-frame/notify-event-iframe.https.html [ Skip Timeout ]
 crbug.com/331851044 [ Mac14 ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any.worker.html?gpu [ Failure ]
 crbug.com/331711029 [ Win11-arm64 ] virtual/fenced-frame-mparch/external/wpt/fenced-frame/notify-event-success.https.html [ Failure Timeout ]
-crbug.com/626703 [ Mac11 ] virtual/threaded/external/wpt/css/css-view-transitions/navigation/chromium-paint-holding-timeout.html [ Timeout ]
-crbug.com/626703 [ Mac12 ] virtual/threaded/external/wpt/css/css-view-transitions/navigation/chromium-paint-holding-timeout.html [ Timeout ]
-crbug.com/626703 [ Mac15 ] virtual/threaded/external/wpt/css/css-view-transitions/navigation/chromium-paint-holding-timeout.html [ Timeout ]
-crbug.com/626703 [ Win11-arm64 ] virtual/threaded/external/wpt/css/css-view-transitions/navigation/chromium-paint-holding-timeout.html [ Timeout ]
 crbug.com/626703 external/wpt/css/css-text/white-space/text-wrap-balance-004.html [ Failure ]
 crbug.com/626703 external/wpt/editing/crashtests/designMode-caret-change.html [ Timeout ]
 crbug.com/626703 [ Mac14 ] external/wpt/webrtc-encoded-transform/tentative/RTCPeerConnection-insertable-streams-simulcast.https.html [ Pass Timeout ]
@@ -8849,8 +8845,8 @@
 crbug.com/383105114 [ Linux ] tables/mozilla/bugs/bug78162.html [ Failure Pass ]
 crbug.com/383105114 [ Win ] tables/mozilla/bugs/bug78162.html [ Failure Pass ]
 
-crbug.com/378549335 [ Mac ] wpt_internal/ai/language-model-api-context-overflow.https.any.html [ Pass Timeout ]
-crbug.com/378549335 [ Mac ] wpt_internal/ai/language-model-api-context-overflow.https.any.worker.html [ Pass Timeout ]
+crbug.com/378549335 [ Mac ] wpt_internal/ai/language-model-api-context-overflow.https.any.html [ Failure Pass Timeout ]
+crbug.com/378549335 [ Mac ] wpt_internal/ai/language-model-api-context-overflow.https.any.worker.html [ Failure Pass Timeout ]
 
 crbug.com/383855460 inspector-protocol/css/css-get-animated-styles.js [ Failure Pass ]
 
@@ -8858,3 +8854,6 @@
 
 # Gardener 2024-12-16
 crbug.com/381238355 [ Mac11 ] virtual/gpu-rasterization/external/wpt/css/css-images/object-view-box-fit-fill-video.html [ Failure Pass ]
+
+# Gardener 2024-12-17
+crbug.com/384549646 virtual/threaded/external/wpt/css/css-view-transitions/navigation/chromium-paint-holding-timeout.html [ Failure Pass Timeout ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 9060562..eeeca29e 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -4789,5 +4789,15 @@
     "args": ["--enable-features=SRIMessageSignatureEnforcement"],
     "owners": ["mkwst@chromium.org"],
     "expires": "May 1, 2025"
+  },
+  {
+    "prefix": "error-iserror-enabled",
+    "platforms": ["Linux"],
+    "bases": ["external/wpt/webidl/ecmascript-binding/es-exceptions/DOMException-is-error.any.js"],
+    "exclusive_tests": "ALL",
+    "args": ["--js-flags=--js-error-iserror"],
+    "owners": ["syg@chromium.org"],
+    "expires": "Feb 1, 2025"
   }
+
 ]
diff --git a/third_party/blink/web_tests/editing/pasteboard/extend_table_selection_crash_test.html b/third_party/blink/web_tests/editing/pasteboard/extend_table_selection_crash_test.html
new file mode 100644
index 0000000..a9b85bf8
--- /dev/null
+++ b/third_party/blink/web_tests/editing/pasteboard/extend_table_selection_crash_test.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<body></body>
+<script>
+  test(() => {
+    const body = document.getElementsByTagName("body")[0];
+    body.appendChild(document.createElement("td"));
+    body.appendChild(document.createElement("td"));
+    body.appendChild(document.createElement("td"));
+    document.designMode = "on";
+    assert_true(document.execCommand("selectAll"));
+    assert_true(document.execCommand("Cut"));
+  }, "copying only table part should not crash");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-cascade/scope-overlapping-has.html b/third_party/blink/web_tests/external/wpt/css/css-cascade/scope-overlapping-has.html
new file mode 100644
index 0000000..542cda0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-cascade/scope-overlapping-has.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>@scope - Overlapping scopes with :has(..:scope..) selector</title>
+<link rel="help" href="https://drafts.csswg.org/css-cascade-6/#scope-atrule">
+<link rel="help" href="https://issues.chromium.org/issues/383343312">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  :where(*) {
+    background-color: green;
+  }
+  @scope (.a) to (.limit) {
+    :scope:has(.b:not(:scope .a *)) .hello {
+      background-color: red;
+    }
+  }
+</style>
+<div class=a id=outer>
+  <div>
+    <div class=limit>
+      <div class=a id=inner>
+        <div class=b></div>
+        <div class=hello id=first>hello</div>
+      </div>
+    </div>
+  </div>
+  <div class=hello id=second>hello</div>
+</div>
+<script>
+test(() => {
+  assert_equals(getComputedStyle(first).backgroundColor, 'rgb(255, 0, 0)');
+  assert_equals(getComputedStyle(second).backgroundColor, 'rgb(0, 128, 0)');
+}, ':has() with inner :scope works when scopes overlap');
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-overflow/parsing/scroll-buttons-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/parsing/parsing/scroll-buttons-invalid.html
similarity index 97%
rename from third_party/blink/web_tests/wpt_internal/css/css-overflow/parsing/scroll-buttons-invalid.html
rename to third_party/blink/web_tests/external/wpt/css/css-overflow/parsing/parsing/scroll-buttons-invalid.html
index 6d7178b..752aa3c 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-overflow/parsing/scroll-buttons-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/parsing/parsing/scroll-buttons-invalid.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <meta charset="utf-8">
 <title>CSS Overflow Test: ::scroll-button() invalid tests</title>
 <link rel="help" href="https://drafts.csswg.org/css-overflow-5/#scroll-buttons">
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-overflow/parsing/scroll-buttons-valid.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/parsing/parsing/scroll-buttons-valid.html
similarity index 98%
rename from third_party/blink/web_tests/wpt_internal/css/css-overflow/parsing/scroll-buttons-valid.html
rename to third_party/blink/web_tests/external/wpt/css/css-overflow/parsing/parsing/scroll-buttons-valid.html
index 0198a65..b4e747e 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-overflow/parsing/scroll-buttons-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/parsing/parsing/scroll-buttons-valid.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <meta charset="utf-8">
 <title>CSS Overflow Test: ::scroll-button() valid tests</title>
 <link rel="help" href="https://drafts.csswg.org/css-overflow-5/#scroll-buttons">
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/parsing/parsing/scroll-markers-computed.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/parsing/parsing/scroll-markers-computed.html
new file mode 100644
index 0000000..882ed83
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/parsing/parsing/scroll-markers-computed.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Overflow: scroll-marker-group computed values</title>
+<link rel="help" href="https://drafts.csswg.org/css-overflow-5/#scroll-marker-group-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #target {
+    scroll-marker-group: before;
+  }
+</style>
+<div id="target"></div>
+<script>
+  test_computed_value('scroll-marker-group', 'initial', 'none');
+  test_computed_value('scroll-marker-group', 'inherit', 'none');
+  test_computed_value('scroll-marker-group', 'unset', 'none');
+  test_computed_value('scroll-marker-group', 'revert', 'none');
+
+  test_computed_value('scroll-marker-group', 'none');
+  test_computed_value('scroll-marker-group', 'before');
+  test_computed_value('scroll-marker-group', 'after');
+
+  test(() => {
+    let style = getComputedStyle(document.getElementById('target'));
+    assert_not_equals(Array.from(style).indexOf('scroll-marker-group'), -1);
+  }, 'The scroll-marker-group property shows up in CSSStyleDeclaration enumeration');
+
+  test(() => {
+    let style = document.getElementById('target').style;
+    assert_not_equals(style.cssText.indexOf('scroll-marker-group'), -1);
+  }, 'The scroll-marker-group property shows up in CSSStyleDeclaration.cssText');
+
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/parsing/parsing/scroll-markers-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/parsing/parsing/scroll-markers-invalid.html
new file mode 100644
index 0000000..5194d5a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/parsing/parsing/scroll-markers-invalid.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Overflow: parsing scroll-marker-group with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-overflow-5/#scroll-marker-group-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<div id="target"></div>
+<script>
+  test_invalid_value('scroll-marker-group', '10');
+  test_invalid_value('scroll-marker-group', 'true');
+  test_invalid_value('scroll-marker-group', 'default');
+  test_invalid_value('scroll-marker-group', 'set');
+  test_invalid_value('scroll-marker-group', 'before, after');
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/parsing/parsing/scroll-markers-valid.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/parsing/parsing/scroll-markers-valid.html
new file mode 100644
index 0000000..760efc8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/parsing/parsing/scroll-markers-valid.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Overflow: parsing scroll-marker-group with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-overflow-5/#scroll-marker-group-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<div id="target"></div>
+<script>
+  test_valid_value('scroll-marker-group', 'initial');
+  test_valid_value('scroll-marker-group', 'inherit');
+  test_valid_value('scroll-marker-group', 'unset');
+  test_valid_value('scroll-marker-group', 'revert');
+
+  test_valid_value("scroll-marker-group", "none");
+  test_valid_value("scroll-marker-group", "before");
+  test_valid_value("scroll-marker-group", "after");
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/register-property-syntax-parsing-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/initial-value-unit-arithmetic-expected.txt
similarity index 87%
rename from third_party/blink/web_tests/external/wpt/css/css-properties-values-api/register-property-syntax-parsing-expected.txt
rename to third_party/blink/web_tests/external/wpt/css/css-properties-values-api/initial-value-unit-arithmetic-expected.txt
index 6d09c309..10b6b476 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/register-property-syntax-parsing-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/initial-value-unit-arithmetic-expected.txt
@@ -1,5 +1,4 @@
 This is a testharness.js-based test.
-Found 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] syntax:'<length>', initialValue:'calc(5px * 3px / 6px)' is valid
   Failed to execute 'registerProperty' on 'CSS': The initial value provided does not parse for the given syntax.
 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/initial-value-unit-arithmetic.html b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/initial-value-unit-arithmetic.html
new file mode 100644
index 0000000..0974e13
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/initial-value-unit-arithmetic.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<title>CSS Properties and Values API: Unit arithmetic in initial value</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api/#dom-css-registerproperty" />
+<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api/#supported-syntax-strings" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/utils.js"></script>
+<script>
+    test_initial_value_valid("<length>", "calc(5px * 3px / 6px)");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/register-property-syntax-parsing.html b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/register-property-syntax-parsing.html
index 793ef21..076eddb8 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/register-property-syntax-parsing.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/register-property-syntax-parsing.html
@@ -4,24 +4,11 @@
 <link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api/#supported-syntax-strings" />
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="./resources/utils.js"></script>
 <script>
-test_count = 0;
 
-function assert_valid(syntax, initialValue) {
-    // No actual assertions, this just shouldn't throw
-    test(function() {
-        var name = '--syntax-test-' + (test_count++);
-        CSS.registerProperty({name: name, syntax: syntax, initialValue: initialValue, inherits: false});
-    }, "syntax:'" + syntax + "', initialValue:'" + initialValue + "' is valid");
-}
-
-function assert_invalid(syntax, initialValue) {
-    test(function(){
-        var name = '--syntax-test-' + (test_count++);
-        assert_throws_dom("SyntaxError",
-            () => CSS.registerProperty({name: name, syntax: syntax, initialValue: initialValue, inherits: false}));
-    }, "syntax:'" + syntax + "', initialValue:'" + initialValue + "' is invalid");
-}
+let assert_valid = test_initial_value_valid;
+let assert_invalid = test_initial_value_invalid;
 
 assert_valid("*", "a");
 assert_valid(" * ", "b");
@@ -47,7 +34,6 @@
 assert_valid("<length>", "10px /*:)*/");
 assert_valid("<length>", " calc(-2px)");
 assert_valid("<length>", "calc(2px*4 + 10px)");
-assert_valid("<length>", "calc(5px * 3px / 6px)");
 assert_valid("<length>", "7.1e-4cm");
 assert_valid("<length>", "calc(7in - 12px)");
 assert_valid("<length>", "calc(15px + (sign(100vh - 10px) * 5px))");
diff --git a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/resources/utils.js b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/resources/utils.js
index a952a4fe..b850e61 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/resources/utils.js
+++ b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/resources/utils.js
@@ -243,3 +243,19 @@
     assert_equals(getComputedStyle(target).getPropertyValue(customProperty), options.to, "Element has the expected final value");
   }, description);
 };
+
+function test_initial_value_valid(syntax, initialValue) {
+    // No actual assertions, this just shouldn't throw
+    test(() => {
+        var name = generate_name();
+        CSS.registerProperty({name: name, syntax: syntax, initialValue: initialValue, inherits: false});
+    }, "syntax:'" + syntax + "', initialValue:'" + initialValue + "' is valid");
+}
+
+function test_initial_value_invalid(syntax, initialValue) {
+    test(() =>{
+        var name = generate_name();
+        assert_throws_dom("SyntaxError",
+            () => CSS.registerProperty({name: name, syntax: syntax, initialValue: initialValue, inherits: false}));
+    }, "syntax:'" + syntax + "', initialValue:'" + initialValue + "' is invalid");
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/subresource-integrity/signatures/tentative/fetch.any.js b/third_party/blink/web_tests/external/wpt/subresource-integrity/signatures/tentative/fetch.any.js
index fc81fcc..4840451 100644
--- a/third_party/blink/web_tests/external/wpt/subresource-integrity/signatures/tentative/fetch.any.js
+++ b/third_party/blink/web_tests/external/wpt/subresource-integrity/signatures/tentative/fetch.any.js
@@ -1,10 +1,5 @@
 // META: global=window,dedicatedworker,sharedworker
-
-// Given `{ digest: "...", body: "...", cors: true, type: "..." }`:
-function resourceURL(data) {
-  let params = new URLSearchParams(data);
-  return "./resource.py?" + params.toString();
-}
+// META: script=helper.js
 
 // A canonically validly signed response, generated using the steps at
 // https://wicg.github.io/signature-based-sri/#examples, relying on the test
@@ -27,19 +22,12 @@
 // {"hello": "world"}
 // ```
 
-// Test key from https://www.rfc-editor.org/rfc/rfc9421.html#name-example-ed25519-test-key.
-const kValidKey   = "JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=";
-
-// A key with the right length that cannot be used to verify the HTTP response
-// above.
-const kInvalidKey = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
-
 // Metadata from the response above:
 const kRequestWithValidSignature = {
   body: `{"hello": "world"}`,
   digest: `sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:`,
   signature: `signature=:TUznBT2ikFq6VrtoZeC5znRtZugu1U8OHJWoBkOLDTJA2FglSR34QY9j+BwN79PT4H0p8aIosnv4rXSKfIZVDA==:`,
-  signatureInput: `signature=("identity-digest";sf);alg="ed25519";keyid="JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=";tag="sri"`
+  signatureInput: `signature=("identity-digest";sf);alg="ed25519";keyid="${kValidKeys['rfc']}";tag="sri"`
 };
 
 // Metadata from the response above, but with an incorrect signature:
@@ -47,83 +35,48 @@
   body: `{"hello": "world"}`,
   digest: `sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:`,
   signature: `signature=:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==:`,
-  signatureInput: `signature=("identity-digest";sf);alg="ed25519";keyid="JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=";tag="sri"`
+  signatureInput: `signature=("identity-digest";sf);alg="ed25519";keyid="${kValidKeys['rfc']}";tag="sri"`
 };
 
-const EXPECT_BLOCKED = "block";
-const EXPECT_LOADED = "loaded";
+generate_fetch_test({}, "", EXPECT_LOADED,
+                    "No signature, no integrity check: loads.");
 
-function generate_test(request_data, integrity, expectation, description) {
-  promise_test(test => {
-    const url = resourceURL(request_data);
-    let options = {};
-    if (integrity != "") {
-      options.integrity = integrity;
-    }
+generate_fetch_test({}, `ed25519-!!!`, EXPECT_LOADED,
+                    "No signature, malformed integrity check: loads.");
 
-    let fetcher = fetch(url, options);
-    if (expectation == EXPECT_LOADED) {
-      return fetcher.then(r => {
-        assert_equals(r.status, 200, "Response status is 200.");
-
-        // Verify `accept-signatures`: if the invalid key is present, both a valid and invalid
-        // key were set. If just the valid key is present, that's the only key we should see
-        // in the header.
-        if (integrity.includes(`ed25519-${kInvalidKey}`)) {
-          assert_equals(r.headers.get('accept-signatures'),
-                        `sig0=("identity-digest";sf);keyid="${kInvalidKey}";tag="sri", sig1=("identity-digest";sf);keyid="${kValidKey}";tag="sri"`,
-                        "`accept-signatures` was set.");
-        } else if (integrity.includes(`ed25519-${kValidKey}`)) {
-          assert_equals(r.headers.get('accept-signatures'),
-                        `sig0=("identity-digest";sf);keyid="${kValidKey}";tag="sri"`,
-                        "`accept-signatures` was set.");
-        }
-      });
-    } else {
-      return promise_rejects_js(test, TypeError, fetcher);
-    }
-  }, description);
-}
-
-generate_test({}, "", EXPECT_LOADED,
-              "No signature, no integrity check: loads.");
-
-generate_test({}, `ed25519-!!!`, EXPECT_LOADED,
-              "No signature, malformed integrity check: loads.");
-
-generate_test({}, `ed25519-${kValidKey}`, EXPECT_BLOCKED,
-              "No signature, valid integrity check: blocked.");
+generate_fetch_test({}, `ed25519-${kValidKeys['rfc']}`, EXPECT_BLOCKED,
+                    "No signature, valid integrity check: blocked.");
 
 // Valid signatures depend upon integrity checks.
-generate_test(kRequestWithValidSignature, "", EXPECT_LOADED,
-              "Valid signature, no integrity check: loads.");
+generate_fetch_test(kRequestWithValidSignature, "", EXPECT_LOADED,
+                    "Valid signature, no integrity check: loads.");
 
-generate_test(kRequestWithValidSignature, "ed25519-???", EXPECT_LOADED,
-              "Valid signature, malformed integrity check: loads.");
+generate_fetch_test(kRequestWithValidSignature, "ed25519-???", EXPECT_LOADED,
+                    "Valid signature, malformed integrity check: loads.");
 
-generate_test(kRequestWithValidSignature, `ed25519-${kValidKey}`, EXPECT_LOADED,
-              "Valid signature, matching integrity check: loads.");
+generate_fetch_test(kRequestWithValidSignature, `ed25519-${kValidKeys['rfc']}`, EXPECT_LOADED,
+                    "Valid signature, matching integrity check: loads.");
 
-generate_test(kRequestWithValidSignature, `ed25519-${kInvalidKey}`, EXPECT_BLOCKED,
-              "Valid signature, mismatched integrity check: blocked.");
+generate_fetch_test(kRequestWithValidSignature, `ed25519-${kInvalidKey}`, EXPECT_BLOCKED,
+                    "Valid signature, mismatched integrity check: blocked.");
 
-generate_test(kRequestWithValidSignature,
-              `ed25519-${kValidKey} ed25519-${kInvalidKey}`, EXPECT_LOADED,
-              "Valid signature, one valid integrity check: loads.");
+generate_fetch_test(kRequestWithValidSignature,
+                    `ed25519-${kValidKeys['rfc']} ed25519-${kInvalidKey}`, EXPECT_LOADED,
+                    "Valid signature, one valid integrity check: loads.");
 
 // Invalid signatures are all blocked.
-generate_test(kRequestWithInvalidSignature, "", EXPECT_BLOCKED,
-              "Invalid signature, no integrity check: blocked.");
+generate_fetch_test(kRequestWithInvalidSignature, "", EXPECT_BLOCKED,
+                    "Invalid signature, no integrity check: blocked.");
 
-generate_test(kRequestWithInvalidSignature, "ed25519-???", EXPECT_BLOCKED,
-              "Invalid signature, malformed integrity check: blocked.");
+generate_fetch_test(kRequestWithInvalidSignature, "ed25519-???", EXPECT_BLOCKED,
+                    "Invalid signature, malformed integrity check: blocked.");
 
-generate_test(kRequestWithInvalidSignature, `ed25519-${kValidKey}`, EXPECT_BLOCKED,
-              "Invalid signature, matching integrity check: blocked.");
+generate_fetch_test(kRequestWithInvalidSignature, `ed25519-${kValidKeys['rfc']}`, EXPECT_BLOCKED,
+                    "Invalid signature, matching integrity check: blocked.");
 
-generate_test(kRequestWithInvalidSignature, `ed25519-${kInvalidKey}`, EXPECT_BLOCKED,
-              "Invalid signature, mismatched integrity check: blocked.");
+generate_fetch_test(kRequestWithInvalidSignature, `ed25519-${kInvalidKey}`, EXPECT_BLOCKED,
+                    "Invalid signature, mismatched integrity check: blocked.");
 
-generate_test(kRequestWithInvalidSignature,
-              `ed25519-${kValidKey} ed25519-${kInvalidKey}`, EXPECT_BLOCKED,
-              "Invalid signature, one valid integrity check: blocked.");
+generate_fetch_test(kRequestWithInvalidSignature,
+                    `ed25519-${kValidKeys['rfc']} ed25519-${kInvalidKey}`, EXPECT_BLOCKED,
+                    "Invalid signature, one valid integrity check: blocked.");
diff --git a/third_party/blink/web_tests/external/wpt/subresource-integrity/signatures/tentative/helper.js b/third_party/blink/web_tests/external/wpt/subresource-integrity/signatures/tentative/helper.js
new file mode 100644
index 0000000..c13c6c4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/subresource-integrity/signatures/tentative/helper.js
@@ -0,0 +1,92 @@
+//
+// Exciting constants we'll use for test cases below:
+//
+const kValidKeys = {
+  // https://www.rfc-editor.org/rfc/rfc9421.html#name-example-ed25519-test-key
+  rfc: "JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=",
+
+  // Randomly generated key:
+  //
+  // {
+  //   "crv": "Ed25519",
+  //   "d": "MTodZiTA9CBsuIvSfO679TThkG3b7ce6R3sq_CdyVp4",
+  //   "ext": true,
+  //   "kty": "OKP",
+  //   "x": "xDnP380zcL4rJ76rXYjeHlfMyPZEOqpJYjsjEppbuXE"
+  // }
+  //
+  arbitrary: "xDnP380zcL4rJ76rXYjeHlfMyPZEOqpJYjsjEppbuXE="
+};
+
+// A key with the right length that cannot be used to verify the HTTP response
+// above.
+const kInvalidKey = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+
+// Generated test expectations are more readable if we're using something
+// other than a boolean.
+const EXPECT_BLOCKED = "block";
+const EXPECT_LOADED = "loaded";
+
+
+// Given `{ digest: "...", body: "...", cors: true, type: "..." }`, generates
+// the URL to a script resource that has the given characteristics.
+let counter = 0;
+function resourceURL(data) {
+  counter++;
+  data.type ??= "application/javascript";
+  data.counter = counter;
+  let params = new URLSearchParams(data);
+  return "./resource.py?" + params.toString();
+}
+
+function generate_fetch_test(request_data, integrity, expectation, description) {
+  promise_test(test => {
+    const url = resourceURL(request_data);
+    let options = {};
+    if (integrity != "") {
+      options.integrity = integrity;
+    }
+
+    let fetcher = fetch(url, options);
+    if (expectation == EXPECT_LOADED) {
+      return fetcher.then(r => {
+        assert_equals(r.status, 200, "Response status is 200.");
+
+        // Verify `accept-signatures`: if the invalid key is present, both a valid and invalid
+        // key were set. If just the valid key is present, that's the only key we should see
+        // in the header.
+        if (integrity.includes(`ed25519-${kInvalidKey}`)) {
+          assert_equals(r.headers.get('accept-signatures'),
+                        `sig0=("identity-digest";sf);keyid="${kInvalidKey}";tag="sri", sig1=("identity-digest";sf);keyid="${kValidKeys['rfc']}";tag="sri"`,
+                        "`accept-signatures` was set.");
+        } else if (integrity.includes(`ed25519-${kValidKeys['rfc']}`)) {
+          assert_equals(r.headers.get('accept-signatures'),
+                        `sig0=("identity-digest";sf);keyid="${kValidKeys['rfc']}";tag="sri"`,
+                        "`accept-signatures` was set.");
+        }
+      });
+    } else {
+      return promise_rejects_js(test, TypeError, fetcher);
+    }
+  }, "`fetch()`: " + description);
+}
+
+function generate_script_test(request_data, integrity, expectation, description) {
+  async_test(t => {
+    let s = document.createElement('script');
+    s.src = resourceURL(request_data);
+    s.integrity = integrity;
+    if (expectation == EXPECT_BLOCKED) {
+      s.onerror = t.step_func_done(e => {
+        assert_equals("error", e.type);
+      });
+      s.onload = t.unreached_func("Script should not execute.");
+    } else {
+      s.onload = t.step_func_done(e => {
+        assert_equals("load", e.type);
+      });
+      s.onerror = t.unreached_func("Script should not fail.");
+    }
+    document.body.appendChild(s);
+  }, "`<script>`: " + description);
+}
diff --git a/third_party/blink/web_tests/external/wpt/subresource-integrity/signatures/tentative/path.window.js b/third_party/blink/web_tests/external/wpt/subresource-integrity/signatures/tentative/path.window.js
new file mode 100644
index 0000000..37a6c04
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/subresource-integrity/signatures/tentative/path.window.js
@@ -0,0 +1,83 @@
+// META: script=helper.js
+
+// The following tests validate the behavior of the `@path` derived component.
+// They'll all be rooted in the following response, generated using the steps at
+// https://wicg.github.io/signature-based-sri/#examples, relying on the test
+// key from https://www.rfc-editor.org/rfc/rfc9421.html#name-example-ed25519-test-key:
+//
+// ```
+// NOTE: '\' line wrapping per RFC 8792
+//
+// HTTP/1.1 200 OK
+// Date: Tue, 20 Apr 2021 02:07:56 GMT
+// Content-Type: application/json
+// Identity-Digest: sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:
+// Content-Length: 18
+// Signature-Input: signature=("identity-digest";sf "@path";req);alg="ed25519"; \
+//                  keyid="JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=";       \
+//                  tag="sri"
+// Signature: signature=:oVQ+s/OqXLAVdfvgZ3HaPiyzkpNXZSit9l6e1FB/gOOL3t8FOrIRDV \
+//                       CkcIEcJjd3MA1mROn39/WQShTmnKmlDg==:
+//
+//
+// {"hello": "world"}
+// ```
+//
+// TODO: When we remove the `tentative` label from the path, we'll need to
+// regenerate the expected signatures below, as the signature base will change.
+
+// Metadata from the response above:
+const kRequestsWithValidSignature = [
+  // `identity-digest` then `@path`, with the following signature base:
+  //
+  // ```
+  // "identity-digest";sf: sha-256=:PZJ+9CdAAIacg7wfUe4t/RkDQJVKM0mCZ2K7qiRhHFc=:
+  // "@path";req: /subresource-integrity/signatures/tentative/resource.py
+  // "@signature-params": ("identity-digest";sf "@path";req);alg="ed25519";keyid="JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=";tag="sri"
+  // ```
+  {
+    body: "window.hello = `world`;",
+    digest: "sha-256=:PZJ+9CdAAIacg7wfUe4t/RkDQJVKM0mCZ2K7qiRhHFc=:",
+    signature: `signature=:AEW2XbDmmBK71KBle0Dx1JAWAO7B4QdEH2Tw71c9nntjUmx8xF5t8xbsETRHFwULrvJ4STBFtdMVm5a7QIw5Cw==:`,
+    signatureInput: `signature=("identity-digest";sf "@path";req);alg="ed25519";keyid="${kValidKeys['rfc']}";tag="sri"`
+  },
+  // `@path` then `identity-digest`, with the following signature base:
+  //
+  // ```
+  // "@path";req: /subresource-integrity/signatures/tentative/resource.py
+  // "identity-digest";sf: sha-256=:PZJ+9CdAAIacg7wfUe4t/RkDQJVKM0mCZ2K7qiRhHFc=:
+  // "@signature-params": ("@path";req "identity-digest";sf);alg="ed25519";keyid="JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=";tag="sri"
+  // ```
+  {
+    body: "window.hello = `world`;",
+    digest: "sha-256=:PZJ+9CdAAIacg7wfUe4t/RkDQJVKM0mCZ2K7qiRhHFc=:",
+    signature: `signature=:NEmnhhW1aKxO+ReWQmmSF17i49ZEdtDC4lRI2CJDw2E/rz9j2a8f8kIwVk7W/BIuQ6kejTAQ2FReGmmkREXPDg==:`,
+    signatureInput: `signature=("@path";req "identity-digest";sf);alg="ed25519";keyid="${kValidKeys['rfc']}";tag="sri"`
+  }
+];
+
+// Valid signatures depend upon integrity checks.
+//
+// We're testing our handling of malformed and multiple keys generally in
+// `fetch.any.js` and `script.window.js`. Here we'll just focus on ensuring
+// that responses with `@path` components load at all (no integrity check),
+// load when integrity checks match, and fail when integrity checks mismatch.
+for (const request of kRequestsWithValidSignature) {
+    // fetch():
+    generate_fetch_test(request, "", EXPECT_LOADED,
+                        `Valid signature (${request.signature}), no integrity check: loads.`);
+
+    generate_fetch_test(request, `ed25519-${kValidKeys['rfc']}`, EXPECT_LOADED,
+                        `Valid signature (${request.signature}), matching integrity check: loads.`);
+
+    generate_fetch_test(request, `ed25519-${kInvalidKey}`, EXPECT_BLOCKED,
+                        `Valid signature (${request.signature}), mismatched integrity check: blocked.`);
+
+    // <script>:
+    generate_script_test(request, "", EXPECT_LOADED,
+                        `Valid signature (${request.signature}), no integrity check: loads.`);
+    generate_script_test(request, `ed25519-${kValidKeys['rfc']}`, EXPECT_LOADED,
+                        `Valid signature (${request.signature}), matching integrity check: loads.`);
+    generate_script_test(request, `ed25519-${kInvalidKey}`, EXPECT_BLOCKED,
+                        `Valid signature (${request.signature}), mismatched integrity check: blocked.`);
+}
diff --git a/third_party/blink/web_tests/external/wpt/subresource-integrity/signatures/tentative/script.window.js b/third_party/blink/web_tests/external/wpt/subresource-integrity/signatures/tentative/script.window.js
index 89f2403..c9ccee3 100644
--- a/third_party/blink/web_tests/external/wpt/subresource-integrity/signatures/tentative/script.window.js
+++ b/third_party/blink/web_tests/external/wpt/subresource-integrity/signatures/tentative/script.window.js
@@ -1,31 +1,10 @@
+// META: script=helper.js
+
 //
 // Validate signature-based SRI's interaction between signed script responses
 // and `<script integrity>` assertions.
 //
 
-//
-// Exciting constants we'll use for test cases below:
-//
-const kValidKeys = {
-  // https://www.rfc-editor.org/rfc/rfc9421.html#name-example-ed25519-test-key
-  rfc: "JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=",
-
-  // Randomly generated key:
-  //
-  // {
-  //   "crv": "Ed25519",
-  //   "d": "MTodZiTA9CBsuIvSfO679TThkG3b7ce6R3sq_CdyVp4",
-  //   "ext": true,
-  //   "kty": "OKP",
-  //   "x": "xDnP380zcL4rJ76rXYjeHlfMyPZEOqpJYjsjEppbuXE"
-  // }
-  //
-  arbitrary: "xDnP380zcL4rJ76rXYjeHlfMyPZEOqpJYjsjEppbuXE="
-};
-
-// A key with the right length that cannot be used to verify the HTTP response
-// above.
-const kInvalidKey = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
 
 const kScriptToExecute = {
   body: "window.hello = `world`;",
@@ -69,49 +48,16 @@
 // Equally exciting helper functions
 //
 
-// Given `{ digest: "...", body: "...", cors: true, type: "..." }`, generates
-// the URL to a script resource that has the given characteristics.
-let counter = 0;
-function resourceURL(data) {
-  counter++;
-  data.type = "application/javascript";
-  data.counter = counter;
-  let params = new URLSearchParams(data);
-  return "./resource.py?" + params.toString();
-}
-
-const EXPECT_BLOCKED = "block";
-const EXPECT_LOADED = "loaded";
-
-function generate_test(request_data, integrity, expectation, description) {
-  async_test(t => {
-    let s = document.createElement('script');
-    s.src = resourceURL(request_data);
-    s.integrity = integrity;
-    if (expectation == EXPECT_BLOCKED) {
-      s.onerror = t.step_func_done(e => {
-        assert_equals("error", e.type);
-      });
-      s.onload = t.unreached_func("Script should not execute.");
-    } else {
-      s.onload = t.step_func_done(e => {
-        assert_equals("load", e.type);
-      });
-      s.onerror = t.unreached_func("Script should not fail.");
-    }
-    document.body.appendChild(s);
-  }, description);
-}
 // Executable: unsigned.
 const kUnsigned = { body: kScriptToExecute['body'] };
-generate_test(kUnsigned, "", EXPECT_LOADED,
-              "No signature, no integrity check: loads.");
+generate_script_test(kUnsigned, "", EXPECT_LOADED,
+                     "No signature, no integrity check: loads.");
 
-generate_test(kUnsigned, "ed25519-???", EXPECT_LOADED,
-              "No signature, malformed integrity check: loads.");
+generate_script_test(kUnsigned, "ed25519-???", EXPECT_LOADED,
+                     "No signature, malformed integrity check: loads.");
 
-generate_test(kUnsigned, `ed25519-${kValidKeys['rfc']}`, EXPECT_BLOCKED,
-              "No signature, valid integrity check: loads.");
+generate_script_test(kUnsigned, `ed25519-${kValidKeys['rfc']}`, EXPECT_BLOCKED,
+                     "No signature, valid integrity check: loads.");
 
 // Executable and non-executable scripts signed with RFC's test key.
 const kSignedShouldExecute = {
@@ -128,18 +74,18 @@
 };
 
 // Should load:
-generate_test(kSignedShouldExecute, "", EXPECT_LOADED,
-              "Valid signature, no integrity check: loads.");
-generate_test(kSignedShouldExecute, "ed25519-???", EXPECT_LOADED,
-              "Valid signature, malformed integrity check: loads.");
-generate_test(kSignedShouldExecute, `ed25519-${kValidKeys['rfc']}`, EXPECT_LOADED,
-              "Valid signature, valid integrity check: loads.");
-generate_test(kSignedShouldExecute, `ed25519-${kValidKeys['rfc']} ed25519-${kValidKeys['arbitrary']}`, EXPECT_LOADED,
-              "Valid signature, one matching integrity check: loads.");
+generate_script_test(kSignedShouldExecute, "", EXPECT_LOADED,
+                     "Valid signature, no integrity check: loads.");
+generate_script_test(kSignedShouldExecute, "ed25519-???", EXPECT_LOADED,
+                     "Valid signature, malformed integrity check: loads.");
+generate_script_test(kSignedShouldExecute, `ed25519-${kValidKeys['rfc']}`, EXPECT_LOADED,
+                     "Valid signature, valid integrity check: loads.");
+generate_script_test(kSignedShouldExecute, `ed25519-${kValidKeys['rfc']} ed25519-${kValidKeys['arbitrary']}`, EXPECT_LOADED,
+                     "Valid signature, one matching integrity check: loads.");
 
 // Should block:
-generate_test(kSignedShouldBlock, `ed25519-${kValidKeys['arbitrary']}`, EXPECT_BLOCKED,
-              "Valid signature, mismatched integrity check: blocked.");
+generate_script_test(kSignedShouldBlock, `ed25519-${kValidKeys['arbitrary']}`, EXPECT_BLOCKED,
+                     "Valid signature, mismatched integrity check: blocked.");
 
 // Executable and non-executable scripts signed with RFC's test key and the arbitrary key:
 const kMultiplySignedShouldExecute = {
@@ -158,17 +104,17 @@
   signature: `signature1=:${kScriptToBlock['signatures']['rfc']}:, ` +
              `signature2=:${kScriptToBlock['signatures']['arbitrary']}:`
 };
-generate_test(kMultiplySignedShouldExecute, "", EXPECT_LOADED,
-              "Valid signatures, no integrity check: loads.");
-generate_test(kMultiplySignedShouldExecute, "ed25519-???", EXPECT_LOADED,
-              "Valid signatures, malformed integrity check: loads.");
-generate_test(kMultiplySignedShouldExecute, `ed25519-${kValidKeys['rfc']}`, EXPECT_LOADED,
-              "Valid signatures, integrity check matches one: loads.");
-generate_test(kMultiplySignedShouldExecute, `ed25519-${kValidKeys['arbitrary']}`, EXPECT_LOADED,
-              "Valid signatures, integrity check matches the other: loads.");
-generate_test(kMultiplySignedShouldExecute, `ed25519-${kValidKeys['rfc']} ed25519-${kValidKeys['arbitrary']}`, EXPECT_LOADED,
-              "Valid signatures, integrity check matches both: loads.");
+generate_script_test(kMultiplySignedShouldExecute, "", EXPECT_LOADED,
+                     "Valid signatures, no integrity check: loads.");
+generate_script_test(kMultiplySignedShouldExecute, "ed25519-???", EXPECT_LOADED,
+                     "Valid signatures, malformed integrity check: loads.");
+generate_script_test(kMultiplySignedShouldExecute, `ed25519-${kValidKeys['rfc']}`, EXPECT_LOADED,
+                     "Valid signatures, integrity check matches one: loads.");
+generate_script_test(kMultiplySignedShouldExecute, `ed25519-${kValidKeys['arbitrary']}`, EXPECT_LOADED,
+                     "Valid signatures, integrity check matches the other: loads.");
+generate_script_test(kMultiplySignedShouldExecute, `ed25519-${kValidKeys['rfc']} ed25519-${kValidKeys['arbitrary']}`, EXPECT_LOADED,
+                     "Valid signatures, integrity check matches both: loads.");
 
 // Should block:
-generate_test(kMultiplySignedShouldBlock, `ed25519-${kInvalidKey}`, EXPECT_BLOCKED,
-              "Valid signatures, integrity check matches neither: blocked.");
+generate_script_test(kMultiplySignedShouldBlock, `ed25519-${kInvalidKey}`, EXPECT_BLOCKED,
+                     "Valid signatures, integrity check matches neither: blocked.");
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-exception-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-exception-expected.txt
index 34b24773..5543707d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-exception-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-uncaught-exception-expected.txt
@@ -12,8 +12,6 @@
     at uncaught-in-iframe.html:13:5
 f @ uncaught-in-iframe.html:11
 (anonymous) @ uncaught-in-iframe.html:13
-load
-(anonymous) @ uncaught-in-iframe.html:2
 uncaught-in-iframe.html:6 Uncaught Error: Exception in setTimeout callback.
     at bar (uncaught-in-iframe.html:6:23)
     at uncaught-in-iframe.html:8:13
@@ -22,6 +20,4 @@
 setTimeout
 f @ uncaught-in-iframe.html:4
 (anonymous) @ uncaught-in-iframe.html:13
-load
-(anonymous) @ uncaught-in-iframe.html:2
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/copy-network-request-expected.txt b/third_party/blink/web_tests/http/tests/devtools/copy-network-request-expected.txt
index 19e0867b..cd29f03 100644
--- a/third_party/blink/web_tests/http/tests/devtools/copy-network-request-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/copy-network-request-expected.txt
Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/shadowrealm/webexposed/global-interface-listing-shadow-realm-expected.txt b/third_party/blink/web_tests/http/tests/shadowrealm/webexposed/global-interface-listing-shadow-realm-expected.txt
index bfd27c4..d68c8e8 100644
--- a/third_party/blink/web_tests/http/tests/shadowrealm/webexposed/global-interface-listing-shadow-realm-expected.txt
+++ b/third_party/blink/web_tests/http/tests/shadowrealm/webexposed/global-interface-listing-shadow-realm-expected.txt
@@ -1,5 +1,180 @@
 CONSOLE MESSAGE: This test logs exposed APIs from ShadowRealmGlobalScope
 CONSOLE MESSAGE: [INTERFACES]
+CONSOLE MESSAGE: interface AbortController
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter signal
+CONSOLE MESSAGE:     method abort
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE: interface AbortSignal : EventTarget
+CONSOLE MESSAGE:     static method abort
+CONSOLE MESSAGE:     static method any
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter aborted
+CONSOLE MESSAGE:     getter onabort
+CONSOLE MESSAGE:     getter reason
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method throwIfAborted
+CONSOLE MESSAGE:     setter onabort
+CONSOLE MESSAGE: interface ByteLengthQueuingStrategy
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter highWaterMark
+CONSOLE MESSAGE:     getter size
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE: interface CountQueuingStrategy
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter highWaterMark
+CONSOLE MESSAGE:     getter size
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE: interface CustomEvent : Event
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter detail
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method initCustomEvent
+CONSOLE MESSAGE: interface DOMException
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     attribute ABORT_ERR
+CONSOLE MESSAGE:     attribute DATA_CLONE_ERR
+CONSOLE MESSAGE:     attribute DOMSTRING_SIZE_ERR
+CONSOLE MESSAGE:     attribute HIERARCHY_REQUEST_ERR
+CONSOLE MESSAGE:     attribute INDEX_SIZE_ERR
+CONSOLE MESSAGE:     attribute INUSE_ATTRIBUTE_ERR
+CONSOLE MESSAGE:     attribute INVALID_ACCESS_ERR
+CONSOLE MESSAGE:     attribute INVALID_CHARACTER_ERR
+CONSOLE MESSAGE:     attribute INVALID_MODIFICATION_ERR
+CONSOLE MESSAGE:     attribute INVALID_NODE_TYPE_ERR
+CONSOLE MESSAGE:     attribute INVALID_STATE_ERR
+CONSOLE MESSAGE:     attribute NAMESPACE_ERR
+CONSOLE MESSAGE:     attribute NETWORK_ERR
+CONSOLE MESSAGE:     attribute NOT_FOUND_ERR
+CONSOLE MESSAGE:     attribute NOT_SUPPORTED_ERR
+CONSOLE MESSAGE:     attribute NO_DATA_ALLOWED_ERR
+CONSOLE MESSAGE:     attribute NO_MODIFICATION_ALLOWED_ERR
+CONSOLE MESSAGE:     attribute QUOTA_EXCEEDED_ERR
+CONSOLE MESSAGE:     attribute SECURITY_ERR
+CONSOLE MESSAGE:     attribute SYNTAX_ERR
+CONSOLE MESSAGE:     attribute TIMEOUT_ERR
+CONSOLE MESSAGE:     attribute TYPE_MISMATCH_ERR
+CONSOLE MESSAGE:     attribute URL_MISMATCH_ERR
+CONSOLE MESSAGE:     attribute VALIDATION_ERR
+CONSOLE MESSAGE:     attribute WRONG_DOCUMENT_ERR
+CONSOLE MESSAGE:     getter code
+CONSOLE MESSAGE:     getter message
+CONSOLE MESSAGE:     getter name
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE: interface ErrorEvent : Event
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter colno
+CONSOLE MESSAGE:     getter error
+CONSOLE MESSAGE:     getter filename
+CONSOLE MESSAGE:     getter lineno
+CONSOLE MESSAGE:     getter message
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE: interface Event
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     attribute AT_TARGET
+CONSOLE MESSAGE:     attribute BUBBLING_PHASE
+CONSOLE MESSAGE:     attribute CAPTURING_PHASE
+CONSOLE MESSAGE:     attribute NONE
+CONSOLE MESSAGE:     getter bubbles
+CONSOLE MESSAGE:     getter cancelBubble
+CONSOLE MESSAGE:     getter cancelable
+CONSOLE MESSAGE:     getter composed
+CONSOLE MESSAGE:     getter currentTarget
+CONSOLE MESSAGE:     getter defaultPrevented
+CONSOLE MESSAGE:     getter eventPhase
+CONSOLE MESSAGE:     getter returnValue
+CONSOLE MESSAGE:     getter srcElement
+CONSOLE MESSAGE:     getter target
+CONSOLE MESSAGE:     getter timeStamp
+CONSOLE MESSAGE:     getter type
+CONSOLE MESSAGE:     method composedPath
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method initEvent
+CONSOLE MESSAGE:     method preventDefault
+CONSOLE MESSAGE:     method stopImmediatePropagation
+CONSOLE MESSAGE:     method stopPropagation
+CONSOLE MESSAGE:     setter cancelBubble
+CONSOLE MESSAGE:     setter returnValue
+CONSOLE MESSAGE: interface EventTarget
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     method addEventListener
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method dispatchEvent
+CONSOLE MESSAGE:     method removeEventListener
+CONSOLE MESSAGE:     method when
+CONSOLE MESSAGE: interface Observable
+CONSOLE MESSAGE:     static method from
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     method catch
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method drop
+CONSOLE MESSAGE:     method every
+CONSOLE MESSAGE:     method filter
+CONSOLE MESSAGE:     method find
+CONSOLE MESSAGE:     method first
+CONSOLE MESSAGE:     method flatMap
+CONSOLE MESSAGE:     method forEach
+CONSOLE MESSAGE:     method inspect
+CONSOLE MESSAGE:     method last
+CONSOLE MESSAGE:     method map
+CONSOLE MESSAGE:     method reduce
+CONSOLE MESSAGE:     method some
+CONSOLE MESSAGE:     method subscribe
+CONSOLE MESSAGE:     method switchMap
+CONSOLE MESSAGE:     method take
+CONSOLE MESSAGE:     method takeUntil
+CONSOLE MESSAGE:     method toArray
+CONSOLE MESSAGE: interface PromiseRejectionEvent : Event
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter promise
+CONSOLE MESSAGE:     getter reason
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE: interface ReadableByteStreamController
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter byobRequest
+CONSOLE MESSAGE:     getter desiredSize
+CONSOLE MESSAGE:     method close
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method enqueue
+CONSOLE MESSAGE:     method error
+CONSOLE MESSAGE: interface ReadableStream
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter locked
+CONSOLE MESSAGE:     method @@asyncIterator
+CONSOLE MESSAGE:     method cancel
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method getReader
+CONSOLE MESSAGE:     method pipeThrough
+CONSOLE MESSAGE:     method pipeTo
+CONSOLE MESSAGE:     method tee
+CONSOLE MESSAGE:     method values
+CONSOLE MESSAGE: interface ReadableStreamBYOBReader
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter closed
+CONSOLE MESSAGE:     method cancel
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method read
+CONSOLE MESSAGE:     method releaseLock
+CONSOLE MESSAGE: interface ReadableStreamBYOBRequest
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter view
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method respond
+CONSOLE MESSAGE:     method respondWithNewView
+CONSOLE MESSAGE: interface ReadableStreamDefaultController
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter desiredSize
+CONSOLE MESSAGE:     method close
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method enqueue
+CONSOLE MESSAGE:     method error
+CONSOLE MESSAGE: interface ReadableStreamDefaultReader
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter closed
+CONSOLE MESSAGE:     method cancel
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method read
+CONSOLE MESSAGE:     method releaseLock
 CONSOLE MESSAGE: interface ShadowRealm
 CONSOLE MESSAGE:     attribute @@toStringTag
 CONSOLE MESSAGE:     method constructor
@@ -8,6 +183,110 @@
 CONSOLE MESSAGE: interface ShadowRealmGlobalScope
 CONSOLE MESSAGE:     attribute @@toStringTag
 CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE: interface Subscriber
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter active
+CONSOLE MESSAGE:     getter signal
+CONSOLE MESSAGE:     method addTeardown
+CONSOLE MESSAGE:     method complete
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method error
+CONSOLE MESSAGE:     method next
+CONSOLE MESSAGE: interface TransformStream
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter readable
+CONSOLE MESSAGE:     getter writable
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE: interface TransformStreamDefaultController
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter desiredSize
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method enqueue
+CONSOLE MESSAGE:     method error
+CONSOLE MESSAGE:     method terminate
+CONSOLE MESSAGE: interface URL
+CONSOLE MESSAGE:     static method canParse
+CONSOLE MESSAGE:     static method parse
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter hash
+CONSOLE MESSAGE:     getter host
+CONSOLE MESSAGE:     getter hostname
+CONSOLE MESSAGE:     getter href
+CONSOLE MESSAGE:     getter origin
+CONSOLE MESSAGE:     getter password
+CONSOLE MESSAGE:     getter pathname
+CONSOLE MESSAGE:     getter port
+CONSOLE MESSAGE:     getter protocol
+CONSOLE MESSAGE:     getter search
+CONSOLE MESSAGE:     getter searchParams
+CONSOLE MESSAGE:     getter username
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method toJSON
+CONSOLE MESSAGE:     method toString
+CONSOLE MESSAGE:     setter hash
+CONSOLE MESSAGE:     setter host
+CONSOLE MESSAGE:     setter hostname
+CONSOLE MESSAGE:     setter href
+CONSOLE MESSAGE:     setter password
+CONSOLE MESSAGE:     setter pathname
+CONSOLE MESSAGE:     setter port
+CONSOLE MESSAGE:     setter protocol
+CONSOLE MESSAGE:     setter search
+CONSOLE MESSAGE:     setter username
+CONSOLE MESSAGE: interface URLPattern
+CONSOLE MESSAGE:     static method compareComponent
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter hasRegExpGroups
+CONSOLE MESSAGE:     getter hash
+CONSOLE MESSAGE:     getter hostname
+CONSOLE MESSAGE:     getter password
+CONSOLE MESSAGE:     getter pathname
+CONSOLE MESSAGE:     getter port
+CONSOLE MESSAGE:     getter protocol
+CONSOLE MESSAGE:     getter search
+CONSOLE MESSAGE:     getter username
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method exec
+CONSOLE MESSAGE:     method test
+CONSOLE MESSAGE: interface URLSearchParams
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter size
+CONSOLE MESSAGE:     method @@iterator
+CONSOLE MESSAGE:     method append
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method delete
+CONSOLE MESSAGE:     method entries
+CONSOLE MESSAGE:     method forEach
+CONSOLE MESSAGE:     method get
+CONSOLE MESSAGE:     method getAll
+CONSOLE MESSAGE:     method has
+CONSOLE MESSAGE:     method keys
+CONSOLE MESSAGE:     method set
+CONSOLE MESSAGE:     method sort
+CONSOLE MESSAGE:     method toString
+CONSOLE MESSAGE:     method values
+CONSOLE MESSAGE: interface WritableStream
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter locked
+CONSOLE MESSAGE:     method abort
+CONSOLE MESSAGE:     method close
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method getWriter
+CONSOLE MESSAGE: interface WritableStreamDefaultController
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter signal
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method error
+CONSOLE MESSAGE: interface WritableStreamDefaultWriter
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter closed
+CONSOLE MESSAGE:     getter desiredSize
+CONSOLE MESSAGE:     getter ready
+CONSOLE MESSAGE:     method abort
+CONSOLE MESSAGE:     method close
+CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE:     method releaseLock
+CONSOLE MESSAGE:     method write
 CONSOLE MESSAGE: [NAMESPACES]
 CONSOLE MESSAGE: namespace console
 CONSOLE MESSAGE:     attribute @@toStringTag
diff --git a/third_party/blink/web_tests/inspector-protocol/debugger/async-stacks-for-load-and-error-events-expected.txt b/third_party/blink/web_tests/inspector-protocol/debugger/async-stacks-for-load-and-error-events-expected.txt
index dbf126d..7c20bc9 100644
--- a/third_party/blink/web_tests/inspector-protocol/debugger/async-stacks-for-load-and-error-events-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/debugger/async-stacks-for-load-and-error-events-expected.txt
@@ -1,10 +1,10 @@
 Tests async stacks for load and error events
 Test load event..
 onScriptLoad at :7:6
---load--
-(anonymous) at test.js:3:11
+--script--
+(anonymous) at test.js:1:26
 Test error event..
 onScriptError at :7:6
---error--
-(anonymous) at test.js:3:11
+--script--
+(anonymous) at test.js:1:22
 
diff --git a/third_party/blink/web_tests/virtual/error-iserror-enabled/README.md b/third_party/blink/web_tests/virtual/error-iserror-enabled/README.md
new file mode 100644
index 0000000..dbfa27d
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/error-iserror-enabled/README.md
@@ -0,0 +1,5 @@
+Error.isError is a Stage 3 TC39 proposal. This test suite is used for any
+tests requiring `--js-error-iserror` until V8 ships the proposal, after which
+this test suite can be removed.
+
+See https://github.com/tc39/proposal-is-error
diff --git a/third_party/blink/web_tests/virtual/error-iserror-enabled/external/wpt/webidl/ecmascript-binding/es-exceptions/DOMException-is-error.any-expected.txt b/third_party/blink/web_tests/virtual/error-iserror-enabled/external/wpt/webidl/ecmascript-binding/es-exceptions/DOMException-is-error.any-expected.txt
new file mode 100644
index 0000000..d2490db
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/error-iserror-enabled/external/wpt/webidl/ecmascript-binding/es-exceptions/DOMException-is-error.any-expected.txt
@@ -0,0 +1,3 @@
+This is a testharness.js-based test.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/error-iserror-enabled/external/wpt/webidl/ecmascript-binding/es-exceptions/DOMException-is-error.any.worker-expected.txt b/third_party/blink/web_tests/virtual/error-iserror-enabled/external/wpt/webidl/ecmascript-binding/es-exceptions/DOMException-is-error.any.worker-expected.txt
new file mode 100644
index 0000000..d2490db
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/error-iserror-enabled/external/wpt/webidl/ecmascript-binding/es-exceptions/DOMException-is-error.any.worker-expected.txt
@@ -0,0 +1,3 @@
+This is a testharness.js-based test.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/webaudio/AudioContext/media-playback-while-not-visible-permission-policy-interrupt-when-hidden.html b/third_party/blink/web_tests/webaudio/AudioContext/media-playback-while-not-visible-permission-policy-interrupt-when-hidden.html
new file mode 100644
index 0000000..e94aae90
--- /dev/null
+++ b/third_party/blink/web_tests/webaudio/AudioContext/media-playback-while-not-visible-permission-policy-interrupt-when-hidden.html
@@ -0,0 +1,177 @@
+<!DOCTYPE html>
+<title>Test the behavior of AudioContext with the media-playback-while-not-rendered permission policy</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<body>
+  <script>
+    // The tests in this file depend on
+    //resources/media-playback-while-not-visible-permission-policy-audiocontext-frame.html
+    internals.settings.setAutoplayPolicy('no-user-gesture-required');
+
+    // Sets up an iframe with an AudioContext with the
+    // media-playback-while-not-visible permission policy disabled, set the
+    // iframe source to
+    // resources/media-playback-while-not-visible-permission-policy-audiocontext-frame.html
+    // and sets the iframe's AudioContext initial state to
+    // `expected_initial_state`.
+    async function setUpIframeAudioContextInitialState(expected_initial_state) {
+      if (document.readyState !=='complete'){
+        await new Promise(resolve => {
+          window.addEventListener('load', resolve)
+        })
+      }
+
+      let iframe = document.createElement('iframe');
+      iframe.id = 'audio-context-frame';
+      iframe.allow = "media-playback-while-not-visible 'none'; autoplay *"
+      iframe.src = 'resources/media-playback-while-not-visible-permission-policy-audiocontext-frame.html';
+      document.body.appendChild(iframe);
+      await new Promise(resolve => {
+        iframe.addEventListener('load', resolve)
+      })
+
+
+      let initial_state = await queryAudioContextState(iframe);
+      if (initial_state === 'closed') {
+        assert_unreached('AudioContext initial state is closed');
+      }
+
+      if (initial_state === expected_initial_state) {
+        return;
+      }
+
+      if (expected_initial_state === 'running') {
+        await sendCommandToAudioContext(iframe, 'resume');
+        assert_equals(await queryAudioContextState(iframe), 'running');
+      } else if (expected_initial_state === 'suspended') {
+        await sendCommandToAudioContext(iframe, 'suspend');
+        assert_equals(await queryAudioContextState(iframe), 'suspended');
+      }
+    }
+
+    // Returns a promise that resolves when the iframe's AudioContext emits a
+    // 'statechange' event. The promise resolves with the new state of the
+    // AudioContext. Moreover, the event listener is removed after the promise
+    // resolves or if the promise times out (after 500ms).
+    function expectIframeAudioContextStateChangeEvent() {
+      return new Promise(resolve => {
+        function expectStateChangeEvent(event) {
+          if (event.data.operation !== 'statechange') {
+            return;
+          }
+          window.removeEventListener('message', expectStateChangeEvent);
+          resolve(event.data.value);
+        }
+
+        window.addEventListener('message', expectStateChangeEvent);
+        setTimeout(() => {
+          window.removeEventListener('message', expectStateChangeEvent);
+          resolve('no state change');
+        }, 500);
+      })
+    }
+
+    // Sends a message to the iframe to query the state of the AudioContext and
+    // returns a promise that resolves with the state of the AudioContext. The
+    // event listener is removed after the promise resolves.
+    function queryAudioContextState(iframe) {
+      return new Promise((resolve, reject) => {
+        window.addEventListener(
+            'message',
+            function expectStateQueryResponse(event) {
+              if (event.data.operation !== 'getState') {
+                return;
+              }
+              window.removeEventListener('message', expectStateQueryResponse);
+              resolve(event.data.value);
+            });
+        iframe.contentWindow.postMessage('getState', '*');
+      })
+    }
+
+    // Sends a message to the iframe with a command that should be performed on
+    // the AudioContext. Returns a promise that resolves when the operation is
+    // completed. The event listener is removed after the promise resolves.
+    function sendCommandToAudioContext(iframe, command) {
+      return new Promise((resolve, reject)  => {
+        window.addEventListener(
+            'message',
+            function expectCommandResponse(event) {
+              if (event.data.operation !== command) {
+                return;
+              }
+              window.removeEventListener('message', expectCommandResponse);
+              resolve();
+            });
+        iframe.contentWindow.postMessage(command, '*');
+      })
+    }
+
+    promise_test(async t => {
+      await setUpIframeAudioContextInitialState('running');
+      let iframe = document.getElementById('audio-context-frame');
+
+      let statechange_promise = expectIframeAudioContextStateChangeEvent();
+      iframe.style.setProperty('display', 'none');
+      assert_equals(await statechange_promise, 'interrupted');
+
+      statechange_promise = expectIframeAudioContextStateChangeEvent();
+      iframe.style.setProperty('display', 'block');
+      assert_equals(await statechange_promise, 'running');
+
+      t.add_cleanup(() => {
+        document.body.removeChild(iframe);
+      });
+    }, 'Hide and show an iframe with a running AudioContext');
+
+    promise_test(async t => {
+      await setUpIframeAudioContextInitialState('suspended');
+      let iframe = document.getElementById('audio-context-frame');
+
+      // No state change should be observed and `timeout_promise` should
+      // resolve first.
+      let statechange_promise = expectIframeAudioContextStateChangeEvent();
+      iframe.style.setProperty('display', 'none');
+      assert_equals(await statechange_promise, 'no state change');
+
+      // Likewise, no state change should be observed and `timeout_promise`
+      // should resolve first.
+      statechange_promise = expectIframeAudioContextStateChangeEvent();
+      iframe.style.setProperty('display', 'block');
+      assert_equals(await statechange_promise, 'no state change');
+
+      t.add_cleanup(() => {
+        document.body.removeChild(iframe);
+      });
+    }, 'Hide and show an iframe with a suspended AudioContext');
+
+    promise_test(async t => {
+      await setUpIframeAudioContextInitialState('suspended');
+      let iframe = document.getElementById('audio-context-frame');
+
+      // No state change should be observed and `timeout_promise` should
+      // resolve first.
+      let statechange_promise = expectIframeAudioContextStateChangeEvent();
+      iframe.style.setProperty('display', 'none');
+      assert_equals(await statechange_promise, 'no state change');
+
+      // Calling resume() on a suspended hidden iframe should throw an
+      // InvalidStateError exception and put the iframe's AudioContext in the
+      // 'interrupted' state.
+      statechange_promise = expectIframeAudioContextStateChangeEvent();
+      resume_audiocontext_promise = sendCommandToAudioContext(iframe, 'resume');
+      assert_equals(await statechange_promise, 'interrupted');
+      await resume_audiocontext_promise
+
+      // Showing the iframe should resume the AudioContext, putting it in the
+      // 'running state'.
+      statechange_promise = expectIframeAudioContextStateChangeEvent();
+      iframe.style.setProperty('display', 'block');
+      assert_equals(await statechange_promise, 'running');
+
+      t.add_cleanup(() => {
+        document.body.removeChild(iframe);
+      });
+    }, 'While the iframe is hidden with a suspended AudioContext, resume the AudioContext');
+  </script>
+</body>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/webaudio/AudioContext/resources/media-playback-while-not-visible-permission-policy-audiocontext-frame.html b/third_party/blink/web_tests/webaudio/AudioContext/resources/media-playback-while-not-visible-permission-policy-audiocontext-frame.html
new file mode 100644
index 0000000..aded5ad5
--- /dev/null
+++ b/third_party/blink/web_tests/webaudio/AudioContext/resources/media-playback-while-not-visible-permission-policy-audiocontext-frame.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <script>
+      // This file is used for the webtest
+      //../media-playback-while-not-visible-permission-policy-interrupt-when-hidden.
+      // This file describes a document that contains an AudioContext and that
+      // can communicate with its embedder by using `postMessage`. The embedder
+      // can send messages to the document to query the state of the
+      // AudioContext, to resume it or to suspend it. Likewise, this document
+      // can send messages to the embedder to notify it of state changes in the
+      // AudioContext.
+      let audioCtx = new AudioContext();
+      audioCtx.addEventListener('statechange', () => {
+        if (window.parent !== window){
+          window.parent.postMessage({
+            operation: 'statechange', value: audioCtx.state
+          }, '*');
+        }
+      });
+
+      window.addEventListener('message', (event) => {
+        if (event.data === 'getState') {
+          window.parent.postMessage({
+            operation: 'getState', value: audioCtx.state
+          }, '*');
+        } else if (event.data === 'resume') {
+          audioCtx.resume()
+          .then(() => {
+            window.parent.postMessage({operation: 'resume', value: null}, '*')
+          }).catch((e) => {
+            window.parent.postMessage({operation: 'resume', value: null}, '*');
+          });
+        } else if (event.data === 'suspend') {
+          audioCtx.suspend().then(() => {
+            window.parent.postMessage({operation: 'suspend', value: null}, '*');
+          });
+        }
+      });
+
+      const oscillator = audioCtx.createOscillator();
+      oscillator.connect(audioCtx.destination);
+      oscillator.start();
+    </script>
+  </body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-overflow/parsing/scroll-markers-computed.tentative.html b/third_party/blink/web_tests/wpt_internal/css/css-overflow/parsing/scroll-markers-computed.tentative.html
deleted file mode 100644
index df297b3..0000000
--- a/third_party/blink/web_tests/wpt_internal/css/css-overflow/parsing/scroll-markers-computed.tentative.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<html>
-
-<head>
-  <meta charset="utf-8">
-  <title>CSS Overflow: scroll-marker-group computed values</title>
-  <link rel="help" href="https://github.com/w3c/csswg-drafts/pull/10243">
-  <script src="/resources/testharness.js"></script>
-  <script src="/resources/testharnessreport.js"></script>
-  <script src="/css/support/computed-testcommon.js"></script>
-</head>
-
-<body>
-  <style>
-    #target { scroll-marker-group: before; }
-  </style>
-  <div id="target"></div>
-  <script>
-    test_computed_value('scroll-marker-group', 'initial', 'none');
-    test_computed_value('scroll-marker-group', 'inherit', 'none');
-    test_computed_value('scroll-marker-group', 'unset', 'none');
-    test_computed_value('scroll-marker-group', 'revert', 'none');
-
-    test_computed_value('scroll-marker-group', 'none');
-    test_computed_value('scroll-marker-group', 'before');
-    test_computed_value('scroll-marker-group', 'after');
-
-    test(() => {
-      let style = getComputedStyle(document.getElementById('target'));
-      assert_not_equals(Array.from(style).indexOf('scroll-marker-group'), -1);
-    }, 'The scroll-marker-group property shows up in CSSStyleDeclaration enumeration');
-
-    test(() => {
-      let style = document.getElementById('target').style;
-      assert_not_equals(style.cssText.indexOf('scroll-marker-group'), -1);
-    }, 'The scroll-marker-group property shows up in CSSStyleDeclaration.cssText');
-
-  </script>
-</body>
-
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-overflow/parsing/scroll-markers-invalid.tentative.html b/third_party/blink/web_tests/wpt_internal/css/css-overflow/parsing/scroll-markers-invalid.tentative.html
deleted file mode 100644
index 641d97d..0000000
--- a/third_party/blink/web_tests/wpt_internal/css/css-overflow/parsing/scroll-markers-invalid.tentative.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<html>
-
-<head>
-  <meta charset="utf-8">
-  <title>CSS Overflow: parsing scroll-marker-group with invalid values</title>
-  <link rel="help" href="https://github.com/w3c/csswg-drafts/pull/10243">
-  <script src="/resources/testharness.js"></script>
-  <script src="/resources/testharnessreport.js"></script>
-  <script src="/css/support/parsing-testcommon.js"></script>
-</head>
-
-<body>
-  <div id="target"></div>
-  <script>
-    test_invalid_value('scroll-marker-group', '10');
-    test_invalid_value('scroll-marker-group', 'true');
-    test_invalid_value('scroll-marker-group', 'default');
-    test_invalid_value('scroll-marker-group', 'set');
-    test_invalid_value('scroll-marker-group', 'before, after');
-  </script>
-</body>
-
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-overflow/parsing/scroll-markers-valid.tentative.html b/third_party/blink/web_tests/wpt_internal/css/css-overflow/parsing/scroll-markers-valid.tentative.html
deleted file mode 100644
index 2856cb8..0000000
--- a/third_party/blink/web_tests/wpt_internal/css/css-overflow/parsing/scroll-markers-valid.tentative.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<html>
-
-<head>
-  <meta charset="utf-8">
-  <title>CSS Overflow: parsing scroll-marker-group with valid values</title>
-  <link rel="help" href="https://github.com/w3c/csswg-drafts/pull/10243">
-  <script src="/resources/testharness.js"></script>
-  <script src="/resources/testharnessreport.js"></script>
-  <script src="/css/support/parsing-testcommon.js"></script>
-</head>
-
-<body>
-  <div id="target"></div>
-  <script>
-    test_valid_value('scroll-marker-group', 'initial');
-    test_valid_value('scroll-marker-group', 'inherit');
-    test_valid_value('scroll-marker-group', 'unset');
-    test_valid_value('scroll-marker-group', 'revert');
-
-    test_valid_value("scroll-marker-group", "none");
-    test_valid_value("scroll-marker-group", "before");
-    test_valid_value("scroll-marker-group", "after");
-  </script>
-</body>
-
-</html>
\ No newline at end of file
diff --git a/third_party/boringssl/src b/third_party/boringssl/src
index f49081b..59fc518 160000
--- a/third_party/boringssl/src
+++ b/third_party/boringssl/src
@@ -1 +1 @@
-Subproject commit f49081b4ef4e99bae452e05170d8433807bd70e9
+Subproject commit 59fc5189630ab1409555647f361ece64930a50ca
diff --git a/third_party/catapult b/third_party/catapult
index 452b85e..abd0e1e 160000
--- a/third_party/catapult
+++ b/third_party/catapult
@@ -1 +1 @@
-Subproject commit 452b85ea51998d34386f3b7f8bd711ba12e5d4b7
+Subproject commit abd0e1e8ccd7f38681b8c9503bbf4c14220c86f3
diff --git a/third_party/chromium-variations b/third_party/chromium-variations
index 57ea908..75345f6 160000
--- a/third_party/chromium-variations
+++ b/third_party/chromium-variations
@@ -1 +1 @@
-Subproject commit 57ea908f6afb7ef24fc1d28158837173a641617d
+Subproject commit 75345f6fdba14f81b63ccf0530c6fb5adfc9a103
diff --git a/third_party/closure_compiler/externs/virtual_keyboard_private.js b/third_party/closure_compiler/externs/virtual_keyboard_private.js
index 8653bb66..b6e5fd8 100644
--- a/third_party/closure_compiler/externs/virtual_keyboard_private.js
+++ b/third_party/closure_compiler/externs/virtual_keyboard_private.js
@@ -151,7 +151,7 @@
 chrome.virtualKeyboardPrivate.getKeyboardConfig = function(callback) {};
 
 /**
- * Opens chrome://os-settings/osLanguages page.
+ * Opens chrome://os-settings/osLanguages/input page.
  */
 chrome.virtualKeyboardPrivate.openSettings = function() {};
 
diff --git a/third_party/crossbench b/third_party/crossbench
index ed3404ed..cdb37ea 160000
--- a/third_party/crossbench
+++ b/third_party/crossbench
@@ -1 +1 @@
-Subproject commit ed3404ed0b31ef20837f60d2aef1e405284e9549
+Subproject commit cdb37eabb31cf3b1723a1692b9762158f197730a
diff --git a/third_party/dawn b/third_party/dawn
index afc9c13..eaeba81 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit afc9c139de7ea3a911171da83ac6922a0089fe34
+Subproject commit eaeba81b24c7b6e0af1b621c3a3479bfb52a1fab
diff --git a/third_party/depot_tools b/third_party/depot_tools
index cbead19..f548b21 160000
--- a/third_party/depot_tools
+++ b/third_party/depot_tools
@@ -1 +1 @@
-Subproject commit cbead190e5a4badb427fda83c7a57868b634511e
+Subproject commit f548b21cd3554d013ac0bc53a6cb1ae0de79e2f8
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index 6551e43..7d0851a 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit 6551e43966d7dd4d085ca6c0fc05a9ef2f3f4176
+Subproject commit 7d0851a8ce15f96e59c8c25fd2b5db32b0475d3d
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index bec79b4..1ce02d5 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-13-3-25-g59320b2d3
-Revision: 59320b2d3c2584ac01914ed0deff64bcc8fb23b2
+Version: VER-2-13-3-26-g38272bf85
+Revision: 38272bf85341348eb0a5162ba4e1c95d370f9bce
 CPEPrefix: cpe:/a:freetype:freetype:2.13.3
 License: FTL
 License File: src/docs/FTL.TXT
diff --git a/third_party/freetype/src b/third_party/freetype/src
index 59320b2..38272bf 160000
--- a/third_party/freetype/src
+++ b/third_party/freetype/src
@@ -1 +1 @@
-Subproject commit 59320b2d3c2584ac01914ed0deff64bcc8fb23b2
+Subproject commit 38272bf85341348eb0a5162ba4e1c95d370f9bce
diff --git a/third_party/libc++abi/src b/third_party/libc++abi/src
index 574b92b..77e59bec 160000
--- a/third_party/libc++abi/src
+++ b/third_party/libc++abi/src
@@ -1 +1 @@
-Subproject commit 574b92bc1d7aa586ed30e4e9923041d1ec495017
+Subproject commit 77e59bec0fb93d9733378e1b6188bae0efdbc32e
diff --git a/third_party/llvm-libc/src b/third_party/llvm-libc/src
index c8307c5..09341da 160000
--- a/third_party/llvm-libc/src
+++ b/third_party/llvm-libc/src
@@ -1 +1 @@
-Subproject commit c8307c52cdf40133e725a3d0912e2fa60ef014b3
+Subproject commit 09341dae519a08cbb4b0c58f5409b722073d2eff
diff --git a/third_party/pdfium b/third_party/pdfium
index bea1014..b69783f 160000
--- a/third_party/pdfium
+++ b/third_party/pdfium
@@ -1 +1 @@
-Subproject commit bea10144d15d4f9f55d78095dcbf931c3d3b2813
+Subproject commit b69783fd189976dd4625c7dcd9c07921b94d4a3c
diff --git a/third_party/perfetto b/third_party/perfetto
index 6361af2..5bf4e2a 160000
--- a/third_party/perfetto
+++ b/third_party/perfetto
@@ -1 +1 @@
-Subproject commit 6361af291ce8ffd1f992fec3f44483c00bba124e
+Subproject commit 5bf4e2a65d76d5a603ff175222d1513f71d28a0b
diff --git a/third_party/skia b/third_party/skia
index 7fc6934..804042d 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 7fc6934b20348e6609552918b9d09da0d6f03457
+Subproject commit 804042d752991d6753dd17f8585d6f8fe951492f
diff --git a/third_party/tflite/src b/third_party/tflite/src
index 3ed58a7..b25df27 160000
--- a/third_party/tflite/src
+++ b/third_party/tflite/src
@@ -1 +1 @@
-Subproject commit 3ed58a749e37e7e45f1771e9c60f0fffbf139d4c
+Subproject commit b25df276c8e912c22f57263ffcae6ca8f4c64342
diff --git a/third_party/webrtc b/third_party/webrtc
index 021cf5a..6ef206a 160000
--- a/third_party/webrtc
+++ b/third_party/webrtc
@@ -1 +1 @@
-Subproject commit 021cf5ac3ef6c5ffd8b65c7365d0f6d7ff456b9c
+Subproject commit 6ef206aa1a92ec09f936105bc19f50ece0ea297b
diff --git a/tools/clang/spanify/Spanifier.cpp b/tools/clang/spanify/Spanifier.cpp
index f14c1095..049a2e03 100644
--- a/tools/clang/spanify/Spanifier.cpp
+++ b/tools/clang/spanify/Spanifier.cpp
@@ -540,7 +540,7 @@
   clang::SourceManager& source_manager = *result.SourceManager;
 
   const auto* array_variable =
-      result.Nodes.getNodeAs<clang::VarDecl>("array_variable");
+      result.Nodes.getNodeAs<clang::VarDecl>("array_variable_rhs");
   const std::string& array_variable_as_string =
       array_variable->getNameAsString();
 
@@ -572,6 +572,7 @@
 
   Node n;
   n.replacement = replacement_directive;
+  n.is_deref_expr = true;
   return n;
 }
 
@@ -1152,6 +1153,12 @@
       return getNodeFromCallToExternalFunction(result);
     }
 
+    if (const auto* sizeof_array_expr =
+            result.Nodes.getNodeAs<clang::UnaryExprOrTypeTraitExpr>(
+                "sizeof_array_expr")) {
+      return getNodeFromSizeOfArrayExpr(sizeof_array_expr, result);
+    }
+
     if (result.Nodes.getNodeAs<clang::VarDecl>("array_variable")) {
       return getNodeFromArrayType(result);
     }
@@ -1167,12 +1174,6 @@
       return getNodeFromPointerTypeLoc(type_loc, result);
     }
 
-    if (const auto* sizeof_array_expr =
-            result.Nodes.getNodeAs<clang::UnaryExprOrTypeTraitExpr>(
-                "sizeof_array_expr")) {
-      return getNodeFromSizeOfArrayExpr(sizeof_array_expr, result);
-    }
-
     if (auto* rhs_array_var =
             result.Nodes.getNodeAs<clang::VarDecl>("array_variable")) {
       return getProxyVarNodeFromArrayVariable(rhs_array_var, result);
@@ -1584,12 +1585,16 @@
             arraySubscriptExpr(hasLHS(declRefExpr(to(array_variable)))))));
     match_finder_.addMatcher(buffer_expr2, &potential_nodes_);
 
+    auto c_style_array_var = varDecl(hasType(arrayType()), unless(exclusions),
+                                     unless(hasExternalFormalLinkage()));
+
     // `sizeof(c_array)` is rewritten to
     // `std_array.size() * sizeof(element_size)`.
-    auto sizeof_array_expr =
-        traverse(clang::TK_IgnoreUnlessSpelledInSource,
-                 sizeOfExpr(has(declRefExpr(to(array_variable))))
-                     .bind("sizeof_array_expr"));
+    auto sizeof_array_expr = traverse(
+        clang::TK_IgnoreUnlessSpelledInSource,
+        sizeOfExpr(
+            has(declRefExpr(to(c_style_array_var.bind("array_variable_rhs")))))
+            .bind("sizeof_array_expr"));
     match_finder_.addMatcher(sizeof_array_expr, &potential_nodes_);
 
     auto deref_expression = traverse(
@@ -1635,8 +1640,7 @@
 
     // When passing c-style arrays to third_party functions as parameters, we
     // need to add `.data()` to extract the pointer and keep things compiling.
-    auto c_style_array_var = varDecl(hasType(arrayType()), unless(exclusions),
-                                     unless(hasExternalFormalLinkage()));
+    //
     // Functions that are annotated with UNSAFE_BUFFER_USAGE also get this
     // treatment because the annotation means it was left there intentionally.
     // And since they emit warnings we can easily find and spanify them later.
diff --git a/tools/clang/spanify/tests/array-external-call-expected.cc b/tools/clang/spanify/tests/array-external-call-expected.cc
index 647efa5..d548ba5d 100644
--- a/tools/clang/spanify/tests/array-external-call-expected.cc
+++ b/tools/clang/spanify/tests/array-external-call-expected.cc
@@ -6,6 +6,7 @@
 #include <cstdint>
 #include <cstring>
 #include <iterator>
+#include <string_view>
 
 void fct() {
   // Expected rewrite:
@@ -57,3 +58,12 @@
   std::ranges::find(data, 'a');
   std::ignore = std::ranges::min(data);
 }
+
+void fct4() {
+  // Adding .data() works for std::string_view rewrites too.
+  // Expected rewrite:
+  // const std::string_view buf = "123456789";
+  const std::string_view buf = "123456789";
+  std::ignore = buf[1];
+  std::ignore = memcmp(buf.data(), "xxx456789", 3);
+}
diff --git a/tools/clang/spanify/tests/array-external-call-original.cc b/tools/clang/spanify/tests/array-external-call-original.cc
index 7d67fa66..b4f589c2c 100644
--- a/tools/clang/spanify/tests/array-external-call-original.cc
+++ b/tools/clang/spanify/tests/array-external-call-original.cc
@@ -56,3 +56,12 @@
   std::ranges::find(data, 'a');
   std::ignore = std::ranges::min(data);
 }
+
+void fct4() {
+  // Adding .data() works for std::string_view rewrites too.
+  // Expected rewrite:
+  // const std::string_view buf = "123456789";
+  const char buf[] = "123456789";
+  std::ignore = buf[1];
+  std::ignore = memcmp(buf, "xxx456789", 3);
+}
diff --git a/tools/clang/spanify/tests/array-tests-expected.cc b/tools/clang/spanify/tests/array-tests-expected.cc
index be2dc30..192ed8df 100644
--- a/tools/clang/spanify/tests/array-tests-expected.cc
+++ b/tools/clang/spanify/tests/array-tests-expected.cc
@@ -4,6 +4,7 @@
 
 #include <array>
 #include <cstdint>
+#include <cstring>
 #include <tuple>
 
 // No rewrite expected.
@@ -90,3 +91,11 @@
   std::ignore = sizeof *buf;
   std::ignore = sizeof buf[0];
 }
+
+// Test for crbug.com/383424943.
+void crbug_383424943() {
+  // No rewrite expected.
+  int buf[]{1};
+  // Using sizeof was causing buf to be rewritten.
+  memset(buf, 'x', sizeof(buf));
+}
diff --git a/tools/clang/spanify/tests/array-tests-original.cc b/tools/clang/spanify/tests/array-tests-original.cc
index 13e8ced..bb800fb 100644
--- a/tools/clang/spanify/tests/array-tests-original.cc
+++ b/tools/clang/spanify/tests/array-tests-original.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <cstdint>
+#include <cstring>
 #include <tuple>
 
 // No rewrite expected.
@@ -89,3 +90,11 @@
   std::ignore = sizeof *buf;
   std::ignore = sizeof buf[0];
 }
+
+// Test for crbug.com/383424943.
+void crbug_383424943() {
+  // No rewrite expected.
+  int buf[]{1};
+  // Using sizeof was causing buf to be rewritten.
+  memset(buf, 'x', sizeof(buf));
+}
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 4fbed86..c58a7bf 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -18222,6 +18222,7 @@
   <int value="-870120067" label="EnableSearchBoxSelection:enabled"/>
   <int value="-870118210" label="AutofillEnableCardBenefitsSync:enabled"/>
   <int value="-869690461" label="ShoppingListTrackByDefault:enabled"/>
+  <int value="-869149210" label="ProjectorUseDVSPlaybackEndpoint:enabled"/>
   <int value="-868138290" label="CrostiniPortForwarding:disabled"/>
   <int value="-868041476" label="OmniboxFocusTriggersSRPZeroSuggest:enabled"/>
   <int value="-867571486" label="PrivateStateTokens:disabled"/>
@@ -18309,6 +18310,7 @@
   <int value="-836123854" label="wallet-service-use-sandbox"/>
   <int value="-835672415" label="PointerEventV1SpecCapturing:disabled"/>
   <int value="-835627918" label="QuickSettingsNetworkRevamp:enabled"/>
+  <int value="-835487878" label="FedCmDelegation:enabled"/>
   <int value="-835331907" label="TabOutlinesInLowContrastThemes:disabled"/>
   <int value="-835242361" label="OmniboxAdaptiveSuggestionsCount:enabled"/>
   <int value="-834661509" label="ModalPermissionPrompts:disabled"/>
@@ -20760,6 +20762,7 @@
   <int value="147342055" label="ChromeHomeClearUrlOnOpen:disabled"/>
   <int value="147373243" label="enable-deferred-image-decoding"/>
   <int value="147645817" label="DnsHttpssvc:enabled"/>
+  <int value="147845068" label="ProjectorUseDVSPlaybackEndpoint:disabled"/>
   <int value="147982046" label="OfflineAutoFetch:enabled"/>
   <int value="148094867" label="IwaKeyDistributionComponent:enabled"/>
   <int value="148142535" label="ShortcutCustomization:disabled"/>
@@ -22260,6 +22263,7 @@
   <int value="743124458" label="OmniboxSuggestionAnswerMigration:disabled"/>
   <int value="743696247" label="RedInterstitialFacelift:enabled"/>
   <int value="743714331" label="HelpAppLauncherSearch:enabled"/>
+  <int value="744050521" label="FedCmDelegation:disabled"/>
   <int value="744050675" label="PrivacySandboxPrivacyGuideAdTopics:disabled"/>
   <int value="744342941" label="SafetyCheckChromeCleanerChild:enabled"/>
   <int value="745541471" label="PaintHolding:disabled"/>
@@ -34232,6 +34236,7 @@
   <int value="267" label="WindowControlsOverlay"/>
   <int value="268" label="FetchPriority"/>
   <int value="269" label="Highlight"/>
+  <int value="270" label="DRAFT_ErrorIsError"/>
 </enum>
 
 <!-- LINT.ThenChange(//third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom:WebDXFeature) -->
diff --git a/tools/metrics/histograms/metadata/accessibility/histograms.xml b/tools/metrics/histograms/metadata/accessibility/histograms.xml
index 2a80bf2..b5c953f 100644
--- a/tools/metrics/histograms/metadata/accessibility/histograms.xml
+++ b/tools/metrics/histograms/metadata/accessibility/histograms.xml
@@ -2119,7 +2119,7 @@
 
 <histogram
     name="Accessibility.Performance.AXObjectCacheImpl.Incremental.{DataType}"
-    units="bytes" expires_after="2025-04-13">
+    units="bytes" expires_after="2025-06-15">
   <owner>kevers@chromium.org</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
@@ -2948,7 +2948,7 @@
 </histogram>
 
 <histogram name="Accessibility.ScreenAI.OCR.Time.PDF" units="ms"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>rhalavati@chromium.org</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index a13ca76..88d2fe1 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -375,7 +375,7 @@
 </histogram>
 
 <histogram name="Android.AdaptiveToolbarButton.Variant.OnPageLoad"
-    enum="AdaptiveToolbarButtonVariant" expires_after="2025-04-13">
+    enum="AdaptiveToolbarButtonVariant" expires_after="2025-06-15">
   <owner>shaktisahu@chromium.org</owner>
   <owner>chrome-segmentation-platform@google.com</owner>
   <summary>
@@ -624,7 +624,7 @@
 </histogram>
 
 <histogram name="Android.BackgroundTaskScheduler.TaskFinished.{TaskType}"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>nyquist@chromium.org</owner>
   <owner>shaktisahu@chromium.org</owner>
   <summary>
@@ -4884,7 +4884,7 @@
 </histogram>
 
 <histogram name="Android.TabMultiSelectV2.BookmarkTabsCount" units="count"
-    expires_after="2025-01-30">
+    expires_after="2025-06-30">
   <owner>ckitagawa@chromium.org</owner>
   <owner>bjfong@google.com</owner>
   <owner>fredmello@chromium.org</owner>
@@ -4896,7 +4896,7 @@
 </histogram>
 
 <histogram name="Android.TabMultiSelectV2.SharingState"
-    enum="TabListEditorShareActionState" expires_after="2025-01-30">
+    enum="TabListEditorShareActionState" expires_after="2025-06-30">
   <owner>ckitagawa@chromium.org</owner>
   <owner>bjfong@google.com</owner>
   <owner>fredmello@chromium.org</owner>
@@ -4907,7 +4907,7 @@
 </histogram>
 
 <histogram name="Android.TabMultiSelectV2.TimeSinceLastShown" units="ms"
-    expires_after="2025-01-30">
+    expires_after="2025-06-30">
   <owner>ckitagawa@chromium.org</owner>
   <owner>fredmello@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index 7474b8f..6fb0288 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -2072,7 +2072,7 @@
 </histogram>
 
 <histogram name="Apps.AppListPlayStoreQueryState"
-    enum="AppListPlayStoreQueryState" expires_after="2025-04-13">
+    enum="AppListPlayStoreQueryState" expires_after="2025-06-15">
   <owner>tby@chromium.org</owner>
   <owner>ypitsishin@google.com</owner>
   <owner>chrome-knowledge-eng@google.com</owner>
@@ -2189,7 +2189,7 @@
 </histogram>
 
 <histogram name="Apps.AppsCountPerInstallReason.{AppType}.{InstallReason}"
-    units="Apps" expires_after="2025-04-13">
+    units="Apps" expires_after="2025-06-15">
   <owner>ovn@google.com</owner>
   <owner>cros-web-apps-team@google.com</owner>
   <component>1389907</component>
@@ -2329,7 +2329,7 @@
 </histogram>
 
 <histogram name="Apps.DefaultAppLaunch{DefaultAppLaunchSource}"
-    enum="DefaultAppName" expires_after="2025-04-13">
+    enum="DefaultAppName" expires_after="2025-06-15">
   <owner>ovn@google.com</owner>
   <owner>cros-web-apps-team@google.com</owner>
   <owner>cros-device-enablement@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml
index cc681f5..64d1ee0 100644
--- a/tools/metrics/histograms/metadata/arc/histograms.xml
+++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -838,7 +838,7 @@
 
 <histogram
     name="Arc.CloudDpc{TimedCloudDpcOp}.TimeDelta{SuccessFailure}{ArcUserTypes}"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>batoon@google.com</owner>
   <owner>mhasank@google.com</owner>
   <owner>arc-commercial@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/ash/enums.xml b/tools/metrics/histograms/metadata/ash/enums.xml
index 40d975f9..c6178fd 100644
--- a/tools/metrics/histograms/metadata/ash/enums.xml
+++ b/tools/metrics/histograms/metadata/ash/enums.xml
@@ -2378,6 +2378,8 @@
   <int value="56" label="Copy Image To Clipboard Action"/>
   <int value="57" label="Capture Mode Text Copied"/>
   <int value="58" label="Coral Saved Groups Limit Max"/>
+  <int value="59" label="Scanner Action Success"/>
+  <int value="60" label="Scanner Action Failure"/>
 </enum>
 
 <enum name="TogglePickerAction">
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 9e2ca2e..62762ee7 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -6838,7 +6838,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.DeskBarInitLatency" units="ms"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>esum@google.com</owner>
   <owner>cros-sw-perf@google.com</owner>
   <summary>
@@ -8950,7 +8950,7 @@
 </histogram>
 
 <histogram name="Ash.Smoothness.PercentDroppedFrames_1sWindow2{Stage}"
-    units="%" expires_after="2025-04-13">
+    units="%" expires_after="2025-06-15">
   <owner>xiyuan@chromium.org</owner>
   <owner>cros-sw-perf@google.com</owner>
   <summary>
@@ -10074,7 +10074,7 @@
 </histogram>
 
 <histogram name="Ash.Wallpaper.Type" enum="WallpaperType"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>kuscher@google.com</owner>
   <owner>cros-p13n-eng@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/attribution_reporting/histograms.xml b/tools/metrics/histograms/metadata/attribution_reporting/histograms.xml
index feb9d620..637d13cc 100644
--- a/tools/metrics/histograms/metadata/attribution_reporting/histograms.xml
+++ b/tools/metrics/histograms/metadata/attribution_reporting/histograms.xml
@@ -1576,7 +1576,7 @@
 </histogram>
 
 <histogram name="Conversions.{ReportType}.ReportRetriesTillSuccessOrFailure"
-    enum="ConversionReportSendRetryCount" expires_after="2025-04-13">
+    enum="ConversionReportSendRetryCount" expires_after="2025-06-15">
   <owner>tquintanilla@chromium.org</owner>
   <owner>johnidel@chromium.org</owner>
   <owner>measurement-api-dev+metrics@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml
index 2e76a181..3614933 100644
--- a/tools/metrics/histograms/metadata/autofill/histograms.xml
+++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -794,7 +794,7 @@
 </histogram>
 
 <histogram name="Autofill.AddressesSuppressedForDisuse" units="addresses"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>battre@chromium.org</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -819,7 +819,7 @@
 </histogram>
 
 <histogram name="Autofill.AddressProfileImportRequirements"
-    enum="AutofillAddressProfileImportRequirement" expires_after="2025-04-13">
+    enum="AutofillAddressProfileImportRequirement" expires_after="2025-06-15">
   <owner>koerber@google.com</owner>
   <owner>battre@chromium.org</owner>
   <summary>
@@ -2291,7 +2291,7 @@
 </histogram>
 
 <histogram name="Autofill.EditedAutofilledFieldAtSubmission2.Aggregate"
-    enum="AutofilledFieldUserEditingStatus" expires_after="2025-04-13">
+    enum="AutofilledFieldUserEditingStatus" expires_after="2025-06-15">
   <owner>koerber@google.com</owner>
   <owner>battre@google.com</owner>
   <summary>
@@ -2303,7 +2303,7 @@
 
 <histogram name="Autofill.EditedAutofilledFieldAtSubmission2.ByFieldType"
     enum="AutofilledFieldUserEditingStatusByFieldType"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>koerber@google.com</owner>
   <owner>battre@google.com</owner>
   <summary>
@@ -2570,7 +2570,7 @@
 
 <histogram
     name="Autofill.FieldPredictionQuality.Aggregate{AutofillFieldPredictionSource}"
-    enum="AutofillFieldPredictionQuality" expires_after="2025-04-13">
+    enum="AutofillFieldPredictionQuality" expires_after="2025-06-15">
   <owner>battre@chromium.org</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -2586,7 +2586,7 @@
 
 <histogram
     name="Autofill.FieldPredictionQuality.ByFieldType{AutofillFieldPredictionSource}"
-    enum="AutofillFieldPredictionQualityByFieldType" expires_after="2025-04-13">
+    enum="AutofillFieldPredictionQualityByFieldType" expires_after="2025-06-15">
   <owner>battre@chromium.org</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -2742,7 +2742,7 @@
 </histogram>
 
 <histogram name="Autofill.FormEvents.{AddressFormType}"
-    enum="AutofillFormEvent" expires_after="2025-04-13">
+    enum="AutofillFormEvent" expires_after="2025-06-15">
   <owner>battre@chromium.org</owner>
   <owner>koerber@google.com</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
@@ -2979,7 +2979,7 @@
 </histogram>
 
 <histogram name="Autofill.Funnel.FillAfterSuggestion.{FormType}"
-    enum="BooleanAutofillFillAfterSuggestion" expires_after="2025-04-13">
+    enum="BooleanAutofillFillAfterSuggestion" expires_after="2025-06-15">
   <owner>battre@chromium.org</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -3073,7 +3073,7 @@
 </histogram>
 
 <histogram name="Autofill.Funnel.SuggestionAfterInteraction.{FormType}"
-    enum="BooleanAutofillSuggestionAfterInteraction" expires_after="2025-04-13">
+    enum="BooleanAutofillSuggestionAfterInteraction" expires_after="2025-06-15">
   <owner>battre@chromium.org</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -3366,7 +3366,7 @@
 </histogram>
 
 <histogram name="Autofill.KeyMetrics.FillingAcceptance.{FormType}"
-    enum="BooleanAutofillFillingAcceptance" expires_after="2025-04-13">
+    enum="BooleanAutofillFillingAcceptance" expires_after="2025-06-15">
   <owner>battre@chromium.org</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -3379,7 +3379,7 @@
 </histogram>
 
 <histogram name="Autofill.KeyMetrics.FillingAssistance.{FormType}"
-    enum="BooleanAutofillFillingAssistance" expires_after="2025-04-13">
+    enum="BooleanAutofillFillingAssistance" expires_after="2025-06-15">
   <owner>battre@chromium.org</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -3395,7 +3395,7 @@
 </histogram>
 
 <histogram name="Autofill.KeyMetrics.FillingCorrectness.{FormType}"
-    enum="BooleanAutofillFillingCorrectness" expires_after="2025-04-13">
+    enum="BooleanAutofillFillingCorrectness" expires_after="2025-06-15">
   <owner>battre@chromium.org</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -3406,7 +3406,7 @@
 </histogram>
 
 <histogram name="Autofill.KeyMetrics.FillingReadiness.{FormType}"
-    enum="BooleanAutofillFillingReadiness" expires_after="2025-04-13">
+    enum="BooleanAutofillFillingReadiness" expires_after="2025-06-15">
   <owner>battre@chromium.org</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -3421,7 +3421,7 @@
 </histogram>
 
 <histogram name="Autofill.KeyMetrics.FormSubmission.Autofilled.{FormType}"
-    enum="BooleanAutofillSubmission" expires_after="2025-04-13">
+    enum="BooleanAutofillSubmission" expires_after="2025-06-15">
   <owner>battre@chromium.org</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -3437,7 +3437,7 @@
 </histogram>
 
 <histogram name="Autofill.KeyMetrics.FormSubmission.NotAutofilled.{FormType}"
-    enum="BooleanAutofillSubmission" expires_after="2025-04-13">
+    enum="BooleanAutofillSubmission" expires_after="2025-06-15">
   <owner>battre@chromium.org</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -5217,7 +5217,7 @@
 </histogram>
 
 <histogram name="Autofill.ScanCreditCard.Completed" enum="BooleanCompleted"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>battre@chromium.org</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>Whether a credit card scan was completed or cancelled.</summary>
@@ -5238,7 +5238,7 @@
 </histogram>
 
 <histogram name="Autofill.ScanCreditCardPrompt"
-    enum="AutofillScanCreditCardPrompt" expires_after="2025-04-13">
+    enum="AutofillScanCreditCardPrompt" expires_after="2025-06-15">
   <owner>battre@chromium.org</owner>
   <owner>koerber@chromium.org</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
@@ -6919,7 +6919,7 @@
 </histogram>
 
 <histogram name="Autofill.WebView.AutofillSession" enum="AutofillSessionStates"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>battre@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>Records the state of an autofill session.</summary>
@@ -7104,7 +7104,7 @@
 </histogram>
 
 <histogram name="Autofill.WebView.PrefillRequestState"
-    enum="AndroidAutofillPrefillRequestState" expires_after="2025-04-13">
+    enum="AndroidAutofillPrefillRequestState" expires_after="2025-06-15">
   <owner>jkeitel@google.com</owner>
   <owner>jihadghanna@google.com</owner>
   <owner>elabadysayed@chromium.org</owner>
@@ -7162,7 +7162,7 @@
 </histogram>
 
 <histogram name="Autofill.WebView.SubmissionSource"
-    enum="AutofillSubmissionSource" expires_after="2025-04-13">
+    enum="AutofillSubmissionSource" expires_after="2025-06-15">
   <owner>battre@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>Records the source of form submission.</summary>
diff --git a/tools/metrics/histograms/metadata/blink/histograms.xml b/tools/metrics/histograms/metadata/blink/histograms.xml
index ba7cea8..61fd1b6 100644
--- a/tools/metrics/histograms/metadata/blink/histograms.xml
+++ b/tools/metrics/histograms/metadata/blink/histograms.xml
@@ -661,7 +661,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.CompositingCommit.UpdateTime"
-    units="microseconds" expires_after="2025-04-13">
+    units="microseconds" expires_after="2025-06-15">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -2341,7 +2341,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.ForcedStyleAndLayout.UpdateTime"
-    units="microseconds" expires_after="2025-04-13">
+    units="microseconds" expires_after="2025-06-15">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -2835,7 +2835,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.IntersectionObservation.UpdateTime"
-    units="microseconds" expires_after="2025-04-13">
+    units="microseconds" expires_after="2025-06-15">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -2955,7 +2955,7 @@
 
 <histogram
     name="Blink.Layout.InlineNode.ShapeText.TotalTime.InOutermostMainFrame3"
-    units="microseconds" expires_after="2025-04-13">
+    units="microseconds" expires_after="2025-06-15">
   <owner>chikamune@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -2969,18 +2969,8 @@
   </summary>
 </histogram>
 
-<histogram name="Blink.Layout.RebuildFragmentTreeSpine" units="microseconds"
-    expires_after="2025-01-26">
-  <owner>tkent@chromium.org</owner>
-  <owner>layout-dev@chromium.org</owner>
-  <summary>
-    Time spent to rebuild container physical fragments, recorded on sub-tree
-    root layout.
-  </summary>
-</histogram>
-
 <histogram name="Blink.Layout.SVGImage.Count.InOutermostMainFrame"
-    units="count" expires_after="2025-01-26">
+    units="count" expires_after="2025-12-01">
   <owner>chikamune@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -3024,7 +3014,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.Layout.UpdateTime" units="microseconds"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -3203,7 +3193,7 @@
 </histogram>
 
 <histogram name="Blink.LCPP.LCPElementLocatorSize" units="bytes"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>kouhei@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -3687,7 +3677,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.MainFrame.UpdateTime" units="microseconds"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -3946,7 +3936,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.Paint.UpdateTime" units="microseconds"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -4667,7 +4657,7 @@
 </histogram>
 
 <histogram name="Blink.UpdateViewportIntersection.UpdateTime"
-    units="microseconds" expires_after="2025-04-13">
+    units="microseconds" expires_after="2025-06-15">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/bookmarks/histograms.xml b/tools/metrics/histograms/metadata/bookmarks/histograms.xml
index 025091b..1df27b9e 100644
--- a/tools/metrics/histograms/metadata/bookmarks/histograms.xml
+++ b/tools/metrics/histograms/metadata/bookmarks/histograms.xml
@@ -260,7 +260,7 @@
 </histogram>
 
 <histogram name="Bookmarks.IdsReassigned.OnProfileLoad{BookmarksFileType}"
-    enum="BooleanReassigned" expires_after="2025-04-13">
+    enum="BooleanReassigned" expires_after="2025-06-15">
   <owner>mastiz@chromium.org</owner>
   <owner>arthurmilchior@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/browser/histograms.xml b/tools/metrics/histograms/metadata/browser/histograms.xml
index 96fdc015..1f1ddaa2 100644
--- a/tools/metrics/histograms/metadata/browser/histograms.xml
+++ b/tools/metrics/histograms/metadata/browser/histograms.xml
@@ -651,7 +651,7 @@
 </histogram>
 
 <histogram name="Browser.MainThreadsCongestion{UsageScenario}" units="janks"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>pmonette@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -994,7 +994,7 @@
 </histogram>
 
 <histogram name="Browser.Tabs.TabSwitchResult3{TabSwitchingType}"
-    enum="TabSwitchResult2" expires_after="2025-04-13">
+    enum="TabSwitchResult2" expires_after="2025-06-15">
   <owner>fdoray@chromium.org</owner>
   <owner>joenotcharles@google.com</owner>
   <owner>catan-team@chromium.org</owner>
@@ -1020,7 +1020,7 @@
 </histogram>
 
 <histogram name="Browser.Tabs.TotalSwitchDuration3{TabSwitchingType}"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>jonross@chromium.org</owner>
   <owner>joenotcharles@google.com</owner>
   <owner>catan-team@chromium.org</owner>
@@ -1034,7 +1034,7 @@
 </histogram>
 
 <histogram name="Browser.WindowCount.Guest" units="units"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>rhalavati@chromium.org</owner>
   <owner>chrome-privacy-core@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/chrome/histograms.xml b/tools/metrics/histograms/metadata/chrome/histograms.xml
index 3ad1c1f..ff9876c 100644
--- a/tools/metrics/histograms/metadata/chrome/histograms.xml
+++ b/tools/metrics/histograms/metadata/chrome/histograms.xml
@@ -358,7 +358,7 @@
 </histogram>
 
 <histogram name="ChromeColors.ColorType" enum="ChromeColorType"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/chromeos/histograms.xml b/tools/metrics/histograms/metadata/chromeos/histograms.xml
index a0b4f98..3dcee3c4 100644
--- a/tools/metrics/histograms/metadata/chromeos/histograms.xml
+++ b/tools/metrics/histograms/metadata/chromeos/histograms.xml
@@ -1706,7 +1706,7 @@
 </histogram>
 
 <histogram name="ChromeOS.HardwareVerifier.Report.IsCompliant" enum="Boolean"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>itspeter@chromium.org</owner>
   <owner>stimim@chromium.org</owner>
   <owner>chromeos-runtime-probe@google.com</owner>
@@ -1714,7 +1714,7 @@
 </histogram>
 
 <histogram name="ChromeOS.HardwareVerifier.TimeToFinish" units="ms"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>itspeter@chromium.org</owner>
   <owner>stimim@chromium.org</owner>
   <owner>chromeos-runtime-probe@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/commerce/histograms.xml b/tools/metrics/histograms/metadata/commerce/histograms.xml
index 61f72191..f3415ca 100644
--- a/tools/metrics/histograms/metadata/commerce/histograms.xml
+++ b/tools/metrics/histograms/metadata/commerce/histograms.xml
@@ -875,7 +875,7 @@
 </histogram>
 
 <histogram name="Commerce.Subscriptions.TrackResult"
-    enum="ShoppingSubscriptionsRequestStatus" expires_after="2025-04-13">
+    enum="ShoppingSubscriptionsRequestStatus" expires_after="2025-06-15">
   <owner>mdjones@chromium.org</owner>
   <owner>ayman@chromium.org</owner>
   <owner>chrome-shopping@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/cookie/histograms.xml b/tools/metrics/histograms/metadata/cookie/histograms.xml
index f852fee..f0e3a31d 100644
--- a/tools/metrics/histograms/metadata/cookie/histograms.xml
+++ b/tools/metrics/histograms/metadata/cookie/histograms.xml
@@ -632,7 +632,7 @@
 </histogram>
 
 <histogram name="Cookie.LoadProblem" enum="CookieLoadProblem"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>morlovich@chromium.org</owner>
   <owner>src/net/cookies/OWNERS</owner>
   <summary>
@@ -1073,7 +1073,7 @@
 </histogram>
 
 <histogram name="Cookie.TimeBlockedOnLoad" units="ms"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>wfh@chromium.org</owner>
   <summary>
     The amount of time (ms) between the cookie store load starting and
diff --git a/tools/metrics/histograms/metadata/cras/histograms.xml b/tools/metrics/histograms/metadata/cras/histograms.xml
index 012dd11..c889c380 100644
--- a/tools/metrics/histograms/metadata/cras/histograms.xml
+++ b/tools/metrics/histograms/metadata/cras/histograms.xml
@@ -178,7 +178,7 @@
   </summary>
 </histogram>
 
-<histogram name="Cras.BusyloopLength" units="units" expires_after="2025-04-13">
+<histogram name="Cras.BusyloopLength" units="units" expires_after="2025-06-15">
   <owner>yuhsuan@chromium.org</owner>
   <owner>chromeos-audio@google.com</owner>
   <summary>
@@ -639,7 +639,7 @@
 </histogram>
 
 <histogram name="Cras.InternalSoundcardStatus{Second}"
-    enum="InternalSoundcardStatus" expires_after="2025-04-13">
+    enum="InternalSoundcardStatus" expires_after="2025-06-15">
   <owner>yuhsuan@chromium.org</owner>
   <owner>chromeos-audio@google.com</owner>
   <summary>
@@ -977,7 +977,7 @@
 </histogram>
 
 <histogram name="Cras.StreamConnectStatus" enum="CrasStreamConnectStatus"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>yuhsuan@chromium.org</owner>
   <owner>hychao@chromium.org</owner>
   <owner>chromeos-audio@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/cros_federated/histograms.xml b/tools/metrics/histograms/metadata/cros_federated/histograms.xml
index 8644127..44c07fb2 100644
--- a/tools/metrics/histograms/metadata/cros_federated/histograms.xml
+++ b/tools/metrics/histograms/metadata/cros_federated/histograms.xml
@@ -42,7 +42,7 @@
 </histogram>
 
 <histogram name="FederatedService.StorageEvent" enum="FederatedStorageEvent"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>alanlxl@chromium.org</owner>
   <owner>amoylan@chromium.org</owner>
   <owner>cros-federated-team@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/event/histograms.xml b/tools/metrics/histograms/metadata/event/histograms.xml
index 54ad9d9c..18ff5f5 100644
--- a/tools/metrics/histograms/metadata/event/histograms.xml
+++ b/tools/metrics/histograms/metadata/event/histograms.xml
@@ -610,7 +610,7 @@
 </histogram>
 
 <histogram name="Event.ScrollJank.MissedVsyncs{Operator}.FixedWindow2"
-    units="counts" expires_after="2025-04-13">
+    units="counts" expires_after="2025-06-15">
   <owner>jonross@chromium.org</owner>
   <owner>woa-performance-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml
index 9b337de..27d5910 100644
--- a/tools/metrics/histograms/metadata/extensions/histograms.xml
+++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -245,7 +245,7 @@
 </histogram>
 
 <histogram name="Extensions.ActiveScriptController.DeniedExtensions"
-    units="Extension Count" expires_after="2025-04-13">
+    units="Extension Count" expires_after="2025-06-15">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
@@ -1215,7 +1215,7 @@
 </histogram>
 
 <histogram name="Extensions.DeclarativeNetRequest.RequestHeaderChanged"
-    enum="WebRequest.RequestHeader" expires_after="2024-12-22">
+    enum="WebRequest.RequestHeader" expires_after="2025-12-01">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>kelvinjiang@chromium.org</owner>
   <owner>src/extensions/OWNERS</owner>
@@ -1227,7 +1227,7 @@
 </histogram>
 
 <histogram name="Extensions.DeclarativeNetRequest.RequestHeaderRemoved"
-    enum="WebRequest.RequestHeader" expires_after="2024-12-12">
+    enum="WebRequest.RequestHeader" expires_after="2025-12-01">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>kelvinjiang@chromium.org</owner>
   <owner>src/extensions/OWNERS</owner>
@@ -1239,7 +1239,7 @@
 </histogram>
 
 <histogram name="Extensions.DeclarativeNetRequest.ResponseHeaderAdded"
-    enum="WebRequest.ResponseHeader" expires_after="2024-12-22">
+    enum="WebRequest.ResponseHeader" expires_after="2025-12-01">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>kelvinjiang@chromium.org</owner>
   <owner>src/extensions/OWNERS</owner>
@@ -1251,7 +1251,7 @@
 </histogram>
 
 <histogram name="Extensions.DeclarativeNetRequest.ResponseHeaderChanged"
-    enum="WebRequest.ResponseHeader" expires_after="2024-12-22">
+    enum="WebRequest.ResponseHeader" expires_after="2025-12-01">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>kelvinjiang@chromium.org</owner>
   <owner>src/extensions/OWNERS</owner>
@@ -1263,7 +1263,7 @@
 </histogram>
 
 <histogram name="Extensions.DeclarativeNetRequest.ResponseHeaderRemoved"
-    enum="WebRequest.ResponseHeader" expires_after="2024-12-22">
+    enum="WebRequest.ResponseHeader" expires_after="2025-12-01">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>kelvinjiang@chromium.org</owner>
   <owner>src/extensions/OWNERS</owner>
@@ -4142,7 +4142,7 @@
 </histogram>
 
 <histogram name="Extensions.NewTabPageOverrides2" units="units"
-    expires_after="2024-09-15">
+    expires_after="2025-12-01">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>kelvinjiang@chromium.org</owner>
   <summary>
@@ -4637,7 +4637,7 @@
 
 <histogram
     name="Extensions.ServiceWorkerBackground.ProcessManagerFinishedExternalRequestResultWithSuccessfulStart"
-    enum="ServiceWorkerExternalRequestResult" expires_after="2024-10-06">
+    enum="ServiceWorkerExternalRequestResult" expires_after="2025-12-01">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
@@ -4651,7 +4651,7 @@
 
 <histogram
     name="Extensions.ServiceWorkerBackground.ProcessManagerFinishedExternalRequestResultWithUnsuccessfulStart"
-    enum="ServiceWorkerExternalRequestResult" expires_after="2024-10-06">
+    enum="ServiceWorkerExternalRequestResult" expires_after="2025-12-01">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/facilitated_payments/histograms.xml b/tools/metrics/histograms/metadata/facilitated_payments/histograms.xml
index c6b43a0..256ea36 100644
--- a/tools/metrics/histograms/metadata/facilitated_payments/histograms.xml
+++ b/tools/metrics/histograms/metadata/facilitated_payments/histograms.xml
@@ -42,6 +42,23 @@
 </variants>
 
 <histogram
+    name="FacilitatedPayments.Ewallet.GetClientToken.{Result}.Latency.{Scheme}"
+    units="ms" expires_after="2025-07-01">
+  <owner>junhuihe@google.com</owner>
+  <owner>qihuizhao@google.com</owner>
+  <owner>rouslan@google.com</owner>
+  <owner>payments-autofill-team@google.com</owner>
+  <summary>
+    Latency for the call to fetch the client token. The client token is fetched
+    from the platform specific payment library in preparation for facilitating
+    the payment using Google Pay. Logged when an eWallet payflow is triggered.
+    {Result} is the token fetch result. The payment is supported by {Scheme}.
+  </summary>
+  <token key="Result" variants="BooleanResult"/>
+  <token key="Scheme" variants="EwalletScheme"/>
+</histogram>
+
+<histogram
     name="FacilitatedPayments.Ewallet.InitiatePayment.{Result}.Latency.{Scheme}"
     units="ms" expires_after="2025-07-01">
   <owner>junhuihe@google.com</owner>
@@ -122,22 +139,6 @@
   </summary>
 </histogram>
 
-<histogram name="FacilitatedPayments.Pix.GetClientToken.{Result}.Latency"
-    units="ms" expires_after="2025-07-01">
-  <owner>siashah@google.com</owner>
-  <owner>vishwasuppoor@google.com</owner>
-  <owner>rouslan@google.com</owner>
-  <owner>payments-autofill-team@google.com</owner>
-  <summary>
-    Latency for the call to fetch the client token. The client token is fetched
-    from the platform specific payment library in preparation for facilitating
-    the payment using Google Pay. {Result} is the token fetch result.
-    [Frequency] Logged at most once per Pix payflow. [Trigger] Page is loaded
-    and the main frame contains a valid payment code for Pix.
-  </summary>
-  <token key="Result" variants="BooleanResult"/>
-</histogram>
-
 <histogram name="FacilitatedPayments.Pix.InitiatePayment.Attempt"
     enum="BooleanAttempted" expires_after="2025-07-01">
   <owner>siashah@google.com</owner>
@@ -291,6 +292,25 @@
 </histogram>
 
 <histogram
+    name="FacilitatedPayments.{FacilitatedPaymentsType}.GetClientToken.{Result}.Latency"
+    units="ms" expires_after="2025-07-01">
+  <owner>siashah@google.com</owner>
+  <owner>vishwasuppoor@google.com</owner>
+  <owner>rouslan@google.com</owner>
+  <owner>payments-autofill-team@google.com</owner>
+  <summary>
+    Latency for the call to fetch the client token. The client token is fetched
+    from the platform specific payment library in preparation for facilitating
+    the payment using Google Pay. {Result} is the token fetch result.
+    [Frequency] Logged at most once per {FacilitatedPaymentsType} payflow.
+    [Trigger] Page is loaded and the main frame contains a valid payment code
+    for {FacilitatedPaymentsType}.
+  </summary>
+  <token key="FacilitatedPaymentsType" variants="FacilitatedPaymentsTypes"/>
+  <token key="Result" variants="BooleanResult"/>
+</histogram>
+
+<histogram
     name="FacilitatedPayments.{FacilitatedPaymentsType}.InitiatePayment.{Result}.Latency"
     units="ms" expires_after="2025-07-01">
   <owner>siashah@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
index 38506dcc6..bc415824 100644
--- a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
+++ b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
@@ -659,7 +659,7 @@
 </histogram>
 
 <histogram name="InProductHelp.DismissalReason.iOS"
-    enum="InProductHelpDismissalReason" expires_after="2025-04-13">
+    enum="InProductHelpDismissalReason" expires_after="2025-06-15">
   <owner>lpromero@google.com</owner>
   <owner>gambard@chromium.org</owner>
   <summary>
@@ -668,7 +668,7 @@
 </histogram>
 
 <histogram name="InProductHelp.Gestural.DismissalReason.iOS"
-    enum="InProductHelpDismissalReason" expires_after="2025-04-13">
+    enum="InProductHelpDismissalReason" expires_after="2025-06-15">
   <owner>ginnyhuang@chromium.org</owner>
   <owner>adamta@google.com</owner>
   <summary>
@@ -700,7 +700,7 @@
 </histogram>
 
 <histogram name="InProductHelp.ShownTime.{IPHFeature}" units="ms"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>lpromero@google.com</owner>
   <owner>gambard@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/gpu/histograms.xml b/tools/metrics/histograms/metadata/gpu/histograms.xml
index 293cace..fee3192e 100644
--- a/tools/metrics/histograms/metadata/gpu/histograms.xml
+++ b/tools/metrics/histograms/metadata/gpu/histograms.xml
@@ -1038,7 +1038,7 @@
 </histogram>
 
 <histogram name="Gpu.GrShaderCacheLoadHitInCache" enum="Boolean"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>geofflang@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
   <summary>
@@ -1476,7 +1476,7 @@
 </histogram>
 
 <histogram name="GPU.TransferCache.ReusedTimes" units="Reuses"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>boliu@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
   <summary>
@@ -1725,7 +1725,7 @@
 </histogram>
 
 <histogram name="GPU.{GraphiteDawnOrWebGPU}.{Cacheable}.CacheMiss"
-    units="microseconds" expires_after="2025-04-13">
+    units="microseconds" expires_after="2025-06-15">
   <owner>lokokung@google.com</owner>
   <owner>mdb.webgpu-dev-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/hang_watcher/histograms.xml b/tools/metrics/histograms/metadata/hang_watcher/histograms.xml
index f6b6644..21aea71 100644
--- a/tools/metrics/histograms/metadata/hang_watcher/histograms.xml
+++ b/tools/metrics/histograms/metadata/hang_watcher/histograms.xml
@@ -62,7 +62,7 @@
 </variants>
 
 <histogram name="HangWatcher.IsThreadHung.{BrowserProcessAndThreadType}"
-    enum="BooleanHung" expires_after="2025-04-13">
+    enum="BooleanHung" expires_after="2025-06-15">
   <owner>olivierli@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/history/histograms.xml b/tools/metrics/histograms/metadata/history/histograms.xml
index 9a67d80..044e279 100644
--- a/tools/metrics/histograms/metadata/history/histograms.xml
+++ b/tools/metrics/histograms/metadata/history/histograms.xml
@@ -2668,7 +2668,7 @@
 </histogram>
 
 <histogram name="History.VisitedLinks.HashTableLengthOnReaderInit"
-    units="entries" expires_after="2025-04-13">
+    units="entries" expires_after="2025-06-15">
   <owner>kyraseevers@chromium.org</owner>
   <owner>brgoldstein@google.com</owner>
   <summary>
@@ -2679,7 +2679,7 @@
 </histogram>
 
 <histogram name="History.VisitedLinks.HashTableSizeOnTableCreate" units="MB"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>kyraseevers@chromium.org</owner>
   <owner>brgoldstein@google.com</owner>
   <summary>
@@ -2689,7 +2689,7 @@
 </histogram>
 
 <histogram name="History.VisitedLinks.HashTableUsageOnLinkAdded"
-    units="fingerprints" expires_after="2025-04-13">
+    units="fingerprints" expires_after="2025-06-15">
   <owner>kyraseevers@chromium.org</owner>
   <owner>brgoldstein@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/language/histograms.xml b/tools/metrics/histograms/metadata/language/histograms.xml
index 9251c4f3..57ae12c2 100644
--- a/tools/metrics/histograms/metadata/language/histograms.xml
+++ b/tools/metrics/histograms/metadata/language/histograms.xml
@@ -151,7 +151,7 @@
 </histogram>
 
 <histogram name="LanguageDetection.TFLiteModel.WasModelAvailableForDetection"
-    enum="BooleanAvailable" expires_after="2025-04-13">
+    enum="BooleanAvailable" expires_after="2025-06-15">
   <owner>mcrouse@chromium.org</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -197,7 +197,7 @@
 </histogram>
 
 <histogram name="LanguageSettings.AppLanguagePrompt.Action"
-    enum="LanguageSettingsAppLanguagePromptAction" expires_after="2025-04-13">
+    enum="LanguageSettingsAppLanguagePromptAction" expires_after="2025-06-15">
   <owner>perrier@chromium.org</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -276,7 +276,7 @@
 </histogram>
 
 <histogram name="LanguageSettings.AppLanguagePrompt.TopULPMatchStatus"
-    enum="ULPTopLanguageMatch" expires_after="2025-04-13">
+    enum="ULPTopLanguageMatch" expires_after="2025-06-15">
   <owner>perrier@chromium.org</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index d3447c1..6aa4b9f1 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -3890,7 +3890,7 @@
 </histogram>
 
 <histogram name="Media.HLS.MultivariantPlaylist" enum="Boolean"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>tmathmeyer@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
@@ -5626,7 +5626,7 @@
 
 <histogram name="Media.Ui.GetDisplayMedia.BasicFlow.UserInteraction"
     enum="MediaUiGetDisplayMediaBasicFlowUserInteraction"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>eladalon@chromium.org</owner>
   <owner>fbeaufort@chromium.org</owner>
   <summary>
@@ -7224,7 +7224,7 @@
 </histogram>
 
 <histogram name="MediaRouter.Cast.Channel.Error"
-    enum="MediaRouterCastChannelError" expires_after="2025-04-13">
+    enum="MediaRouterCastChannelError" expires_after="2025-06-15">
   <owner>mfoltz@chromium.org</owner>
   <owner>openscreen-eng@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/memory/histograms.xml b/tools/metrics/histograms/metadata/memory/histograms.xml
index 4c6ef32..f63e15af 100644
--- a/tools/metrics/histograms/metadata/memory/histograms.xml
+++ b/tools/metrics/histograms/metadata/memory/histograms.xml
@@ -94,7 +94,7 @@
 </variants>
 
 <histogram name="HeapProfiling.InProcess.Enabled{Process}"
-    enum="BooleanEnabled" expires_after="2025-04-13">
+    enum="BooleanEnabled" expires_after="2025-06-15">
   <owner>joenotcharles@google.com</owner>
   <owner>chrome-memory@google.com</owner>
   <summary>
@@ -171,7 +171,7 @@
 </histogram>
 
 <histogram name="HeapProfiling.InProcess.SamplesPerSnapshot{Process}"
-    units="samples" expires_after="2025-04-13">
+    units="samples" expires_after="2025-06-15">
   <owner>joenotcharles@google.com</owner>
   <owner>chrome-memory@google.com</owner>
   <summary>
@@ -1635,7 +1635,7 @@
 </histogram>
 
 <histogram name="Memory.ParkableString.Read.Latency" units="microseconds"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>lizeb@chromium.org</owner>
   <owner>pasko@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index ed904c1..9c76a4ff 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -1446,7 +1446,7 @@
 </histogram>
 
 <histogram name="Navigation.MainFrameProfileType2" enum="BrowserProfileType"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>rhalavati@chromium.org</owner>
   <owner>chrome-privacy-core@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index af629de..e97bf20a 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -446,7 +446,7 @@
 </histogram>
 
 <histogram name="HttpCache.Pattern" enum="HttpCachePattern"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>morlovich@chromium.org</owner>
   <owner>jkarlin@chromium.org</owner>
   <summary>For each http cache transaction, the recorded pattern.</summary>
@@ -3604,7 +3604,7 @@
 
 <histogram
     name="Net.QuicSession.ConnectionCloseErrorCode{Closer}{ServerType}{HandshakeType}"
-    enum="QuicErrorCodes" expires_after="2025-04-13">
+    enum="QuicErrorCodes" expires_after="2025-06-15">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
index da0afc620..fef408d 100644
--- a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
+++ b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
@@ -1593,7 +1593,7 @@
 </histogram>
 
 <histogram name="NewTabPage.WallpaperSearch.Status"
-    enum="NtpWallpaperSearchStatus" expires_after="2025-04-13">
+    enum="NtpWallpaperSearchStatus" expires_after="2025-06-15">
   <owner>pauladedeji@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>rtatum@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/omnibox/histograms.xml b/tools/metrics/histograms/metadata/omnibox/histograms.xml
index 27395f2..a6bc90e 100644
--- a/tools/metrics/histograms/metadata/omnibox/histograms.xml
+++ b/tools/metrics/histograms/metadata/omnibox/histograms.xml
@@ -2043,7 +2043,7 @@
 </histogram>
 
 <histogram name="Omnibox.SuggestionUsed.URL.NavigationToFirstContentfulPaint"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>jdonnelly@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
   <owner>chrome-omnibox-team@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 58e7930..80edffea 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -2947,7 +2947,7 @@
 </histogram>
 
 <histogram name="ClientHints.AcceptCHFrame" enum="AcceptCHFrameRestart"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>victortan@chromium.org</owner>
   <owner>miketaylr@chromium.org</owner>
   <owner>katabolism-finch@google.com</owner>
@@ -4858,7 +4858,7 @@
 </histogram>
 
 <histogram name="FetchKeepAlive.RequestOutliveDuration" units="ms"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>mych@chromium.org</owner>
   <owner>chrome-bfcache@google.com</owner>
   <summary>
@@ -4898,7 +4898,7 @@
 
 <histogram
     name="FetchKeepAlive.Requests2.{RequestState}.IsContextDetached.{Process}"
-    enum="Boolean" expires_after="2025-04-13">
+    enum="Boolean" expires_after="2025-06-15">
   <owner>mych@chromium.org</owner>
   <owner>chrome-bfcache@google.com</owner>
   <summary>
@@ -6292,7 +6292,7 @@
 </histogram>
 
 <histogram name="MPArch.ChildProcessLaunchSubsequent" units="ms"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>pasko@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml
index 62f31592..32936c9 100644
--- a/tools/metrics/histograms/metadata/page/histograms.xml
+++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -1279,7 +1279,7 @@
 
 <histogram
     name="PageLoad.Clients.GoogleSearch.NavigationTiming.NavigationStartToFinalLoaderCallback"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>nidhijaju@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -1293,7 +1293,7 @@
 
 <histogram
     name="PageLoad.Clients.GoogleSearch.NavigationTiming.NavigationStartToFinalRequestStart"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>nidhijaju@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -1307,7 +1307,7 @@
 
 <histogram
     name="PageLoad.Clients.GoogleSearch.NavigationTiming.NavigationStartToFinalResponseStart"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>nidhijaju@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -1321,7 +1321,7 @@
 
 <histogram
     name="PageLoad.Clients.GoogleSearch.NavigationTiming.NavigationStartToFirstLoaderCallback"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>kouhei@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -1335,7 +1335,7 @@
 
 <histogram
     name="PageLoad.Clients.GoogleSearch.NavigationTiming.NavigationStartToFirstRequestStart"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>kouhei@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -1349,7 +1349,7 @@
 
 <histogram
     name="PageLoad.Clients.GoogleSearch.NavigationTiming.NavigationStartToFirstResponseStart"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>kouhei@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -1482,7 +1482,7 @@
 
 <histogram
     name="PageLoad.Clients.GoogleSearch{Granularity}.PaintTiming.NavigationToLargestContentfulPaint{SafeSitesFilter}"
-    units="ms" expires_after="2025-06-08">
+    units="ms" expires_after="2025-06-15">
   <owner>spelchat@chromium.org</owner>
   <owner>chrome-brapp-loading@google.com</owner>
   <summary>
@@ -1522,7 +1522,7 @@
 
 <histogram
     name="PageLoad.Clients.LCPP.PaintTiming.NavigationToFirstContentfulPaint"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>kouhei@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -1536,7 +1536,7 @@
 
 <histogram
     name="PageLoad.Clients.LCPP.PaintTiming.NavigationToLargestContentfulPaint"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>kouhei@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -1564,7 +1564,7 @@
 </histogram>
 
 <histogram name="PageLoad.Clients.LCPP.PaintTiming.PredictLCPResult"
-    enum="LcppPredictResult" expires_after="2025-04-13">
+    enum="LcppPredictResult" expires_after="2025-06-15">
   <owner>yoichio@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -2042,7 +2042,7 @@
 
 <histogram
     name="PageLoad.Clients.ThirdParty.Frames.Opaque.NavigationToLargestContentfulPaint"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>awillia@chromium.org</owner>
   <owner>djmitche@chromium.org</owner>
   <summary>
@@ -3317,7 +3317,7 @@
 
 <histogram
     name="PageLoad.InteractiveTiming.{NormalizedResponsivenessMetric}.{UserInteractionLatency}{PageLoadType}"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>iclelland@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
@@ -3583,7 +3583,7 @@
 </histogram>
 
 <histogram name="PageLoad.LayoutInstability.CumulativeShiftScore"
-    units="scorex10" expires_after="2025-04-13">
+    units="scorex10" expires_after="2025-06-15">
   <owner>bmcquade@chromium.org</owner>
   <owner>skobes@chromium.org</owner>
   <summary>
@@ -4013,7 +4013,7 @@
 
 <histogram
     name="PageLoad.PaintTiming.NavigationToLargestContentfulPaint2.CrossSiteSubFrame"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>sisidovski@google.com</owner>
   <owner>kouhei@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml
index 2d3cb46..9e666e3 100644
--- a/tools/metrics/histograms/metadata/password/histograms.xml
+++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -460,7 +460,7 @@
 </histogram>
 
 <histogram name="PasswordGeneration.PopupShown"
-    enum="PasswordGenerationPopupShown" expires_after="2025-04-13">
+    enum="PasswordGenerationPopupShown" expires_after="2025-06-15">
   <owner>kazinova@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>Records an entry if (and only if) a popup was shown.</summary>
@@ -490,7 +490,7 @@
 </histogram>
 
 <histogram name="PasswordGeneration.UserDecision"
-    enum="PasswordGenerationUserEvent" expires_after="2025-04-13">
+    enum="PasswordGenerationUserEvent" expires_after="2025-06-15">
   <owner>ioanap@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -2832,7 +2832,7 @@
 </histogram>
 
 <histogram name="PasswordManager.PasswordReuse.TotalPasswords"
-    units="credentials" expires_after="2025-04-13">
+    units="credentials" expires_after="2025-06-15">
   <owner>nwokedi@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -3949,7 +3949,7 @@
 </histogram>
 
 <histogram name="PasswordManager.SuccessfulSubmissionIndicatorEvent"
-    enum="SubmissionIndicatorEvent" expires_after="2025-04-13">
+    enum="SubmissionIndicatorEvent" expires_after="2025-06-15">
   <owner>kazinova@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/pdf/histograms.xml b/tools/metrics/histograms/metadata/pdf/histograms.xml
index 3fe612f..9c76734 100644
--- a/tools/metrics/histograms/metadata/pdf/histograms.xml
+++ b/tools/metrics/histograms/metadata/pdf/histograms.xml
@@ -23,7 +23,7 @@
 <histograms>
 
 <histogram name="PDF.Actions" enum="ChromePDFViewerActions"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>andyphan@chromium.org</owner>
   <owner>thestig@chromium.org</owner>
   <summary>
@@ -143,7 +143,7 @@
   </summary>
 </histogram>
 
-<histogram name="PDF.PageCount" units="pages" expires_after="2025-04-13">
+<histogram name="PDF.PageCount" units="pages" expires_after="2025-06-15">
   <owner>andyphan@chromium.org</owner>
   <owner>thestig@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/permissions/histograms.xml b/tools/metrics/histograms/metadata/permissions/histograms.xml
index f37bafb..3a8b519 100644
--- a/tools/metrics/histograms/metadata/permissions/histograms.xml
+++ b/tools/metrics/histograms/metadata/permissions/histograms.xml
@@ -188,7 +188,7 @@
 </histogram>
 
 <histogram name="Permissions.Action.WithDisposition.{DispositionType}"
-    enum="PermissionAction" expires_after="2025-04-13">
+    enum="PermissionAction" expires_after="2025-06-15">
   <owner>andypaicu@chromium.org</owner>
   <owner>engedy@chromium.org</owner>
   <owner>hkamila@chromium.org</owner>
@@ -967,7 +967,7 @@
 </histogram>
 
 <histogram name="Permissions.Prompt.Shown" enum="PermissionRequestType"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>engedy@chromium.org</owner>
   <owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/power/histograms.xml b/tools/metrics/histograms/metadata/power/histograms.xml
index f123678..4ab30b3e 100644
--- a/tools/metrics/histograms/metadata/power/histograms.xml
+++ b/tools/metrics/histograms/metadata/power/histograms.xml
@@ -197,7 +197,7 @@
 </variants>
 
 <histogram name="PerformanceMonitor.AverageCPU8.Total{UsageScenario}"
-    units="1/100 %" expires_after="2025-04-13">
+    units="1/100 %" expires_after="2025-06-15">
   <owner>fdoray@chromium.org</owner>
   <owner>pmonette@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
@@ -209,7 +209,7 @@
 </histogram>
 
 <histogram name="PerformanceMonitor.AverageCPU8.{ProcessName}" units="1/100 %"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>fdoray@chromium.org</owner>
   <owner>pmonette@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
@@ -699,7 +699,7 @@
 
 <histogram
     name="Power.BatteryDischargeRateMilliwatts6{UsageScenario}{IntervalType}{BatterySaverMode}"
-    units="milliwatts" expires_after="2025-04-13">
+    units="milliwatts" expires_after="2025-06-15">
   <owner>etiennep@chromium.org</owner>
   <owner>olivierli@chromium.org</owner>
   <owner>lgrey@chromium.org</owner>
@@ -726,7 +726,7 @@
 
 <histogram
     name="Power.BatteryDischargeRatePreciseMilliwatts{UsageScenario}{IntervalType}{BatterySaverMode}"
-    units="milliwatts" expires_after="2025-04-13">
+    units="milliwatts" expires_after="2025-06-15">
   <owner>pmonette@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -755,7 +755,7 @@
 
 <histogram
     name="Power.BatteryDischargeRateRelative5{UsageScenario}{IntervalType}{BatterySaverMode}"
-    units="hundredth of percent" expires_after="2025-04-13">
+    units="hundredth of percent" expires_after="2025-06-15">
   <owner>etiennep@chromium.org</owner>
   <owner>olivierli@chromium.org</owner>
   <owner>lgrey@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/preloading/histograms.xml b/tools/metrics/histograms/metadata/preloading/histograms.xml
index 8962af5..cd4705a6 100644
--- a/tools/metrics/histograms/metadata/preloading/histograms.xml
+++ b/tools/metrics/histograms/metadata/preloading/histograms.xml
@@ -272,7 +272,7 @@
 
 <histogram
     name="Preloading.{PreloadingType}.Attempt.{PreloadingPredictor}.Recall"
-    enum="PredictorConfusionMatrix" expires_after="2025-04-13">
+    enum="PredictorConfusionMatrix" expires_after="2025-06-15">
   <owner>isaboori@google.com</owner>
   <owner>spelchat@chromium.org</owner>
   <owner>sreejakshetty@chromium.org</owner>
@@ -293,7 +293,7 @@
 
 <histogram
     name="Preloading.{PreloadingType}.Attempt.{PreloadingPredictor}.TriggeringOutcome"
-    enum="PreloadingTriggeringOutcome" expires_after="2025-04-13">
+    enum="PreloadingTriggeringOutcome" expires_after="2025-06-15">
   <owner>spelchat@chromium.org</owner>
   <owner>sreejakshetty@chromium.org</owner>
   <owner>jbroman@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/privacy/histograms.xml b/tools/metrics/histograms/metadata/privacy/histograms.xml
index e9bb7396..7a1038c 100644
--- a/tools/metrics/histograms/metadata/privacy/histograms.xml
+++ b/tools/metrics/histograms/metadata/privacy/histograms.xml
@@ -1240,7 +1240,7 @@
 </histogram>
 
 <histogram name="PrivacySandbox.Attestations.IsSiteAttestedStatus"
-    enum="PrivacySandboxApiAllowed" expires_after="2025-04-13">
+    enum="PrivacySandboxApiAllowed" expires_after="2025-06-15">
   <owner>shivanisha@chromium.org</owner>
   <owner>xiaochenzh@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/readaloud/histograms.xml b/tools/metrics/histograms/metadata/readaloud/histograms.xml
index 52961fdc..0315df6 100644
--- a/tools/metrics/histograms/metadata/readaloud/histograms.xml
+++ b/tools/metrics/histograms/metadata/readaloud/histograms.xml
@@ -168,7 +168,7 @@
 </histogram>
 
 <histogram name="ReadAloud.IsPageReadabilitySuccessful" enum="BooleanSuccess"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>andreaxg@google.com</owner>
   <owner>basiaz@google.com</owner>
   <owner>iwells@chromium.org</owner>
@@ -180,7 +180,7 @@
 </histogram>
 
 <histogram name="ReadAloud.IsPageReadable" enum="BooleanEligible"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>andreaxg@google.com</owner>
   <owner>basiaz@google.com</owner>
   <owner>iwells@chromium.org</owner>
@@ -198,7 +198,7 @@
 </histogram>
 
 <histogram name="ReadAloud.IsTabPlaybackCreationSuccessful"
-    enum="BooleanSuccess" expires_after="2025-04-13">
+    enum="BooleanSuccess" expires_after="2025-06-15">
   <owner>andreaxg@google.com</owner>
   <owner>basiaz@google.com</owner>
   <owner>iwells@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/renderer4/histograms.xml b/tools/metrics/histograms/metadata/renderer4/histograms.xml
index bebafa57..af586cc 100644
--- a/tools/metrics/histograms/metadata/renderer4/histograms.xml
+++ b/tools/metrics/histograms/metadata/renderer4/histograms.xml
@@ -126,7 +126,7 @@
 
 <histogram base="true"
     name="Renderer4.ImageDecodeTaskDurationUs{ImageOrTaskType}.{DecodeType}"
-    units="microseconds" expires_after="2025-04-13">
+    units="microseconds" expires_after="2025-06-15">
   <owner>cblume@chromium.org</owner>
   <owner>vmpstr@chromium.org</owner>
   <owner>sashamcintosh@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/sb_client/histograms.xml b/tools/metrics/histograms/metadata/sb_client/histograms.xml
index 02158e5..a2b117c 100644
--- a/tools/metrics/histograms/metadata/sb_client/histograms.xml
+++ b/tools/metrics/histograms/metadata/sb_client/histograms.xml
@@ -459,7 +459,7 @@
 </histogram>
 
 <histogram name="SBClientDownload.{Encryption}DeepScanEvent3"
-    enum="SBDeepScanEvent" expires_after="2025-04-13">
+    enum="SBDeepScanEvent" expires_after="2025-06-15">
   <owner>drubery@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -885,7 +885,7 @@
 </histogram>
 
 <histogram name="SBClientPhishing.PhishingImageEmbeddingResult"
-    enum="ClientSidePhishingImageEmbeddingResult" expires_after="2025-04-13">
+    enum="ClientSidePhishingImageEmbeddingResult" expires_after="2025-06-15">
   <owner>andysjlim@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/scheduler/histograms.xml b/tools/metrics/histograms/metadata/scheduler/histograms.xml
index f79394f9..7753c51f 100644
--- a/tools/metrics/histograms/metadata/scheduler/histograms.xml
+++ b/tools/metrics/histograms/metadata/scheduler/histograms.xml
@@ -122,7 +122,7 @@
 </histogram>
 
 <histogram name="Scheduling.MessagePumpTimeKeeper.{NamedThread}"
-    enum="MessagePumpPhases" expires_after="2025-04-13">
+    enum="MessagePumpPhases" expires_after="2025-06-15">
   <owner>gab@chromium.org</owner>
   <owner>fdoray@chromium.org</owner>
   <owner>spvw@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/security/histograms.xml b/tools/metrics/histograms/metadata/security/histograms.xml
index a00e5f6..870d4d6 100644
--- a/tools/metrics/histograms/metadata/security/histograms.xml
+++ b/tools/metrics/histograms/metadata/security/histograms.xml
@@ -203,7 +203,7 @@
 </histogram>
 
 <histogram name="Security.HttpsFirstMode.InterstitialReason"
-    enum="HttpsFirstModeInterstitialReason" expires_after="2025-04-13">
+    enum="HttpsFirstModeInterstitialReason" expires_after="2025-06-15">
   <owner>meacer@chromium.org</owner>
   <owner>trusty-transport@chromium.org</owner>
   <summary>
@@ -213,7 +213,7 @@
 </histogram>
 
 <histogram name="Security.HttpsFirstMode.NavigationEvent"
-    enum="HttpsFirstModeNavigationEvent" expires_after="2025-04-13">
+    enum="HttpsFirstModeNavigationEvent" expires_after="2025-06-15">
   <owner>cthomp@chromium.org</owner>
   <owner>trusty-transport@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/service/histograms.xml b/tools/metrics/histograms/metadata/service/histograms.xml
index e3319f7..8b1457e0 100644
--- a/tools/metrics/histograms/metadata/service/histograms.xml
+++ b/tools/metrics/histograms/metadata/service/histograms.xml
@@ -698,7 +698,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.FetchHandlerStartToFetchHandlerEnd{EmbeddedWorkerInitialStatus}"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -777,7 +777,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.ForwardServiceWorkerToWorkerReady2{EmbeddedWorkerInitialStatus}{NavigationType}"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -1522,7 +1522,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.StartWorker.Status"
-    enum="ServiceWorkerStatusCode" expires_after="2025-04-13">
+    enum="ServiceWorkerStatusCode" expires_after="2025-06-15">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/session/histograms.xml b/tools/metrics/histograms/metadata/session/histograms.xml
index 63e14b60..dd937ea 100644
--- a/tools/metrics/histograms/metadata/session/histograms.xml
+++ b/tools/metrics/histograms/metadata/session/histograms.xml
@@ -35,7 +35,7 @@
 </histogram>
 
 <histogram name="Session.Background.TotalDuration" units="ms"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>asvitkine@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -995,7 +995,7 @@
 </histogram>
 
 <histogram name="Session.WebStates.NativeRestoreSession" enum="BooleanSuccess"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>justincohen@chromium.org</owner>
   <owner>michaeldo@chromium.org</owner>
   <summary>
@@ -1006,7 +1006,7 @@
 </histogram>
 
 <histogram name="Session.WebStates.NativeRestoreSessionFromCache"
-    enum="BooleanSuccess" expires_after="2025-04-13">
+    enum="BooleanSuccess" expires_after="2025-06-15">
   <owner>justincohen@chromium.org</owner>
   <owner>michaeldo@chromium.org</owner>
   <summary>
@@ -1017,7 +1017,7 @@
 </histogram>
 
 <histogram name="Session.WebStates.NativeRestoreSessionFromCacheHasData"
-    enum="BooleanHasData" expires_after="2025-04-13">
+    enum="BooleanHasData" expires_after="2025-06-15">
   <owner>justincohen@chromium.org</owner>
   <owner>michaeldo@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/sharing/histograms.xml b/tools/metrics/histograms/metadata/sharing/histograms.xml
index bc621c4..50de0d7 100644
--- a/tools/metrics/histograms/metadata/sharing/histograms.xml
+++ b/tools/metrics/histograms/metadata/sharing/histograms.xml
@@ -268,7 +268,7 @@
 </histogram>
 
 <histogram name="Sharing.DefaultSharesheetAndroid.Opened" enum="ShareOrigin"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>wenyufu@chromium.org</owner>
   <owner>sophey@chromium.org</owner>
   <owner>src/chrome/browser/share/OWNERS</owner>
@@ -442,7 +442,7 @@
 </histogram>
 
 <histogram name="Sharing.SharingHubAndroid.Opened" enum="ShareOrigin"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>wenyufu@chromium.org</owner>
   <owner>sophey@chromium.org</owner>
   <owner>src/chrome/browser/share/OWNERS</owner>
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml
index e36c92e..d11de42e 100644
--- a/tools/metrics/histograms/metadata/signin/histograms.xml
+++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -550,7 +550,7 @@
 </histogram>
 
 <histogram base="true" name="Signin.AndroidGetAccountsTime" units="ms"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>alexilin@chromium.org</owner>
   <owner>bsazonov@chromium.org</owner>
   <summary>
@@ -979,7 +979,7 @@
 </histogram>
 
 <histogram name="Signin.CctAccountMismatchNoticeSuppressed"
-    enum="SuppressedReason" expires_after="2025-04-13">
+    enum="SuppressedReason" expires_after="2025-06-15">
   <owner>samarchehade@google.com</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/startup/histograms.xml b/tools/metrics/histograms/metadata/startup/histograms.xml
index 47d81a7..83acac8 100644
--- a/tools/metrics/histograms/metadata/startup/histograms.xml
+++ b/tools/metrics/histograms/metadata/startup/histograms.xml
@@ -674,7 +674,7 @@
 </histogram>
 
 <histogram name="Startup.BrowserMessageLoopFirstIdle" units="ms"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>gab@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <summary>
@@ -1020,7 +1020,7 @@
 </histogram>
 
 <histogram name="Startup.GPU.LoadTime.ApplicationStartToGpuInitialized"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>spvw@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <summary>
@@ -1057,7 +1057,7 @@
 </histogram>
 
 <histogram name="Startup.GPU.LoadTime.ProcessCreationToGpuInitialized"
-    units="ms" expires_after="2025-04-13">
+    units="ms" expires_after="2025-06-15">
   <owner>spvw@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/structured_metrics/histograms.xml b/tools/metrics/histograms/metadata/structured_metrics/histograms.xml
index 2aec1c3..8a9c88c4 100644
--- a/tools/metrics/histograms/metadata/structured_metrics/histograms.xml
+++ b/tools/metrics/histograms/metadata/structured_metrics/histograms.xml
@@ -9,7 +9,7 @@
 <histograms>
 
 <histogram name="StructuredMetrics.ExternalMetricsDropped" units="count"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>andrewbregger@google.com</owner>
   <owner>jongahn@google.com</owner>
   <owner>chromeos-data-eng@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml
index d941ef6..e145a14 100644
--- a/tools/metrics/histograms/metadata/sync/histograms.xml
+++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -439,7 +439,7 @@
 </histogram>
 
 <histogram name="Sync.ConfigureDataTypes" enum="SyncDataTypes"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>mastiz@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -1641,7 +1641,7 @@
 </histogram>
 
 <histogram name="Sync.SyncablePrefValueChanged" enum="SyncablePref"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>ankushkush@google.com</owner>
   <owner>treib@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/tab/histograms.xml b/tools/metrics/histograms/metadata/tab/histograms.xml
index bd438d5b..0d88e8b 100644
--- a/tools/metrics/histograms/metadata/tab/histograms.xml
+++ b/tools/metrics/histograms/metadata/tab/histograms.xml
@@ -770,7 +770,7 @@
 </histogram>
 
 <histogram name="TabGroups.NumberOfRootIdsFixed" units="groups"
-    expires_after="2025-01-26">
+    expires_after="2025-06-26">
   <owner>ckitagawa@chromium.org</owner>
   <owner>clank-tab-dev@chromium.org</owner>
   <summary>
@@ -3385,7 +3385,7 @@
 </histogram>
 
 <histogram name="Tabs.TabState.SaveTime{Schema}" units="ms"
-    expires_after="2025-04-12">
+    expires_after="2025-06-15">
   <owner>nyquist@chromium.org</owner>
   <owner>dtrainor@chromium.org</owner>
   <owner>davidjm@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/toasts/histograms.xml b/tools/metrics/histograms/metadata/toasts/histograms.xml
index bdcf0588..0e8cfd5 100644
--- a/tools/metrics/histograms/metadata/toasts/histograms.xml
+++ b/tools/metrics/histograms/metadata/toasts/histograms.xml
@@ -32,7 +32,7 @@
 </histogram>
 
 <histogram name="Toast.{ToastName}.Dismissed" enum="ToastCloseReason"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>agale@chromium.org</owner>
   <owner>stluong@chromium.org</owner>
   <owner>chrome-performance-ui-sea@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/translate/histograms.xml b/tools/metrics/histograms/metadata/translate/histograms.xml
index d48ec8d..2e929505 100644
--- a/tools/metrics/histograms/metadata/translate/histograms.xml
+++ b/tools/metrics/histograms/metadata/translate/histograms.xml
@@ -178,7 +178,7 @@
 </histogram>
 
 <histogram name="Translate.HrefHint.Status" enum="HrefTranslateStatus"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>sclittle@google.com</owner>
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
@@ -212,7 +212,7 @@
 </histogram>
 
 <histogram name="Translate.LanguageDetection.LanguageVerification"
-    enum="TranslateLanguageVerification" expires_after="2025-04-13">
+    enum="TranslateLanguageVerification" expires_after="2025-06-15">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -386,7 +386,7 @@
 </histogram>
 
 <histogram name="Translate.PageLoad.FinalState" enum="TranslateState"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -450,7 +450,7 @@
 </histogram>
 
 <histogram name="Translate.PageLoad.InitialTargetLanguage"
-    enum="LocaleCodeISO639" expires_after="2025-04-13">
+    enum="LocaleCodeISO639" expires_after="2025-06-15">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -565,7 +565,7 @@
 </histogram>
 
 <histogram name="Translate.PageLoad.TriggerDecision"
-    enum="TranslateTriggerDecision" expires_after="2025-04-13">
+    enum="TranslateTriggerDecision" expires_after="2025-06-15">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -583,7 +583,7 @@
 </histogram>
 
 <histogram name="Translate.PartialTranslation.HttpResponseCode"
-    enum="HttpResponseCode" expires_after="2025-04-13">
+    enum="HttpResponseCode" expires_after="2025-06-15">
   <owner>basiaz@google.com</owner>
   <owner>cuianthony@google.com</owner>
   <summary>
@@ -645,7 +645,7 @@
 </histogram>
 
 <histogram name="Translate.PartialTranslation.TranslationStatus"
-    enum="PartialTranslateTranslationStatus" expires_after="2025-04-13">
+    enum="PartialTranslateTranslationStatus" expires_after="2025-06-15">
   <owner>cuianthony@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -691,7 +691,7 @@
 </histogram>
 
 <histogram name="Translate.Translation.SourceLanguage" enum="LocaleCodeISO639"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -703,7 +703,7 @@
 </histogram>
 
 <histogram name="Translate.Translation.Status" enum="TranslationStatus"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -722,7 +722,7 @@
 </histogram>
 
 <histogram name="Translate.Translation.TargetLanguage" enum="LocaleCodeISO639"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -781,7 +781,7 @@
 </histogram>
 
 <histogram name="Translate.Translation.Type" enum="TranslationType"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/uma/histograms.xml b/tools/metrics/histograms/metadata/uma/histograms.xml
index c7b39d7..e424595 100644
--- a/tools/metrics/histograms/metadata/uma/histograms.xml
+++ b/tools/metrics/histograms/metadata/uma/histograms.xml
@@ -652,7 +652,7 @@
 </histogram>
 
 <histogram name="UMA.PersistentAllocator.{PersistentAllocatorType}.UsedPct"
-    units="%" expires_after="2025-04-13">
+    units="%" expires_after="2025-06-15">
   <owner>asvitkine@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/v8/histograms.xml b/tools/metrics/histograms/metadata/v8/histograms.xml
index ca2c0199..e1b25a2c 100644
--- a/tools/metrics/histograms/metadata/v8/histograms.xml
+++ b/tools/metrics/histograms/metadata/v8/histograms.xml
@@ -41,7 +41,7 @@
 </histogram>
 
 <histogram name="V8.AsmjsInstantiateResult" enum="AsmJsInstantiateResult"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>ahaas@chromium.org</owner>
   <owner>ecmziegler@chromium.org</owner>
   <owner>wasm-v8@google.com</owner>
@@ -462,7 +462,7 @@
 </histogram>
 
 <histogram name="V8.GC.Cycle{Priority}.CollectionRate.Full" units="%"
-    expires_after="M136">
+    expires_after="2025-06-15">
   <owner>nikolaos@chromium.org</owner>
   <owner>v8-memory-sheriffs@google.com</owner>
   <summary>
@@ -496,7 +496,7 @@
 </histogram>
 
 <histogram name="V8.GC.Cycle{Priority}.CollectionRate.Young" units="%"
-    expires_after="M136">
+    expires_after="2025-06-15">
   <owner>nikolaos@chromium.org</owner>
   <owner>v8-memory-sheriffs@google.com</owner>
   <summary>
@@ -685,7 +685,8 @@
   </token>
 </histogram>
 
-<histogram name="V8.GC.Cycle{Priority}.Full" units="ms" expires_after="M136">
+<histogram name="V8.GC.Cycle{Priority}.Full" units="ms"
+    expires_after="2025-06-15">
   <owner>nikolaos@chromium.org</owner>
   <owner>v8-memory-sheriffs@google.com</owner>
   <summary>
@@ -797,7 +798,7 @@
 </histogram>
 
 <histogram name="V8.GC.Cycle{Priority}.Full.Sweep.Cpp" units="ms"
-    expires_after="M136">
+    expires_after="2025-06-15">
   <owner>omerkatz@chromium.org</owner>
   <owner>v8-memory-sheriffs@google.com</owner>
   <summary>
@@ -846,7 +847,7 @@
 </histogram>
 
 <histogram name="V8.GC.Cycle{Priority}.MainThread.Full" units="ms"
-    expires_after="M136">
+    expires_after="2025-06-15">
   <owner>nikolaos@chromium.org</owner>
   <owner>v8-memory-sheriffs@google.com</owner>
   <summary>
@@ -1230,7 +1231,7 @@
 </histogram>
 
 <histogram name="V8.GC.Cycle{Priority}.MainThread.Full.Sweep.Cpp" units="ms"
-    expires_after="M136">
+    expires_after="2025-06-15">
   <owner>omerkatz@chromium.org</owner>
   <owner>v8-memory-sheriffs@google.com</owner>
   <summary>
@@ -1281,7 +1282,7 @@
 </histogram>
 
 <histogram name="V8.GC.Cycle{Priority}.MainThread.Young" units="ms"
-    expires_after="M136">
+    expires_after="2025-06-15">
   <owner>nikolaos@chromium.org</owner>
   <owner>v8-memory-sheriffs@google.com</owner>
   <summary>
@@ -1457,7 +1458,8 @@
   </token>
 </histogram>
 
-<histogram name="V8.GC.Cycle{Priority}.Young" units="ms" expires_after="M136">
+<histogram name="V8.GC.Cycle{Priority}.Young" units="ms"
+    expires_after="2025-06-15">
   <owner>nikolaos@chromium.org</owner>
   <owner>v8-memory-sheriffs@google.com</owner>
   <summary>
@@ -2217,7 +2219,7 @@
 </histogram>
 
 <histogram name="V8.WasmCodeCaching" enum="WasmCodeCaching"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>ahaas@chromium.org</owner>
   <owner>clemensb@chromium.org</owner>
   <owner>wasm-runtime@google.com</owner>
@@ -2355,7 +2357,7 @@
 </histogram>
 
 <histogram name="V8.WasmDeserializationTimeMilliSeconds" units="ms"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>ahaas@chromium.org</owner>
   <owner>clemensb@chromium.org</owner>
   <owner>ecmziegler@chromium.org</owner>
@@ -2572,7 +2574,7 @@
 </histogram>
 
 <histogram name="V8.WasmModuleSizeBytes" units="bytes"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>ecmziegler@chromium.org</owner>
   <owner>adamk@chromium.org</owner>
   <owner>ahaas@chromium.org</owner>
@@ -2607,7 +2609,7 @@
 </histogram>
 
 <histogram name="V8.WasmSerializationTimeMilliSeconds" units="ms"
-    expires_after="2025-04-13">
+    expires_after="2025-06-15">
   <owner>ahaas@chromium.org</owner>
   <owner>clemensb@chromium.org</owner>
   <owner>ecmziegler@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/webauthn/enums.xml b/tools/metrics/histograms/metadata/webauthn/enums.xml
index c7786eb1..de4955b 100644
--- a/tools/metrics/histograms/metadata/webauthn/enums.xml
+++ b/tools/metrics/histograms/metadata/webauthn/enums.xml
@@ -74,6 +74,18 @@
   <int value="4" label="prepareGetCredential request failed."/>
 </enum>
 
+<enum name="GPMGetAssertionEvents">
+  <int value="0" label="Started - GPM passkey selected"/>
+  <int value="1" label="Success - Authentication complete"/>
+  <int value="2" label="Failure - Error dialog shown"/>
+</enum>
+
+<enum name="GPMMakeCredentialEvents">
+  <int value="0" label="Started - Create GPM passkey dialog shown"/>
+  <int value="1" label="Success - Passkey saved"/>
+  <int value="2" label="Failure - Error dialog shown"/>
+</enum>
+
 <enum name="OnboardingEvents">
   <int value="0" label="Started (Create GPM passkey dialog shown)"/>
   <int value="1" label="Succeeded (GPM passkey created)"/>
@@ -304,6 +316,16 @@
   <int value="17" label="Other Failure"/>
 </enum>
 
+<enum name="WebAuthenticationPinRenewalEvent">
+  <int value="0" label="Considered renewing the PIN"/>
+  <int value="1" label="No PIN to renew"/>
+  <int value="2" label="Another renewal was running concurrently"/>
+  <int value="3" label="Not yet time to renew"/>
+  <int value="4" label="Started renewal"/>
+  <int value="5" label="Successful renewal"/>
+  <int value="6" label="Renewal failed"/>
+</enum>
+
 <enum name="WebAuthenticationRequestMode">
   <int value="0" label="WebAuthn Modal Request"/>
   <int value="1" label="WebAuthn Conditional UI Request"/>
diff --git a/tools/metrics/histograms/metadata/webauthn/histograms.xml b/tools/metrics/histograms/metadata/webauthn/histograms.xml
index 52cf45c0..8ddf272 100644
--- a/tools/metrics/histograms/metadata/webauthn/histograms.xml
+++ b/tools/metrics/histograms/metadata/webauthn/histograms.xml
@@ -307,6 +307,28 @@
   </summary>
 </histogram>
 
+<histogram name="WebAuthentication.GPM.GetAssertion"
+    enum="GPMGetAssertionEvents" expires_after="2025-09-17">
+  <owner>natiahlyi@google.com</owner>
+  <owner>chrome-webauthn@google.com</owner>
+  <summary>
+    Records start, success, and failure events for Google Password Manager (GPM)
+    passkey authentication attempts (GetAssertion calls). Each event is emitted
+    immediately after it occurs. See GPMGetAssertionEvents enum for details.
+  </summary>
+</histogram>
+
+<histogram name="WebAuthentication.GPM.MakeCredential"
+    enum="GPMMakeCredentialEvents" expires_after="2025-09-17">
+  <owner>natiahlyi@google.com</owner>
+  <owner>chrome-webauthn@google.com</owner>
+  <summary>
+    Records start, success, and failure events for Google Password Manager (GPM)
+    passkey creation attempts (MakeCredential calls). Each event is emitted
+    immediately after it occurs. See GPMMakeCredentialEvents enum for details.
+  </summary>
+</histogram>
+
 <histogram name="WebAuthentication.IsUVPlatformAuthenticatorAvailable2"
     enum="Boolean" expires_after="2025-06-08">
   <owner>kenrb@chromium.org</owner>
@@ -366,6 +388,13 @@
   </summary>
 </histogram>
 
+<histogram name="WebAuthentication.PinRenewalEvent"
+    enum="WebAuthenticationPinRenewalEvent" expires_after="2025-05-11">
+  <owner>agl@google.com</owner>
+  <owner>kenrb@chromium.org</owner>
+  <summary>Records events related to GPM PIN renewals</summary>
+</histogram>
+
 <histogram
     name="WebAuthentication.SignalAllAcceptedCredentialsRemovedGPMPasskey"
     enum="SignalAllAcceptedCredentialsResult" expires_after="2025-09-17">
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index ba792ee..66b713b 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,28 +1,28 @@
 {
     "trace_processor_shell": {
         "linux_arm64": {
-            "hash": "4a488010ab1427a327f1b9fd4045dd0f3bc813ff",
-            "full_remote_path": "perfetto-luci-artifacts/76778cdf92dd1795698ce9d4742484645e06074b/linux-arm64/trace_processor_shell"
+            "hash": "1839ff51215f9b27b4e4524dd2075e512e30a27a",
+            "full_remote_path": "perfetto-luci-artifacts/5bf4e2a65d76d5a603ff175222d1513f71d28a0b/linux-arm64/trace_processor_shell"
         },
         "win": {
-            "hash": "8cc6b5adcb8a549b89df25699bab0ab17d8cb376",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/076d3983da9bbbe312f1c8d5fb77867e9a41779d/trace_processor_shell.exe"
+            "hash": "12ad3c9f266de117858859f1f5b5dee2694bf0ba",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/5bf4e2a65d76d5a603ff175222d1513f71d28a0b/trace_processor_shell.exe"
         },
         "linux_arm": {
-            "hash": "296798e193cbca9d79cbe293f93ab8acf194bec1",
-            "full_remote_path": "perfetto-luci-artifacts/76778cdf92dd1795698ce9d4742484645e06074b/linux-arm/trace_processor_shell"
+            "hash": "e250187786aa190a66288bc9443a5e1f5888f8d7",
+            "full_remote_path": "perfetto-luci-artifacts/5bf4e2a65d76d5a603ff175222d1513f71d28a0b/linux-arm/trace_processor_shell"
         },
         "mac": {
             "hash": "f5d83eca972747f7c3db9f35c07ed57902418e8c",
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/881ad50c05049ca13d4b34e4f92f4167de5ac52a/trace_processor_shell"
         },
         "mac_arm64": {
-            "hash": "ab2319a0ae7ca06fa899436b0a477e26d2329ede",
-            "full_remote_path": "perfetto-luci-artifacts/76778cdf92dd1795698ce9d4742484645e06074b/mac-arm64/trace_processor_shell"
+            "hash": "cf5cd094ca2e4424fb59f6e9c872130feb1e3462",
+            "full_remote_path": "perfetto-luci-artifacts/5bf4e2a65d76d5a603ff175222d1513f71d28a0b/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "c01f98651b2164002c7818d8096e13a04255e11b",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/6361af291ce8ffd1f992fec3f44483c00bba124e/trace_processor_shell"
+            "hash": "6732a9390a195cdf1573174c41c79892bd862c87",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/5bf4e2a65d76d5a603ff175222d1513f71d28a0b/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/android/java/src/org/chromium/ui/AsyncViewProvider.java b/ui/android/java/src/org/chromium/ui/AsyncViewProvider.java
index 7587e87..8f96de3 100644
--- a/ui/android/java/src/org/chromium/ui/AsyncViewProvider.java
+++ b/ui/android/java/src/org/chromium/ui/AsyncViewProvider.java
@@ -4,27 +4,29 @@
 
 package org.chromium.ui;
 
-import android.view.View;
+import static org.chromium.build.NullUtil.assumeNonNull;
 
-import androidx.annotation.Nullable;
+import android.view.View;
 
 import org.chromium.base.Callback;
 import org.chromium.base.ThreadUtils;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * A provider that encapsulates a {@link View} that is in the view hierarchy to be inflated by
  * an {@link AsyncViewStub}.
  * @param <T> type of the {@link View} that this provider encapsulates.
  */
+@NullMarked
 public class AsyncViewProvider<T extends View> implements Callback<View>, ViewProvider<T> {
     private int mResId;
     // Exactly one of mView and mViewStub is non-null at any point.
-    private T mView;
-    private AsyncViewStub mViewStub;
+    private @Nullable T mView;
+    private @Nullable AsyncViewStub mViewStub;
     private boolean mDestroyed;
 
     private AsyncViewProvider(AsyncViewStub viewStub, int resId) {
-        assert viewStub != null;
         mResId = resId;
         mViewStub = viewStub;
     }
@@ -45,8 +47,9 @@
      */
     public static <E extends View> AsyncViewProvider<E> of(AsyncViewStub viewStub, int resId) {
         ThreadUtils.assertOnUiThread();
-        if (viewStub.getInflatedView() != null) {
-            return new AsyncViewProvider<>(viewStub.getInflatedView().findViewById(resId));
+        View inflatedView = viewStub.getInflatedView();
+        if (inflatedView != null) {
+            return new AsyncViewProvider<>(inflatedView.findViewById(resId));
         }
         AsyncViewProvider<E> provider = new AsyncViewProvider<>(viewStub, resId);
         viewStub.addOnInflateListener(provider);
@@ -85,8 +88,7 @@
      * @return the {@link View} encapsulated by this provider or null (if the view has not been
      * inflated yet).
      */
-    @Nullable
-    public T get() {
+    public @Nullable T get() {
         return mView;
     }
 
@@ -101,12 +103,12 @@
         if (mView != null) {
             return new AsyncViewProvider<>(mView.findViewById(resId));
         }
-        return of(mViewStub, resId);
+        return of(assumeNonNull(mViewStub), resId);
     }
 
     @Override
     public void inflate() {
-        mViewStub.inflate();
+        assumeNonNull(mViewStub).inflate();
     }
 
     @Override
@@ -117,25 +119,19 @@
             // fire right now if view already inflated.
             callback.onResult(mView);
         } else {
-            mViewStub.addOnInflateListener(
-                    (View view) -> {
-                        if (mDestroyed) return;
-                        // listeners are called in order so mView should be set correctly at this
-                        // point.
-                        callback.onResult(mView);
-                    });
+            assumeNonNull(mViewStub)
+                    .addOnInflateListener(
+                            (View view) -> {
+                                if (mDestroyed) return;
+                                // listeners are called in order so mView should be set correctly at
+                                // this
+                                // point.
+                                callback.onResult(assumeNonNull(mView));
+                            });
         }
     }
 
     /**
-     * Destroy the provider making sure that all queued up after inflate callbacks are no longer
-     * called.
-     */
-    public void destroy() {
-        destroy(null);
-    }
-
-    /**
      * Same as {@link #destroy()} but takes a callback that is ensured to be run (either immediately
      * if the view is already inflated or after inflation of the {@link AsyncViewStub})).
      */
@@ -148,7 +144,7 @@
         if (mViewStub != null) {
             mViewStub.addOnInflateListener(
                     (View view) -> {
-                        destroyCallback.onResult(mView);
+                        destroyCallback.onResult(assumeNonNull(mView));
                     });
             mViewStub = null;
         }
diff --git a/ui/android/java/src/org/chromium/ui/AsyncViewStub.java b/ui/android/java/src/org/chromium/ui/AsyncViewStub.java
index 69848d0..0efa95bc 100644
--- a/ui/android/java/src/org/chromium/ui/AsyncViewStub.java
+++ b/ui/android/java/src/org/chromium/ui/AsyncViewStub.java
@@ -14,13 +14,14 @@
 import android.view.ViewGroup;
 import android.view.ViewParent;
 
-import androidx.annotation.NonNull;
 import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
 
 import org.chromium.base.Callback;
 import org.chromium.base.ObserverList;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.TraceEvent;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * An implementation of ViewStub that inflates the view in a background thread. Callbacks are still
@@ -28,9 +29,10 @@
  *
  * <p>TODO(crbug.com/40937701): Deprecate AsyncViewStub or make it per activity.
  */
+@NullMarked
 public class AsyncViewStub extends View implements AsyncLayoutInflater.OnInflateFinishedListener {
     private int mLayoutResource;
-    private View mInflatedView;
+    private @Nullable View mInflatedView;
 
     private AsyncLayoutInflater mAsyncLayoutInflater;
 
@@ -72,7 +74,8 @@
     protected void dispatchDraw(Canvas canvas) {}
 
     @Override
-    public void onInflateFinished(@NonNull View view, int resId, ViewGroup parent) {
+    public void onInflateFinished(View view, int resId, @Nullable ViewGroup parent) {
+        assert parent != null;
         mInflatedView = view;
         replaceSelfWithView(view, parent);
         callListeners(view);
@@ -135,6 +138,7 @@
     /**
      * @return the inflated view or null if inflation is not complete yet.
      */
+    @Nullable
     View getInflatedView() {
         return mInflatedView;
     }
diff --git a/ui/android/java/src/org/chromium/ui/DeferredViewStubInflationProvider.java b/ui/android/java/src/org/chromium/ui/DeferredViewStubInflationProvider.java
index 7da9d9d..85666008 100644
--- a/ui/android/java/src/org/chromium/ui/DeferredViewStubInflationProvider.java
+++ b/ui/android/java/src/org/chromium/ui/DeferredViewStubInflationProvider.java
@@ -9,12 +9,14 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.Promise;
+import org.chromium.build.annotations.NullMarked;
 
 /**
  * View provider that inflates a ViewStub. This does not support inflation on a background thread,
  * therefore {@link AsyncViewProvider} should be preferred.
  * @param <T> The view type.
  */
+@NullMarked
 public class DeferredViewStubInflationProvider<T extends View> implements ViewProvider<T> {
     private final ViewStub mViewStub;
     private Promise<T> mViewPromise = new Promise<>();
diff --git a/ui/android/java/src/org/chromium/ui/DropdownAdapter.java b/ui/android/java/src/org/chromium/ui/DropdownAdapter.java
index 62d08675..230d80a 100644
--- a/ui/android/java/src/org/chromium/ui/DropdownAdapter.java
+++ b/ui/android/java/src/org/chromium/ui/DropdownAdapter.java
@@ -4,6 +4,8 @@
 
 package org.chromium.ui;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.content.Context;
 import android.graphics.Color;
 import android.graphics.Typeface;
@@ -22,10 +24,15 @@
 import androidx.core.view.MarginLayoutParamsCompat;
 import androidx.core.view.ViewCompat;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
+
 import java.util.List;
 import java.util.Set;
 
 /** Dropdown item adapter for DropdownPopupWindow. */
+@NullMarked
 public class DropdownAdapter extends ArrayAdapter<DropdownItem> {
     private final Context mContext;
     private final Set<Integer> mSeparators;
@@ -51,7 +58,7 @@
 
     private boolean checkAreAllItemsEnabled() {
         for (int i = 0; i < getCount(); i++) {
-            DropdownItem item = getItem(i);
+            DropdownItem item = assumeNonNull(getItem(i));
             if (item.isEnabled() && !item.isGroupHeader()) {
                 return false;
             }
@@ -59,8 +66,9 @@
         return true;
     }
 
+    @NullUnmarked
     @Override
-    public View getView(int position, View convertView, ViewGroup parent) {
+    public View getView(int position, @Nullable View convertView, ViewGroup parent) {
         View layout = convertView;
         if (convertView == null) {
             LayoutInflater inflater =
@@ -88,7 +96,7 @@
             divider.setDividerColor(dividerColor);
         }
 
-        DropdownItem item = getItem(position);
+        DropdownItem item = assumeNonNull(getItem(position));
 
         // Note: trying to set the height of the root LinearLayout breaks accessibility,
         // so we have to adjust the height of this LinearLayout that wraps the TextViews instead.
@@ -179,7 +187,7 @@
     @Override
     public boolean isEnabled(int position) {
         if (position < 0 || position >= getCount()) return false;
-        DropdownItem item = getItem(position);
+        DropdownItem item = assumeNonNull(getItem(position));
         return item.isEnabled() && !item.isGroupHeader();
     }
 }
diff --git a/ui/android/java/src/org/chromium/ui/DropdownDividerDrawable.java b/ui/android/java/src/org/chromium/ui/DropdownDividerDrawable.java
index 7002ac01..8adfae6 100644
--- a/ui/android/java/src/org/chromium/ui/DropdownDividerDrawable.java
+++ b/ui/android/java/src/org/chromium/ui/DropdownDividerDrawable.java
@@ -11,18 +11,22 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
 /** A drawable divider to be used by dropdown adapters. */
+@NullMarked
 public class DropdownDividerDrawable extends Drawable {
     private final Paint mPaint;
     private final Rect mDividerRect;
-    private final Integer mBackgroundColor;
+    private final @Nullable Integer mBackgroundColor;
 
     /**
      * Creates a drawable to draw a divider line that separates the list of {@link DropdownItem}
      * and, optionally, paints the rectangular canvas.
      * @param backgroundColor Popup background color. If {@code null}, does not paint the canvas.
      */
-    public DropdownDividerDrawable(Integer backgroundColor) {
+    public DropdownDividerDrawable(@Nullable Integer backgroundColor) {
         mPaint = new Paint();
         mDividerRect = new Rect();
         mBackgroundColor = backgroundColor;
@@ -51,7 +55,7 @@
     public void setAlpha(int alpha) {}
 
     @Override
-    public void setColorFilter(ColorFilter cf) {}
+    public void setColorFilter(@Nullable ColorFilter cf) {}
 
     @Override
     public int getOpacity() {
diff --git a/ui/android/java/src/org/chromium/ui/DropdownItem.java b/ui/android/java/src/org/chromium/ui/DropdownItem.java
index 133f892..26b897c1 100644
--- a/ui/android/java/src/org/chromium/ui/DropdownItem.java
+++ b/ui/android/java/src/org/chromium/ui/DropdownItem.java
@@ -6,16 +6,18 @@
 
 import android.graphics.drawable.Drawable;
 
-import androidx.annotation.Nullable;
-
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.url.GURL;
 
 /** Dropdown item interface used to access all the information needed to show the item. */
+@NullMarked
 public interface DropdownItem {
     // A stand in for a resource ID which indicates no icon should be shown.
     public static final int NO_ICON = 0;
 
     /** Returns the first part of the first line that should be shown in the dropdown. */
+    @Nullable
     String getLabel();
 
     /** Returns the second part of the first line that should be shown in the dropdown. */
@@ -23,6 +25,7 @@
     String getSecondaryLabel();
 
     /** Returns the first part of the second line that should be shown in the dropdown. */
+    @Nullable
     String getSublabel();
 
     /** Returns the second part of the second line that should be shown in the dropdown. */
@@ -30,6 +33,7 @@
     String getSecondarySublabel();
 
     /** Returns the item tag that should be shown in the dropdown. */
+    @Nullable
     String getItemTag();
 
     /**
@@ -43,6 +47,7 @@
      * Returns the url for the icon to be downloaded. If present, the downloaded icon should be
      * preferred over the resource id returned by getIconId().
      */
+    @Nullable
     GURL getCustomIconUrl();
 
     /**
diff --git a/ui/android/java/src/org/chromium/ui/DropdownItemBase.java b/ui/android/java/src/org/chromium/ui/DropdownItemBase.java
index 1089a64..672a5216 100644
--- a/ui/android/java/src/org/chromium/ui/DropdownItemBase.java
+++ b/ui/android/java/src/org/chromium/ui/DropdownItemBase.java
@@ -6,37 +6,38 @@
 
 import android.graphics.drawable.Drawable;
 
-import androidx.annotation.Nullable;
-
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.url.GURL;
 
 /**
  * Base implementation of DropdownItem which is used to get default settings to
  * show the item.
  */
+@NullMarked
 public class DropdownItemBase implements DropdownItem {
     @Override
-    public String getLabel() {
+    public @Nullable String getLabel() {
         return null;
     }
 
     @Override
-    public String getSecondaryLabel() {
+    public @Nullable String getSecondaryLabel() {
         return null;
     }
 
     @Override
-    public String getSublabel() {
+    public @Nullable String getSublabel() {
         return null;
     }
 
     @Override
-    public String getSecondarySublabel() {
+    public @Nullable String getSecondarySublabel() {
         return null;
     }
 
     @Override
-    public String getItemTag() {
+    public @Nullable String getItemTag() {
         return null;
     }
 
@@ -101,13 +102,12 @@
     }
 
     @Override
-    public GURL getCustomIconUrl() {
+    public @Nullable GURL getCustomIconUrl() {
         return null;
     }
 
     @Override
-    @Nullable
-    public Drawable getIconDrawable() {
+    public @Nullable Drawable getIconDrawable() {
         return null;
     }
 }
diff --git a/ui/android/java/src/org/chromium/ui/DropdownPopupWindow.java b/ui/android/java/src/org/chromium/ui/DropdownPopupWindow.java
index 81a2c23..541ab6c 100644
--- a/ui/android/java/src/org/chromium/ui/DropdownPopupWindow.java
+++ b/ui/android/java/src/org/chromium/ui/DropdownPopupWindow.java
@@ -11,13 +11,14 @@
 import android.widget.ListView;
 import android.widget.PopupWindow;
 
-import androidx.annotation.Nullable;
-
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.widget.AnchoredPopupWindow;
 import org.chromium.ui.widget.RectProvider;
 
 // TODO(crbug.com/40250394): This class is a noop now, so we should remove it.
 /** The dropdown popup window that decides what widget should be used for the popup. */
+@NullMarked
 public class DropdownPopupWindow {
     private DropdownPopupWindowInterface mPopup;
 
diff --git a/ui/android/java/src/org/chromium/ui/DropdownPopupWindowImpl.java b/ui/android/java/src/org/chromium/ui/DropdownPopupWindowImpl.java
index 141c888..1d39210 100644
--- a/ui/android/java/src/org/chromium/ui/DropdownPopupWindowImpl.java
+++ b/ui/android/java/src/org/chromium/ui/DropdownPopupWindowImpl.java
@@ -15,9 +15,10 @@
 import android.widget.ListView;
 import android.widget.PopupWindow;
 
-import androidx.annotation.Nullable;
 import androidx.appcompat.content.res.AppCompatResources;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.widget.AnchoredPopupWindow;
 import org.chromium.ui.widget.RectProvider;
 import org.chromium.ui.widget.ViewRectProvider;
@@ -26,6 +27,7 @@
  * The dropdown popup window for use on Lollipop+. Internally uses an AnchoredPopupWindow
  * anchored to a view to display a list of options.
  */
+@NullMarked
 class DropdownPopupWindowImpl
         implements AnchoredPopupWindow.LayoutObserver, DropdownPopupWindowInterface {
     private final Context mContext;
@@ -33,9 +35,9 @@
     private boolean mRtl;
     private int mInitialSelection = -1;
     private OnLayoutChangeListener mLayoutChangeListener;
-    private CharSequence mDescription;
+    private @Nullable CharSequence mDescription;
     private AnchoredPopupWindow mAnchoredPopupWindow;
-    ListAdapter mAdapter;
+    @Nullable ListAdapter mAdapter;
 
     private final ListView mListView;
     private Drawable mBackground;
diff --git a/ui/android/java/src/org/chromium/ui/DropdownPopupWindowInterface.java b/ui/android/java/src/org/chromium/ui/DropdownPopupWindowInterface.java
index 0ea20fe..6aaeea04 100644
--- a/ui/android/java/src/org/chromium/ui/DropdownPopupWindowInterface.java
+++ b/ui/android/java/src/org/chromium/ui/DropdownPopupWindowInterface.java
@@ -9,7 +9,10 @@
 import android.widget.ListView;
 import android.widget.PopupWindow;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** The interface for dropdown popup window. */
+@NullMarked
 public interface DropdownPopupWindowInterface {
     /**
      * Sets the adapter that provides the data and the views to represent the data
diff --git a/ui/android/java/src/org/chromium/ui/ElidedUrlTextView.java b/ui/android/java/src/org/chromium/ui/ElidedUrlTextView.java
index 088992d..ddf5768 100644
--- a/ui/android/java/src/org/chromium/ui/ElidedUrlTextView.java
+++ b/ui/android/java/src/org/chromium/ui/ElidedUrlTextView.java
@@ -4,24 +4,31 @@
 
 package org.chromium.ui;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.content.Context;
 import android.text.Layout;
 import android.util.AttributeSet;
 
 import androidx.appcompat.widget.AppCompatTextView;
 
+import org.chromium.build.annotations.NullMarked;
+
 /**
  * A TextView which truncates and displays a URL such that the origin is always visible.
  * The URL can be expanded by clicking on the it.
  */
+@NullMarked
 public class ElidedUrlTextView extends AppCompatTextView {
     // The number of lines to display when the URL is truncated. This number
     // should still allow the origin to be displayed. NULL before
     // setUrlAfterLayout() is called.
+    @SuppressWarnings("NullAway.Init")
     private Integer mTruncatedUrlLinesToDisplay;
 
     // The number of lines to display when the URL is expanded. This should be enough to display
     // at most two lines of the fragment if there is one in the URL.
+    @SuppressWarnings("NullAway.Init")
     private Integer mFullLinesToDisplay;
 
     // If true, the text view will show the truncated text. If false, it
@@ -50,7 +57,7 @@
      * a given index.
      */
     private int getLineForIndex(int index) {
-        Layout layout = getLayout();
+        Layout layout = assumeNonNull(getLayout());
         int endLine = 0;
         while (endLine < layout.getLineCount() && layout.getLineEnd(endLine) < index) {
             endLine++;
diff --git a/ui/android/java/src/org/chromium/ui/HorizontalListDividerDrawable.java b/ui/android/java/src/org/chromium/ui/HorizontalListDividerDrawable.java
index 308509c1..443e404 100644
--- a/ui/android/java/src/org/chromium/ui/HorizontalListDividerDrawable.java
+++ b/ui/android/java/src/org/chromium/ui/HorizontalListDividerDrawable.java
@@ -10,12 +10,15 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 
+import org.chromium.build.annotations.NullMarked;
+
 /**
  * Draws a horizontal list divider line at the bottom of its drawing area.
  *
  * Because ?android:attr/listDivider may be a 9-patch, there's no way to achieve this drawing
  * effect with the platform Drawable classes; hence this custom Drawable.
  */
+@NullMarked
 public class HorizontalListDividerDrawable extends LayerDrawable {
     /**
      * Create a horizontal list divider drawable.
diff --git a/ui/android/java/src/org/chromium/ui/InsetObserver.java b/ui/android/java/src/org/chromium/ui/InsetObserver.java
index 90a1fd60..cf26c5e 100644
--- a/ui/android/java/src/org/chromium/ui/InsetObserver.java
+++ b/ui/android/java/src/org/chromium/ui/InsetObserver.java
@@ -8,8 +8,6 @@
 import android.view.View;
 
 import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.core.graphics.Insets;
 import androidx.core.view.DisplayCutoutCompat;
 import androidx.core.view.OnApplyWindowInsetsListener;
@@ -22,6 +20,8 @@
 import org.chromium.base.ResettersForTesting;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.InsetObserver.WindowInsetsConsumer.InsetConsumerSource;
 import org.chromium.ui.base.ImmutableWeakReference;
 
@@ -32,6 +32,7 @@
 /**
  * The purpose of this class is to store the system window insets (OSK, status bar) for later use.
  */
+@NullMarked
 public class InsetObserver implements OnApplyWindowInsetsListener {
     private final Rect mWindowInsets;
     private final Rect mCurrentSafeArea;
@@ -41,7 +42,7 @@
     private final WindowInsetsAnimationCompat.Callback mWindowInsetsAnimationProxyCallback;
     private final ObserverList<WindowInsetsAnimationListener> mWindowInsetsAnimationListeners =
             new ObserverList<>();
-    private final WindowInsetsConsumer[] mInsetsConsumers =
+    private final @Nullable WindowInsetsConsumer[] mInsetsConsumers =
             new WindowInsetsConsumer[InsetConsumerSource.COUNT];
 
     private final ImmutableWeakReference<View> mRootViewReference;
@@ -50,7 +51,7 @@
     private final Rect mDisplayCutoutRect;
 
     // Cached state
-    private WindowInsetsCompat mLastSeenRawWindowInset;
+    private @Nullable WindowInsetsCompat mLastSeenRawWindowInset;
     private static @Nullable WindowInsetsCompat sInitialRawWindowInsetsForTesting;
 
     /** Allows observing changes to the window insets from Android system UI. */
@@ -126,17 +127,16 @@
      * dispatched to the subtree. See {@link WindowInsetsAnimationCompat.Callback} for more.
      */
     public interface WindowInsetsAnimationListener {
-        void onPrepare(@NonNull WindowInsetsAnimationCompat animation);
+        void onPrepare(WindowInsetsAnimationCompat animation);
 
         void onStart(
-                @NonNull WindowInsetsAnimationCompat animation,
-                @NonNull WindowInsetsAnimationCompat.BoundsCompat bounds);
+                WindowInsetsAnimationCompat animation,
+                WindowInsetsAnimationCompat.BoundsCompat bounds);
 
         void onProgress(
-                @NonNull WindowInsetsCompat windowInsetsCompat,
-                @NonNull List<WindowInsetsAnimationCompat> list);
+                WindowInsetsCompat windowInsetsCompat, List<WindowInsetsAnimationCompat> list);
 
-        void onEnd(@NonNull WindowInsetsAnimationCompat animation);
+        void onEnd(WindowInsetsAnimationCompat animation);
     }
 
     private static class KeyboardInsetObservableSupplier extends ObservableSupplierImpl<Integer>
@@ -165,7 +165,7 @@
                 new WindowInsetsAnimationCompat.Callback(
                         WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_STOP) {
                     @Override
-                    public void onPrepare(@NonNull WindowInsetsAnimationCompat animation) {
+                    public void onPrepare(WindowInsetsAnimationCompat animation) {
                         for (WindowInsetsAnimationListener listener :
                                 mWindowInsetsAnimationListeners) {
                             listener.onPrepare(animation);
@@ -173,11 +173,9 @@
                         super.onPrepare(animation);
                     }
 
-                    @NonNull
                     @Override
                     public BoundsCompat onStart(
-                            @NonNull WindowInsetsAnimationCompat animation,
-                            @NonNull BoundsCompat bounds) {
+                            WindowInsetsAnimationCompat animation, BoundsCompat bounds) {
                         for (WindowInsetsAnimationListener listener :
                                 mWindowInsetsAnimationListeners) {
                             listener.onStart(animation, bounds);
@@ -186,7 +184,7 @@
                     }
 
                     @Override
-                    public void onEnd(@NonNull WindowInsetsAnimationCompat animation) {
+                    public void onEnd(WindowInsetsAnimationCompat animation) {
                         for (WindowInsetsAnimationListener listener :
                                 mWindowInsetsAnimationListeners) {
                             listener.onEnd(animation);
@@ -194,11 +192,10 @@
                         super.onEnd(animation);
                     }
 
-                    @NonNull
                     @Override
                     public WindowInsetsCompat onProgress(
-                            @NonNull WindowInsetsCompat windowInsetsCompat,
-                            @NonNull List<WindowInsetsAnimationCompat> list) {
+                            WindowInsetsCompat windowInsetsCompat,
+                            List<WindowInsetsAnimationCompat> list) {
                         for (WindowInsetsAnimationListener listener :
                                 mWindowInsetsAnimationListeners) {
                             listener.onProgress(windowInsetsCompat, list);
@@ -235,13 +232,13 @@
      * order of a pre-defined priority value.
      */
     public void addInsetsConsumer(
-            @NonNull WindowInsetsConsumer insetConsumer, @InsetConsumerSource int source) {
+            WindowInsetsConsumer insetConsumer, @InsetConsumerSource int source) {
         assert mInsetsConsumers[source] == null : "Inset consumer source has already been added.";
         mInsetsConsumers[source] = insetConsumer;
     }
 
     /** Remove a consumer of window insets. */
-    public void removeInsetsConsumer(@NonNull WindowInsetsConsumer insetConsumer) {
+    public void removeInsetsConsumer(WindowInsetsConsumer insetConsumer) {
         for (int i = 0; i < mInsetsConsumers.length; i++) {
             if (mInsetsConsumers[i] == insetConsumer) {
                 mInsetsConsumers[i] = null;
@@ -251,13 +248,12 @@
     }
 
     /** Add a listener for inset animations. */
-    public void addWindowInsetsAnimationListener(@NonNull WindowInsetsAnimationListener listener) {
+    public void addWindowInsetsAnimationListener(WindowInsetsAnimationListener listener) {
         mWindowInsetsAnimationListeners.addObserver(listener);
     }
 
     /** Remove a listener for inset animations. */
-    public void removeWindowInsetsAnimationListener(
-            @NonNull WindowInsetsAnimationListener listener) {
+    public void removeWindowInsetsAnimationListener(WindowInsetsAnimationListener listener) {
         mWindowInsetsAnimationListeners.removeObserver(listener);
     }
 
@@ -277,8 +273,7 @@
      * This should only be used for clients interested in reading a specific type of the insets;
      * otherwise, the client should be registered as a {@link WindowInsetsConsumer}.
      */
-    @Nullable
-    public WindowInsetsCompat getLastRawWindowInsets() {
+    public @Nullable WindowInsetsCompat getLastRawWindowInsets() {
         return mLastSeenRawWindowInset;
     }
 
@@ -294,10 +289,8 @@
         return mWindowInsetsAnimationProxyCallback;
     }
 
-    @NonNull
     @Override
-    public WindowInsetsCompat onApplyWindowInsets(
-            @NonNull View view, @NonNull WindowInsetsCompat insets) {
+    public WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat insets) {
         mLastSeenRawWindowInset = insets;
 
         updateDisplayCutoutRect(insets);
@@ -415,7 +408,7 @@
         ResettersForTesting.register(() -> sInitialRawWindowInsetsForTesting = null);
     }
 
-    private View getRootView() {
+    private @Nullable View getRootView() {
         return mRootViewReference.get();
     }
 }
diff --git a/ui/android/java/src/org/chromium/ui/InsetsRectProvider.java b/ui/android/java/src/org/chromium/ui/InsetsRectProvider.java
index 908ae6f..423197a 100644
--- a/ui/android/java/src/org/chromium/ui/InsetsRectProvider.java
+++ b/ui/android/java/src/org/chromium/ui/InsetsRectProvider.java
@@ -11,12 +11,13 @@
 import android.view.View;
 import android.view.WindowInsets;
 
-import androidx.annotation.NonNull;
 import androidx.core.graphics.Insets;
 import androidx.core.view.WindowInsetsCompat;
 import androidx.core.view.WindowInsetsCompat.Type.InsetsType;
 
 import org.chromium.base.ObserverList;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.InsetObserver.WindowInsetsConsumer;
 import org.chromium.ui.util.WindowInsetsUtils;
 
@@ -37,6 +38,7 @@
  * <li>1. Android version is at least R.
  * <li>2. WindowInsets of given type has insets from one side exactly.
  */
+@NullMarked
 public class InsetsRectProvider implements WindowInsetsConsumer {
     /** Observer interface that's interested in bounding rect updates. */
     public interface Observer {
@@ -50,7 +52,7 @@
     private final ObserverList<Observer> mObservers = new ObserverList<>();
     private final InsetObserver mInsetObserver;
 
-    private WindowInsetsCompat mCachedInsets;
+    private @Nullable WindowInsetsCompat mCachedInsets;
     private List<Rect> mBoundingRects;
     private Rect mWidestUnoccludedRect = new Rect();
 
@@ -65,7 +67,7 @@
      *     consumption.
      */
     public InsetsRectProvider(
-            @NonNull InsetObserver insetObserver,
+            InsetObserver insetObserver,
             @InsetsType int insetType,
             WindowInsetsCompat initialInsets,
             @InsetConsumerSource int insetConsumerSource) {
@@ -90,7 +92,6 @@
      * is an area within the window insets that is not covered by the bounding rects of that window
      * insets.
      */
-    @NonNull
     public Rect getWidestUnoccludedRect() {
         return mWidestUnoccludedRect;
     }
@@ -126,10 +127,10 @@
     }
 
     // Implements WindowInsetsConsumer
-    @NonNull
+
     @Override
     public WindowInsetsCompat onApplyWindowInsets(
-            @NonNull View view, @NonNull WindowInsetsCompat windowInsetsCompat) {
+            View view, WindowInsetsCompat windowInsetsCompat) {
         // Ignore the input by version check.
         if (VERSION.SDK_INT < VERSION_CODES.R) {
             return windowInsetsCompat;
diff --git a/ui/android/java/src/org/chromium/ui/KeyboardUtils.java b/ui/android/java/src/org/chromium/ui/KeyboardUtils.java
index 71999e4..5f94bf7 100644
--- a/ui/android/java/src/org/chromium/ui/KeyboardUtils.java
+++ b/ui/android/java/src/org/chromium/ui/KeyboardUtils.java
@@ -15,10 +15,12 @@
 
 import org.chromium.base.Log;
 import org.chromium.base.TraceEvent;
+import org.chromium.build.annotations.NullMarked;
 
 import java.util.concurrent.atomic.AtomicInteger;
 
 /** Utility methods used for Android's software keyboard. */
+@NullMarked
 public final class KeyboardUtils {
     private static final String TAG = "KeyboardVisibility";
 
diff --git a/ui/android/java/src/org/chromium/ui/KeyboardVisibilityDelegate.java b/ui/android/java/src/org/chromium/ui/KeyboardVisibilityDelegate.java
index 2275e92..5d7f283f 100644
--- a/ui/android/java/src/org/chromium/ui/KeyboardVisibilityDelegate.java
+++ b/ui/android/java/src/org/chromium/ui/KeyboardVisibilityDelegate.java
@@ -8,11 +8,13 @@
 import android.view.View;
 
 import org.chromium.base.ObserverList;
+import org.chromium.build.annotations.NullMarked;
 
 /**
  * A delegate that can be overridden to change the methods to figure out and change the current
  * state of Android's soft keyboard.
  */
+@NullMarked
 public class KeyboardVisibilityDelegate {
 
     /** The delegate to determine keyboard visibility. */
diff --git a/ui/android/java/src/org/chromium/ui/LayoutInflaterUtils.java b/ui/android/java/src/org/chromium/ui/LayoutInflaterUtils.java
index 43f72ab..53529e36 100644
--- a/ui/android/java/src/org/chromium/ui/LayoutInflaterUtils.java
+++ b/ui/android/java/src/org/chromium/ui/LayoutInflaterUtils.java
@@ -10,9 +10,9 @@
 import android.view.ViewGroup;
 import android.view.Window;
 
-import androidx.annotation.Nullable;
-
 import org.chromium.base.StrictModeContext;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * {@link LayoutInflater} wrapper class which suppresses strict mode violations. A helper class is
@@ -21,6 +21,7 @@
  * because we only want to suppress strict mode violations caused by Chromium usage of
  * LayoutInflater and not usage by embedders of Web Layer or Web View.
  */
+@NullMarked
 public class LayoutInflaterUtils {
     public static View inflate(Context context, int resource, @Nullable ViewGroup root) {
         return inflate(context, resource, root, root != null);
@@ -46,7 +47,7 @@
     }
 
     private static View inflateImpl(
-            LayoutInflater inflater, int resource, ViewGroup root, boolean attachToRoot) {
+            LayoutInflater inflater, int resource, @Nullable ViewGroup root, boolean attachToRoot) {
         // LayoutInflater may trigger accessing disk.
         try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) {
             return inflater.inflate(resource, root, attachToRoot);
diff --git a/ui/android/java/src/org/chromium/ui/ModalDialogWrapper.java b/ui/android/java/src/org/chromium/ui/ModalDialogWrapper.java
index e127919..7e35912 100644
--- a/ui/android/java/src/org/chromium/ui/ModalDialogWrapper.java
+++ b/ui/android/java/src/org/chromium/ui/ModalDialogWrapper.java
@@ -4,10 +4,14 @@
 
 package org.chromium.ui;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import org.jni_zero.CalledByNative;
 import org.jni_zero.JNINamespace;
 import org.jni_zero.NativeMethods;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.modaldialog.DialogDismissalCause;
 import org.chromium.ui.modaldialog.ModalDialogManager;
@@ -15,11 +19,12 @@
 import org.chromium.ui.modelutil.PropertyModel;
 
 @JNINamespace("ui")
+@NullMarked
 public class ModalDialogWrapper implements ModalDialogProperties.Controller {
     /** The native-side counterpart of this class */
     private final long mNativeDelegatePtr;
 
-    private final ModalDialogManager mModalDialogManager;
+    private final @Nullable ModalDialogManager mModalDialogManager;
 
     private final PropertyModel.Builder mPropertyModelBuilder;
 
@@ -55,10 +60,11 @@
 
     @Override
     public void onClick(PropertyModel model, int buttonType) {
+        ModalDialogManager modalDialogManager = assumeNonNull(mModalDialogManager);
         if (buttonType == ModalDialogProperties.ButtonType.POSITIVE) {
-            mModalDialogManager.dismissDialog(model, DialogDismissalCause.POSITIVE_BUTTON_CLICKED);
+            modalDialogManager.dismissDialog(model, DialogDismissalCause.POSITIVE_BUTTON_CLICKED);
         } else {
-            mModalDialogManager.dismissDialog(model, DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
+            modalDialogManager.dismissDialog(model, DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
         }
     }
 
diff --git a/ui/android/java/src/org/chromium/ui/MotionEventUtils.java b/ui/android/java/src/org/chromium/ui/MotionEventUtils.java
index f0e716ecd..d43cae1 100644
--- a/ui/android/java/src/org/chromium/ui/MotionEventUtils.java
+++ b/ui/android/java/src/org/chromium/ui/MotionEventUtils.java
@@ -7,9 +7,9 @@
 import android.os.Build;
 import android.view.MotionEvent;
 
-import androidx.annotation.Nullable;
-
 import org.chromium.base.TraceEvent;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -19,9 +19,10 @@
  *
  * <p>Not thread safe.
  */
+@NullMarked
 public class MotionEventUtils {
 
-    @Nullable private static Method sGetTimeNanoMethod;
+    private static @Nullable Method sGetTimeNanoMethod;
     private static boolean sFailedReflection;
 
     /**
@@ -61,7 +62,7 @@
     }
 
     private static boolean sFailedDoubleReflection;
-    private static Method sGetHistoricalEventTimeNanoMethod;
+    private static @Nullable Method sGetHistoricalEventTimeNanoMethod;
 
     /**
      * Returns the time in nanoseconds, but with precision to milliseconds, of the given
diff --git a/ui/android/java/src/org/chromium/ui/OverscrollRefreshHandler.java b/ui/android/java/src/org/chromium/ui/OverscrollRefreshHandler.java
index b8b8652..521e6c7 100644
--- a/ui/android/java/src/org/chromium/ui/OverscrollRefreshHandler.java
+++ b/ui/android/java/src/org/chromium/ui/OverscrollRefreshHandler.java
@@ -6,9 +6,11 @@
 
 import org.jni_zero.CalledByNative;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.base.BackGestureEventSwipeEdge;
 
 /** Simple interface allowing customized response to an overscrolling pull input. */
+@NullMarked
 public interface OverscrollRefreshHandler {
     /**
      * Signals the start of an overscrolling pull.
diff --git a/ui/android/java/src/org/chromium/ui/UiSwitches.java b/ui/android/java/src/org/chromium/ui/UiSwitches.java
index 583e730..91fa7d9 100644
--- a/ui/android/java/src/org/chromium/ui/UiSwitches.java
+++ b/ui/android/java/src/org/chromium/ui/UiSwitches.java
@@ -4,10 +4,13 @@
 
 package org.chromium.ui;
 
+import org.chromium.build.annotations.NullMarked;
+
 /**
  * Contains all of the command line switches that are specific to the ui/ portion of Chromium on
  * Android.
  */
+@NullMarked
 public abstract class UiSwitches {
     // Enables the screenshot mode, which disables certain UI elements (e.g. dialogs) to facilitate
     // more easily scripting screenshots of web content.
diff --git a/ui/android/java/src/org/chromium/ui/UiUtils.java b/ui/android/java/src/org/chromium/ui/UiUtils.java
index 914febb..0841642c 100644
--- a/ui/android/java/src/org/chromium/ui/UiUtils.java
+++ b/ui/android/java/src/org/chromium/ui/UiUtils.java
@@ -34,7 +34,6 @@
 import androidx.annotation.ColorRes;
 import androidx.annotation.DimenRes;
 import androidx.annotation.DrawableRes;
-import androidx.annotation.Nullable;
 import androidx.annotation.StyleableRes;
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.core.graphics.Insets;
@@ -44,6 +43,8 @@
 import org.chromium.base.BuildInfo;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 import java.io.File;
 import java.io.IOException;
@@ -55,6 +56,7 @@
  * Utility functions for common Android UI tasks.
  * This class is not supposed to be instantiated.
  */
+@NullMarked
 public class UiUtils {
     private static final String TAG = "UiUtils";
 
@@ -140,7 +142,7 @@
      * @param bitmapConfig     Bitmap config for the generated screenshot (ARGB_8888 or RGB_565).
      * @return The screen bitmap of the view or null if a problem was encountered.
      */
-    public static Bitmap generateScaledScreenshot(
+    public static @Nullable Bitmap generateScaledScreenshot(
             View currentView, int maximumDimension, Bitmap.Config bitmapConfig) {
         Bitmap screenshot = null;
         boolean drawingCacheEnabled = currentView.isDrawingCacheEnabled();
@@ -253,7 +255,7 @@
      *     height of all items stored at index 1.
      */
     public static int[] computeListAdapterContentDimensions(
-            ListAdapter adapter, ViewGroup parentView) {
+            ListAdapter adapter, @Nullable ViewGroup parentView) {
         final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
         final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
         AbsListView.LayoutParams params =
diff --git a/ui/android/java/src/org/chromium/ui/ViewProvider.java b/ui/android/java/src/org/chromium/ui/ViewProvider.java
index e472b9a..1004eb8 100644
--- a/ui/android/java/src/org/chromium/ui/ViewProvider.java
+++ b/ui/android/java/src/org/chromium/ui/ViewProvider.java
@@ -7,11 +7,13 @@
 import android.view.View;
 
 import org.chromium.base.Callback;
+import org.chromium.build.annotations.NullMarked;
 
 /**
  * Interface to support asynchronous inflation of views.
  * @param <T> The view type.
  */
+@NullMarked
 public interface ViewProvider<T> {
     /** Starts inflating the view. */
     void inflate();
diff --git a/ui/android/java/src/org/chromium/ui/animation/AnimationHandler.java b/ui/android/java/src/org/chromium/ui/animation/AnimationHandler.java
index 6ec0743..e315a96 100644
--- a/ui/android/java/src/org/chromium/ui/animation/AnimationHandler.java
+++ b/ui/android/java/src/org/chromium/ui/animation/AnimationHandler.java
@@ -7,8 +7,8 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 import java.util.Objects;
 
@@ -16,6 +16,7 @@
  * Keeps track of animations. Helps to ensure only one instance of this Animation is running at a
  * time.
  */
+@NullMarked
 public class AnimationHandler {
 
     private @Nullable Animator mCurrentAnimator;
@@ -32,7 +33,7 @@
      * Starts the animation. Ensures that the previous instance of the animation is complete prior
      * to starting said animation.
      */
-    public void startAnimation(@NonNull Animator animation) {
+    public void startAnimation(Animator animation) {
         if (mCurrentAnimator != null) {
             forceFinishAnimation();
         }
diff --git a/ui/android/java/src/org/chromium/ui/animation/AnimationPerformanceTracker.java b/ui/android/java/src/org/chromium/ui/animation/AnimationPerformanceTracker.java
index 31dde681..7fbea27b 100644
--- a/ui/android/java/src/org/chromium/ui/animation/AnimationPerformanceTracker.java
+++ b/ui/android/java/src/org/chromium/ui/animation/AnimationPerformanceTracker.java
@@ -6,14 +6,15 @@
 
 import android.os.SystemClock;
 
-import androidx.annotation.Nullable;
-
 import org.chromium.base.ObserverList;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * Helper class for monitoring animation performance. Each {@link AnimationPerformanceTracker} can
  * track a single animation at a time and can supply results to multiple {@link Listeners}.
  */
+@NullMarked
 public class AnimationPerformanceTracker {
     /** Tracks metrics about animation performance. */
     public static class AnimationMetrics {
diff --git a/ui/android/java/src/org/chromium/ui/animation/DrawableFadeInAnimatorFactory.java b/ui/android/java/src/org/chromium/ui/animation/DrawableFadeInAnimatorFactory.java
index 53b51de..df4b22d3 100644
--- a/ui/android/java/src/org/chromium/ui/animation/DrawableFadeInAnimatorFactory.java
+++ b/ui/android/java/src/org/chromium/ui/animation/DrawableFadeInAnimatorFactory.java
@@ -8,7 +8,10 @@
 import android.animation.ValueAnimator;
 import android.graphics.drawable.Drawable;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Factory class for creating fade in animations for {@link Drawable} elements. */
+@NullMarked
 public class DrawableFadeInAnimatorFactory {
     /**
      * Creates an animation for fading a {@link Drawable} element in.
diff --git a/ui/android/java/src/org/chromium/ui/animation/DrawableTranslationAnimatorFactory.java b/ui/android/java/src/org/chromium/ui/animation/DrawableTranslationAnimatorFactory.java
index 2641f22..c5c2f28 100644
--- a/ui/android/java/src/org/chromium/ui/animation/DrawableTranslationAnimatorFactory.java
+++ b/ui/android/java/src/org/chromium/ui/animation/DrawableTranslationAnimatorFactory.java
@@ -10,7 +10,10 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Factory class for creating translation animations for {@link Drawable} elements. */
+@NullMarked
 public class DrawableTranslationAnimatorFactory {
     /**
      * Creates an animation for translations. The animator will begin at the maximum displacement
diff --git a/ui/android/java/src/org/chromium/ui/animation/EmptyAnimationListener.java b/ui/android/java/src/org/chromium/ui/animation/EmptyAnimationListener.java
index 4c731fe..1203c8c 100644
--- a/ui/android/java/src/org/chromium/ui/animation/EmptyAnimationListener.java
+++ b/ui/android/java/src/org/chromium/ui/animation/EmptyAnimationListener.java
@@ -7,7 +7,10 @@
 import android.view.animation.Animation;
 import android.view.animation.Animation.AnimationListener;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Simple no-op default interface that allows subclasses to only implement methods as needed. */
+@NullMarked
 public interface EmptyAnimationListener extends AnimationListener {
     @Override
     default void onAnimationStart(Animation animation) {}
diff --git a/ui/android/java/src/org/chromium/ui/animation/PathAnimationUtils.java b/ui/android/java/src/org/chromium/ui/animation/PathAnimationUtils.java
index 16f75cab..7274c35 100644
--- a/ui/android/java/src/org/chromium/ui/animation/PathAnimationUtils.java
+++ b/ui/android/java/src/org/chromium/ui/animation/PathAnimationUtils.java
@@ -6,7 +6,10 @@
 
 import android.graphics.RectF;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Utilities related to {@link android.graphics.Path} for animations */
+@NullMarked
 public class PathAnimationUtils {
     /**
      * Returns a RectF which represents the oval to perform Path#arcTo movements.
diff --git a/ui/android/java/src/org/chromium/ui/animation/TranslationAnimatorFactory.java b/ui/android/java/src/org/chromium/ui/animation/TranslationAnimatorFactory.java
index 5f9120f5f..d42fa084 100644
--- a/ui/android/java/src/org/chromium/ui/animation/TranslationAnimatorFactory.java
+++ b/ui/android/java/src/org/chromium/ui/animation/TranslationAnimatorFactory.java
@@ -7,7 +7,10 @@
 import android.animation.Animator;
 import android.animation.ValueAnimator;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Factory class for creating animations for translations. */
+@NullMarked
 public class TranslationAnimatorFactory {
 
     @FunctionalInterface
diff --git a/ui/android/java/src/org/chromium/ui/base/ActivityIntentRequestTrackerDelegate.java b/ui/android/java/src/org/chromium/ui/base/ActivityIntentRequestTrackerDelegate.java
index 7375d11..0cbe702 100644
--- a/ui/android/java/src/org/chromium/ui/base/ActivityIntentRequestTrackerDelegate.java
+++ b/ui/android/java/src/org/chromium/ui/base/ActivityIntentRequestTrackerDelegate.java
@@ -10,11 +10,14 @@
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.base.IntentRequestTracker.Delegate;
 
 import java.lang.ref.WeakReference;
 
 /** Chrome's implementation of the delegate of a IntentRequestTracker. */
+@NullMarked
 public class ActivityIntentRequestTrackerDelegate implements Delegate {
     // Just create one ImmutableWeakReference object to avoid gc churn.
     private final ImmutableWeakReference<Activity> mActivityWeakRefHolder;
@@ -29,7 +32,7 @@
     }
 
     @Override
-    public boolean startActivityForResult(Intent intent, int requestCode) {
+    public boolean startActivityForResult(@Nullable Intent intent, int requestCode) {
         Activity activity = mActivityWeakRefHolder.get();
         if (activity == null) return false;
         try {
diff --git a/ui/android/java/src/org/chromium/ui/base/ActivityKeyboardVisibilityDelegate.java b/ui/android/java/src/org/chromium/ui/base/ActivityKeyboardVisibilityDelegate.java
index 7c4550d8..3981e51 100644
--- a/ui/android/java/src/org/chromium/ui/base/ActivityKeyboardVisibilityDelegate.java
+++ b/ui/android/java/src/org/chromium/ui/base/ActivityKeyboardVisibilityDelegate.java
@@ -4,14 +4,16 @@
 
 package org.chromium.ui.base;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.app.Activity;
 import android.view.View;
 
-import androidx.annotation.Nullable;
-
 import org.chromium.base.Callback;
 import org.chromium.base.supplier.LazyOneshotSupplier;
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.KeyboardVisibilityDelegate;
 
 import java.lang.ref.WeakReference;
@@ -22,14 +24,15 @@
  * the layout or keyboard inset change is suspected to be related to a software keyboard changing
  * visibility.
  */
+@NullMarked
 public class ActivityKeyboardVisibilityDelegate extends KeyboardVisibilityDelegate
         implements View.OnLayoutChangeListener {
     private final Callback<Integer> mOnKeyboardInsetChanged = this::onKeyboardInsetChanged;
 
     private WeakReference<Activity> mActivity;
-    private LazyOneshotSupplier<ObservableSupplier<Integer>> mLazyKeyboardInsetSupplier;
+    private @Nullable LazyOneshotSupplier<ObservableSupplier<Integer>> mLazyKeyboardInsetSupplier;
     private boolean mIsKeyboardShowing;
-    private View mContentViewForTesting;
+    private @Nullable View mContentViewForTesting;
 
     /**
      * Creates a new delegate listening to the given activity. If the activity is destroyed, it will
@@ -48,7 +51,7 @@
         assert mLazyKeyboardInsetSupplier == null;
         mLazyKeyboardInsetSupplier = lazyKeyboardInsetSupplier;
         if (hasKeyboardVisibilityListeners()) {
-            mLazyKeyboardInsetSupplier.get().addObserver(mOnKeyboardInsetChanged);
+            assumeNonNull(lazyKeyboardInsetSupplier.get()).addObserver(mOnKeyboardInsetChanged);
         }
     }
 
@@ -66,7 +69,7 @@
 
         if (mLazyKeyboardInsetSupplier == null) return;
 
-        mLazyKeyboardInsetSupplier.get().addObserver(mOnKeyboardInsetChanged);
+        assumeNonNull(mLazyKeyboardInsetSupplier.get()).addObserver(mOnKeyboardInsetChanged);
     }
 
     @Override
@@ -77,7 +80,7 @@
 
         if (mLazyKeyboardInsetSupplier == null) return;
 
-        mLazyKeyboardInsetSupplier.get().removeObserver(mOnKeyboardInsetChanged);
+        assumeNonNull(mLazyKeyboardInsetSupplier.get()).removeObserver(mOnKeyboardInsetChanged);
     }
 
     @Override
diff --git a/ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java
index 666a736..774d98e2 100644
--- a/ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java
@@ -7,14 +7,13 @@
 import android.app.Activity;
 import android.content.Context;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.supplier.LazyOneshotSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.InsetObserver;
 import org.chromium.ui.permissions.ActivityAndroidPermissionDelegate;
 
@@ -24,13 +23,14 @@
  * The class provides the WindowAndroid's implementation which requires Activity Instance. Only
  * instantiate this class when you need the implemented features.
  */
+@NullMarked
 public class ActivityWindowAndroid extends WindowAndroid
         implements ApplicationStatus.ActivityStateListener,
                 ApplicationStatus.WindowFocusChangedListener {
     private final boolean mListenToActivityState;
 
     // Just create one ImmutableWeakReference object to avoid gc churn.
-    private ImmutableWeakReference<Activity> mActivityWeakRefHolder;
+    private @Nullable ImmutableWeakReference<Activity> mActivityWeakRefHolder;
 
     /**
      * Creates an Activity-specific WindowAndroid with associated intent functionality.
@@ -70,7 +70,7 @@
     public ActivityWindowAndroid(
             Context context,
             boolean listenToActivityState,
-            @NonNull ActivityKeyboardVisibilityDelegate keyboardVisibilityDelegate,
+            ActivityKeyboardVisibilityDelegate keyboardVisibilityDelegate,
             IntentRequestTracker intentRequestTracker,
             InsetObserver insetObserver,
             boolean trackOcclusion) {
@@ -100,7 +100,7 @@
             ActivityAndroidPermissionDelegate activityAndroidPermissionDelegate,
             ActivityKeyboardVisibilityDelegate activityKeyboardVisibilityDelegate,
             IntentRequestTracker intentRequestTracker,
-            InsetObserver insetObserver,
+            @Nullable InsetObserver insetObserver,
             boolean trackOcclusion) {
         super(context, intentRequestTracker, insetObserver, trackOcclusion);
         Activity activity = ContextUtils.activityFromContext(context);
@@ -116,7 +116,7 @@
         activityKeyboardVisibilityDelegate.setLazyKeyboardInsetSupplier(
                 LazyOneshotSupplier.fromSupplier(
                         () -> {
-                            if (getInsetObserver() == null) {
+                            if (insetObserver == null) {
                                 // An InsetObserver can no longer be created. Stub this out so
                                 // calls continue to succeed.
                                 return new ObservableSupplierImpl<Integer>();
diff --git a/ui/android/java/src/org/chromium/ui/base/ApplicationViewportInsetSupplier.java b/ui/android/java/src/org/chromium/ui/base/ApplicationViewportInsetSupplier.java
index e19a08d..388bf37 100644
--- a/ui/android/java/src/org/chromium/ui/base/ApplicationViewportInsetSupplier.java
+++ b/ui/android/java/src/org/chromium/ui/base/ApplicationViewportInsetSupplier.java
@@ -8,6 +8,8 @@
 import org.chromium.base.lifetime.Destroyable;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.mojom.VirtualKeyboardMode;
 
 /**
@@ -41,14 +43,15 @@
  *    ObservableSupplier<ViewportInsets>} object.
  * </pre>
  */
+@NullMarked
 public class ApplicationViewportInsetSupplier extends ObservableSupplierImpl<ViewportInsets>
         implements Destroyable {
     /** Keyboard related suppliers */
-    private ObservableSupplier<Integer> mKeyboardInsetSupplier;
+    private @Nullable ObservableSupplier<Integer> mKeyboardInsetSupplier;
 
-    private ObservableSupplier<Integer> mKeyboardAccessoryInsetSupplier;
+    private @Nullable ObservableSupplier<Integer> mKeyboardAccessoryInsetSupplier;
 
-    private ObservableSupplier<Integer> mBottomSheetInsetSupplier;
+    private @Nullable ObservableSupplier<Integer> mBottomSheetInsetSupplier;
 
     /** The observer that gets attached to all inset suppliers. */
     private final Callback<Integer> mInsetSupplierObserver = (unused) -> computeInsets();
@@ -106,7 +109,7 @@
      *
      * Pass null to unset the current supplier.
      */
-    public void setKeyboardInsetSupplier(ObservableSupplier<Integer> insetSupplier) {
+    public void setKeyboardInsetSupplier(@Nullable ObservableSupplier<Integer> insetSupplier) {
         boolean didRemove = false;
 
         if (mKeyboardInsetSupplier != null) {
@@ -130,7 +133,8 @@
      *
      * Pass null to unset the current supplier.
      */
-    public void setKeyboardAccessoryInsetSupplier(ObservableSupplier<Integer> insetSupplier) {
+    public void setKeyboardAccessoryInsetSupplier(
+            @Nullable ObservableSupplier<Integer> insetSupplier) {
         boolean didRemove = false;
         if (mKeyboardAccessoryInsetSupplier != null) {
             mKeyboardAccessoryInsetSupplier.removeObserver(mInsetSupplierObserver);
@@ -203,7 +207,7 @@
         super.set(newValues);
     }
 
-    private int intFromSupplier(ObservableSupplier<Integer> supplier) {
+    private int intFromSupplier(@Nullable ObservableSupplier<Integer> supplier) {
         if (supplier == null || supplier.get() == null) return 0;
         return supplier.get();
     }
diff --git a/ui/android/java/src/org/chromium/ui/base/BytesFormatting.java b/ui/android/java/src/org/chromium/ui/base/BytesFormatting.java
index 83a7f71..7b13df4c 100644
--- a/ui/android/java/src/org/chromium/ui/base/BytesFormatting.java
+++ b/ui/android/java/src/org/chromium/ui/base/BytesFormatting.java
@@ -7,8 +7,11 @@
 import org.jni_zero.JNINamespace;
 import org.jni_zero.NativeMethods;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Java mirror of ui/base/text/bytes_formatting.h. */
 @JNINamespace("ui")
+@NullMarked
 public class BytesFormatting {
 
     /**
diff --git a/ui/android/java/src/org/chromium/ui/base/Clipboard.java b/ui/android/java/src/org/chromium/ui/base/Clipboard.java
index 44c03fe..6d2ff02 100644
--- a/ui/android/java/src/org/chromium/ui/base/Clipboard.java
+++ b/ui/android/java/src/org/chromium/ui/base/Clipboard.java
@@ -10,8 +10,6 @@
 import android.content.Context;
 import android.net.Uri;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import org.jni_zero.CalledByNative;
@@ -21,15 +19,18 @@
 import org.chromium.base.Callback;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.url.GURL;
 
 /** Simple proxy that provides C++ code with an access pathway to the Android clipboard. */
 @JNINamespace("ui")
+@NullMarked
 public class Clipboard {
     private static final String TAG = "Clipboard";
 
     @SuppressLint("StaticFieldLeak")
-    private static Clipboard sInstance;
+    private static @Nullable Clipboard sInstance;
 
     private long mNativeClipboard;
 
@@ -63,7 +64,7 @@
          * On Android O and O_MR1, URI is stored for revoking permissions later.
          * @param clipboardFileMetadata The metadata needs to be stored.
          */
-        void storeLastCopiedImageMetadata(@NonNull ClipboardFileMetadata clipboardFileMetadata);
+        void storeLastCopiedImageMetadata(ClipboardFileMetadata clipboardFileMetadata);
 
         /** Get stored the last image uri and its timestamp. */
         @Nullable
@@ -129,7 +130,7 @@
      */
     @SuppressWarnings("javadoc")
     @CalledByNative
-    protected String getCoercedText() {
+    protected @Nullable String getCoercedText() {
         return null;
     }
 
@@ -139,7 +140,7 @@
         return false;
     }
 
-    public String clipDataToHtmlText(ClipData clipData) {
+    public @Nullable String clipDataToHtmlText(ClipData clipData) {
         return null;
     }
 
@@ -150,7 +151,7 @@
      *         text or no entries on the primary clip.
      */
     @CalledByNative
-    protected String getHTMLText() {
+    protected @Nullable String getHTMLText() {
         return null;
     }
 
@@ -179,6 +180,7 @@
      */
     @CalledByNative
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    @Nullable
     String getUrl() {
         return null;
     }
@@ -200,7 +202,7 @@
     }
 
     @CalledByNative
-    protected String getImageUriString() {
+    protected @Nullable String getImageUriString() {
         return null;
     }
 
@@ -212,7 +214,7 @@
      * @return a byte array of PNG data if available, otherwise null.
      */
     @CalledByNative
-    public byte[] getPng() {
+    public byte @Nullable [] getPng() {
         return null;
     }
 
@@ -229,7 +231,7 @@
      *     optional display name which will be an empty string when unknown.
      */
     @CalledByNative
-    protected String[][] getFilenames() {
+    protected String @Nullable [][] getFilenames() {
         return null;
     }
 
diff --git a/ui/android/java/src/org/chromium/ui/base/ClipboardImpl.java b/ui/android/java/src/org/chromium/ui/base/ClipboardImpl.java
index 99355e9..7b8acf27 100644
--- a/ui/android/java/src/org/chromium/ui/base/ClipboardImpl.java
+++ b/ui/android/java/src/org/chromium/ui/base/ClipboardImpl.java
@@ -25,8 +25,6 @@
 import android.view.textclassifier.TextClassifier;
 import android.view.textclassifier.TextLinks;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
 import androidx.annotation.VisibleForTesting;
 
@@ -41,6 +39,9 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.task.AsyncTask;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.components.url_formatter.UrlFormatter;
 import org.chromium.ui.R;
 import org.chromium.ui.widget.Toast;
@@ -55,6 +56,7 @@
 
 /** Simple proxy that provides C++ code with an access pathway to the Android clipboard. */
 @JNINamespace("ui")
+@NullMarked
 public class ClipboardImpl extends Clipboard
         implements ClipboardManager.OnPrimaryClipChangedListener {
     private static final float CONFIDENCE_THRESHOLD_FOR_URL_DETECTION = 0.99f;
@@ -81,9 +83,9 @@
 
     private ClipboardManager mClipboardManager;
 
-    private ImageFileProvider mImageFileProvider;
+    private @Nullable ImageFileProvider mImageFileProvider;
 
-    private ImageFileProvider.ClipboardFileMetadata mPendingCopiedImageMetadata;
+    private ImageFileProvider.@Nullable ClipboardFileMetadata mPendingCopiedImageMetadata;
 
     public ClipboardImpl(ClipboardManager clipboardManager) {
         mContext = ContextUtils.getApplicationContext();
@@ -91,8 +93,9 @@
         mClipboardManager.addPrimaryClipChangedListener(this);
     }
 
+    @NullUnmarked
     @Override
-    protected String getCoercedText() {
+    protected @Nullable String getCoercedText() {
         // getPrimaryClip() has been observed to throw unexpected exceptions for some devices (see
         // crbug.com/654802 and b/31501780)
         try {
@@ -135,8 +138,9 @@
         return false;
     }
 
+    @NullUnmarked
     @Override
-    public String clipDataToHtmlText(ClipData clipData) {
+    public @Nullable String clipDataToHtmlText(@Nullable ClipData clipData) {
         ClipDescription description = clipData.getDescription();
         if (description.hasMimeType(ClipDescription.MIMETYPE_TEXT_HTML)) {
             return clipData.getItemAt(0).getHtmlText();
@@ -154,7 +158,7 @@
     }
 
     @Override
-    protected String getHTMLText() {
+    protected @Nullable String getHTMLText() {
         // getPrimaryClip() has been observed to throw unexpected exceptions for some devices (see
         // crbug/654802 and b/31501780)
         try {
@@ -175,6 +179,7 @@
                 || description.hasMimeType(ClipDescription.MIMETYPE_TEXT_HTML);
     }
 
+    @NullUnmarked
     @Override
     boolean hasUrl() {
         // ClipDescription#getConfidenceScore is only available on Android S+, so before Android S,
@@ -201,7 +206,9 @@
         }
     }
 
+    @NullUnmarked
     @Override
+    @Nullable
     String getUrl() {
         if (!hasUrl()) return null;
 
@@ -276,13 +283,14 @@
     }
 
     @Override
-    protected String getImageUriString() {
+    protected @Nullable String getImageUriString() {
         Uri uri = getImageUri();
         return uri == null ? null : uri.toString();
     }
 
+    @NullUnmarked
     @Override
-    public byte[] getPng() {
+    public byte @Nullable [] getPng() {
         ThreadUtils.assertOnBackgroundThread();
 
         Uri uri = getImageUri();
@@ -335,7 +343,7 @@
         return hasImageMimeType(description);
     }
 
-    private static boolean hasImageMimeType(ClipDescription description) {
+    private static boolean hasImageMimeType(@Nullable ClipDescription description) {
         return (description != null)
                 && (description.hasMimeType("image/*")
                         || (sSkipImageMimeTypeCheckForTesting != null
@@ -352,6 +360,7 @@
         return description.getTimestamp();
     }
 
+    @NullUnmarked
     @Override
     protected String[][] getFilenames() {
         // getPrimaryClip() has been observed to throw unexpected exceptions for some devices (see
@@ -376,6 +385,7 @@
         return uris.toArray(new String[][] {});
     }
 
+    @NullUnmarked
     @Override
     public boolean hasFilenames() {
         // getPrimaryClip() has been observed to throw unexpected exceptions for some devices (see
@@ -449,7 +459,7 @@
             }
 
             @Override
-            protected void onPostExecute(ClipData clipData) {
+            protected void onPostExecute(@Nullable ClipData clipData) {
                 if (setPrimaryClipNoException(clipData) && notifyOnSuccess) {
                     showToastIfNeeded(R.string.image_copied);
                 }
@@ -535,8 +545,9 @@
         }
     }
 
+    @NullUnmarked
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    boolean setPrimaryClipNoException(ClipData clip) {
+    boolean setPrimaryClipNoException(@Nullable ClipData clip) {
         final String manufacturer = Build.MANUFACTURER.toLowerCase(Locale.US);
         // See crbug.com/1123727, there are OEM devices having strict mode violations in their
         // Android framework code. Disabling strict mode for non-google devices.
@@ -618,7 +629,7 @@
      * individually. Note: Don't forget to revoke the permission once the clipboard is updated.
      */
     @SuppressWarnings("QueryPermissionsNeeded")
-    private void grantUriPermission(@NonNull Uri uri) {
+    private void grantUriPermission(Uri uri) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P || mImageFileProvider == null) {
             return;
         }
@@ -704,6 +715,7 @@
         }
     }
 
+    @NullUnmarked
     private boolean hasStyledTextOnPreS() {
         CharSequence text;
         try {
diff --git a/ui/android/java/src/org/chromium/ui/base/DeviceFormFactor.java b/ui/android/java/src/org/chromium/ui/base/DeviceFormFactor.java
index 26aca0b3..be25bf5f 100644
--- a/ui/android/java/src/org/chromium/ui/base/DeviceFormFactor.java
+++ b/ui/android/java/src/org/chromium/ui/base/DeviceFormFactor.java
@@ -11,16 +11,27 @@
 
 import org.jni_zero.CalledByNative;
 
+import org.chromium.build.BuildConfig;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.ResettersForTesting;
 import org.chromium.base.ThreadUtils;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.R;
 import org.chromium.ui.display.DisplayAndroid;
 import org.chromium.ui.display.DisplayUtil;
 
 /** UI utilities for accessing form factor information. */
+@NullMarked
 public class DeviceFormFactor {
     /**
+     * Desktop form factor.
+     *
+     * <p>Identified by <code>isDesktop() == true</code>.
+     */
+    public static final String DESKTOP = "Desktop";
+
+    /**
      * Phone form factor.
      *
      * <p>Identified by <code>isNonMultiDisplayContextOnTablet() == false</code>.
@@ -47,7 +58,16 @@
     private static final int SCREEN_BUCKET_LARGET_TABLET = 3;
 
     /** See {@link #setIsTabletForTesting(boolean)}. */
-    private static Boolean sIsTabletForTesting;
+    private static @Nullable Boolean sIsTabletForTesting;
+
+    /**
+     * Only devices built with IS_DESKTOP_ANDROID will return true.
+     *
+     * @return Whether the device is a Desktop.
+     */
+    public static boolean isDesktop() {
+        return BuildConfig.IS_DESKTOP_ANDROID;
+    }
 
     /**
      * Each activity could be on a different display, and this will just tell you whether the
diff --git a/ui/android/java/src/org/chromium/ui/base/DeviceInput.java b/ui/android/java/src/org/chromium/ui/base/DeviceInput.java
index 867272c2..a96c8ca8 100644
--- a/ui/android/java/src/org/chromium/ui/base/DeviceInput.java
+++ b/ui/android/java/src/org/chromium/ui/base/DeviceInput.java
@@ -18,12 +18,15 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.ResettersForTesting;
 import org.chromium.base.ThreadUtils;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * Utilities for accessing device input information. Note that this class is not thread-safe and
  * currently asserts all interactions occur on the UI thread. If usage is required off the UI thread
  * in the future, this class can be modified for multi-thread support.
  */
+@NullMarked
 public class DeviceInput implements InputDeviceListener {
 
     /** Wrapper class which provides lazy initialization of a singleton instance. */
@@ -32,10 +35,10 @@
     }
 
     /** See {@link #setSupportsAlphabeticKeyboardForTesting(boolean)}. */
-    private static Boolean sSupportsAlphabeticKeyboardForTesting;
+    private static @Nullable Boolean sSupportsAlphabeticKeyboardForTesting;
 
     /** See {@link #setSupportsPrevisionPointerForTesting(boolean)}. */
-    private static Boolean sSupportsPrecisionPointerForTesting;
+    private static @Nullable Boolean sSupportsPrecisionPointerForTesting;
 
     /** Cached snapshots of all currently connected {@link InputDevice}s. */
     private final SparseArray<DeviceSnapshot> mDeviceSnapshotsById = new SparseArray<>();
diff --git a/ui/android/java/src/org/chromium/ui/base/EventForwarder.java b/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
index 4cbc05cf..d878949 100644
--- a/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
+++ b/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
@@ -25,6 +25,9 @@
 import org.chromium.base.Log;
 import org.chromium.base.TraceEvent;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.MotionEventUtils;
 
 import java.lang.reflect.UndeclaredThrowableException;
@@ -33,6 +36,7 @@
 
 /** Class used to forward view, input events down to native. */
 @JNINamespace("ui")
+@NullMarked
 public class EventForwarder {
     private static final String TAG = "EventForwarder";
     private final boolean mIsDragDropEnabled;
@@ -65,7 +69,7 @@
     private float mLastTrackpadScrollStartRawY;
 
     // Delegate to call WebContents functionality.
-    private StylusWritingDelegate mStylusWritingDelegate;
+    private @Nullable StylusWritingDelegate mStylusWritingDelegate;
 
     /** Interface to provide stylus writing functionality. */
     public interface StylusWritingDelegate {
@@ -592,6 +596,7 @@
      * @param event {@link DragEvent} instance.
      * @param containerView A view on which the drag event is taking place.
      */
+    @NullUnmarked
     public boolean onDragEvent(DragEvent event, View containerView) {
         ClipDescription clipDescription = event.getClipDescription();
         // Do not forward chrome/tab events to native eventForwarder.
@@ -904,9 +909,9 @@
                 String[] mimeTypes,
                 String content,
                 String[][] filenames,
-                String text,
-                String html,
-                String url);
+                @Nullable String text,
+                @Nullable String html,
+                @Nullable String url);
 
         boolean onGestureEvent(
                 long nativeEventForwarder,
diff --git a/ui/android/java/src/org/chromium/ui/base/EventOffsetHandler.java b/ui/android/java/src/org/chromium/ui/base/EventOffsetHandler.java
index c541b01d..26cdc363 100644
--- a/ui/android/java/src/org/chromium/ui/base/EventOffsetHandler.java
+++ b/ui/android/java/src/org/chromium/ui/base/EventOffsetHandler.java
@@ -9,10 +9,13 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import org.chromium.build.annotations.NullMarked;
+
 /**
  * A class to update motion event offset while dragging. This is needed to compensate the change
  * caused by top control.
  */
+@NullMarked
 public class EventOffsetHandler {
     /** A delegate for EventOffsetHandler. */
     public interface EventOffsetHandlerDelegate {
diff --git a/ui/android/java/src/org/chromium/ui/base/IdleDetector.java b/ui/android/java/src/org/chromium/ui/base/IdleDetector.java
index 141ae6a..2a05e77 100644
--- a/ui/android/java/src/org/chromium/ui/base/IdleDetector.java
+++ b/ui/android/java/src/org/chromium/ui/base/IdleDetector.java
@@ -16,6 +16,7 @@
 import org.jni_zero.JNINamespace;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.build.annotations.NullMarked;
 
 import java.util.concurrent.TimeUnit;
 
@@ -24,6 +25,7 @@
  * idle detection.
  */
 @JNINamespace("ui")
+@NullMarked
 public class IdleDetector extends BroadcastReceiver {
     private static final String TAG = "IdleDetector";
     // Memory handled by idle_android:cc: a singleton (```detector```) gets
@@ -54,9 +56,9 @@
 
     @Override
     public void onReceive(Context context, Intent intent) {
-        if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
+        if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
             start();
-        } else if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)) {
+        } else if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
             reset();
         }
     }
diff --git a/ui/android/java/src/org/chromium/ui/base/ImmutableWeakReference.java b/ui/android/java/src/org/chromium/ui/base/ImmutableWeakReference.java
index acf0248a..a71ebed 100644
--- a/ui/android/java/src/org/chromium/ui/base/ImmutableWeakReference.java
+++ b/ui/android/java/src/org/chromium/ui/base/ImmutableWeakReference.java
@@ -4,6 +4,9 @@
 
 package org.chromium.ui.base;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
 import java.lang.ref.WeakReference;
 
 /**
@@ -11,8 +14,9 @@
  * This is so that it's safe to pass the same instance to multiple
  * clients without worrying about modification.
  */
+@NullMarked
 public class ImmutableWeakReference<T> extends WeakReference<T> {
-    public ImmutableWeakReference(T referent) {
+    public ImmutableWeakReference(@Nullable T referent) {
         super(referent);
     }
 
diff --git a/ui/android/java/src/org/chromium/ui/base/IntentRequestTracker.java b/ui/android/java/src/org/chromium/ui/base/IntentRequestTracker.java
index 11bb66e..8f7af3a 100644
--- a/ui/android/java/src/org/chromium/ui/base/IntentRequestTracker.java
+++ b/ui/android/java/src/org/chromium/ui/base/IntentRequestTracker.java
@@ -9,6 +9,8 @@
 import android.content.IntentSender;
 import android.os.Bundle;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.base.WindowAndroid.IntentCallback;
 
 import java.lang.ref.WeakReference;
@@ -17,6 +19,7 @@
  * The interface for a helper class that keeps track of the intent requests for an Activity. Its
  * implementation should be hidden in ui/base. No implementation should be made outside of ui/base.
  */
+@NullMarked
 public interface IntentRequestTracker {
     /** A delegate of this class's intent sending. */
     interface Delegate {
@@ -24,7 +27,7 @@
          * Starts an activity for the provided intent.
          * @see Activity#startActivityForResult
          */
-        boolean startActivityForResult(Intent intent, int requestCode);
+        boolean startActivityForResult(@Nullable Intent intent, int requestCode);
 
         /**
          * Uses the provided intent sender to start the intent.
diff --git a/ui/android/java/src/org/chromium/ui/base/IntentRequestTrackerImpl.java b/ui/android/java/src/org/chromium/ui/base/IntentRequestTrackerImpl.java
index a75d790..c98d358d 100644
--- a/ui/android/java/src/org/chromium/ui/base/IntentRequestTrackerImpl.java
+++ b/ui/android/java/src/org/chromium/ui/base/IntentRequestTrackerImpl.java
@@ -14,12 +14,15 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.ContextUtils;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.base.WindowAndroid.IntentCallback;
 
 import java.lang.ref.WeakReference;
 import java.util.HashMap;
 
 /** The implementation of IntentRequestTracker. */
+@NullMarked
 /* package */ final class IntentRequestTrackerImpl implements IntentRequestTracker {
     // Constants used for intent request code bounding.
     private static final int REQUEST_CODE_PREFIX = 1000;
@@ -57,7 +60,8 @@
     }
 
     @Override
-    public int showCancelableIntent(Intent intent, IntentCallback callback, Integer errorId) {
+    public int showCancelableIntent(
+            @Nullable Intent intent, IntentCallback callback, Integer errorId) {
         int requestCode = generateNextRequestCode();
 
         if (!mDelegate.startActivityForResult(intent, requestCode)) {
diff --git a/ui/android/java/src/org/chromium/ui/base/LocalizationUtils.java b/ui/android/java/src/org/chromium/ui/base/LocalizationUtils.java
index 6d73487..6af576a 100644
--- a/ui/android/java/src/org/chromium/ui/base/LocalizationUtils.java
+++ b/ui/android/java/src/org/chromium/ui/base/LocalizationUtils.java
@@ -14,11 +14,14 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.LocaleUtils;
 import org.chromium.base.ResettersForTesting;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 import java.util.Locale;
 
 /** This class provides the locale related methods for the native library. */
 @JNINamespace("l10n_util")
+@NullMarked
 public class LocalizationUtils {
 
     // This is mirrored from base/i18n/rtl.h. Please keep in sync.
@@ -26,7 +29,7 @@
     public static final int RIGHT_TO_LEFT = 1;
     public static final int LEFT_TO_RIGHT = 2;
 
-    private static Boolean sIsLayoutRtlForTesting;
+    private static @Nullable Boolean sIsLayoutRtlForTesting;
 
     private LocalizationUtils() {
         /* cannot be instantiated */
diff --git a/ui/android/java/src/org/chromium/ui/base/MimeTypeUtils.java b/ui/android/java/src/org/chromium/ui/base/MimeTypeUtils.java
index 9b8d1f99..c775d38 100644
--- a/ui/android/java/src/org/chromium/ui/base/MimeTypeUtils.java
+++ b/ui/android/java/src/org/chromium/ui/base/MimeTypeUtils.java
@@ -8,15 +8,17 @@
 import android.webkit.MimeTypeMap;
 
 import androidx.annotation.IntDef;
-import androidx.annotation.Nullable;
 
 import org.chromium.base.BuildInfo;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.url.GURL;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 /** Utility methods for determining and working with mime types. */
+@NullMarked
 public class MimeTypeUtils {
     /** The MIME type for a plain text objects dragged from Chrome. */
     public static final String CHROME_MIMETYPE_TEXT = "chrome/text";
diff --git a/ui/android/java/src/org/chromium/ui/base/OverlayTransformApiHelper.java b/ui/android/java/src/org/chromium/ui/base/OverlayTransformApiHelper.java
index 2a737152..576aba2 100644
--- a/ui/android/java/src/org/chromium/ui/base/OverlayTransformApiHelper.java
+++ b/ui/android/java/src/org/chromium/ui/base/OverlayTransformApiHelper.java
@@ -15,12 +15,16 @@
 import androidx.annotation.RequiresApi;
 
 import org.chromium.base.Log;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.gfx.OverlayTransform;
 
 import java.lang.ref.WeakReference;
 
 /** Helper class to avoid fail of ART's class verification for S_V2 APIs in old device. */
 @RequiresApi(Build.VERSION_CODES.S_V2)
+@NullMarked
 final class OverlayTransformApiHelper
         implements AttachedSurfaceControl.OnBufferTransformHintChangedListener,
                 Window.OnFrameMetricsAvailableListener {
@@ -31,7 +35,7 @@
     private boolean mBufferTransformListenerAdded;
     private boolean mFrameMetricsListenerAdded;
 
-    static OverlayTransformApiHelper create(WindowAndroid windowAndroid) {
+    static @Nullable OverlayTransformApiHelper create(WindowAndroid windowAndroid) {
         if (windowAndroid.getWindow() == null) return null;
         return new OverlayTransformApiHelper(windowAndroid);
     }
@@ -98,6 +102,7 @@
         }
     }
 
+    @NullUnmarked
     private void addOnFrameMetricsAvailableListener() {
         if (mFrameMetricsListenerAdded) return;
         Window window = mWindow.get();
diff --git a/ui/android/java/src/org/chromium/ui/base/PhotoPicker.java b/ui/android/java/src/org/chromium/ui/base/PhotoPicker.java
index a783aac3..cced40b 100644
--- a/ui/android/java/src/org/chromium/ui/base/PhotoPicker.java
+++ b/ui/android/java/src/org/chromium/ui/base/PhotoPicker.java
@@ -4,10 +4,13 @@
 
 package org.chromium.ui.base;
 
+import org.chromium.build.annotations.NullMarked;
+
 /**
  * An interface for the custom image file picker.
  * See {@link SelectFileDialog}.
  */
+@NullMarked
 public interface PhotoPicker {
     /**
      * Called after use of the PhotoPicker results in an external intent.
diff --git a/ui/android/java/src/org/chromium/ui/base/PhotoPickerDelegate.java b/ui/android/java/src/org/chromium/ui/base/PhotoPickerDelegate.java
index 4a9f4ee..2b8a07e 100644
--- a/ui/android/java/src/org/chromium/ui/base/PhotoPickerDelegate.java
+++ b/ui/android/java/src/org/chromium/ui/base/PhotoPickerDelegate.java
@@ -4,9 +4,12 @@
 
 package org.chromium.ui.base;
 
+import org.chromium.build.annotations.NullMarked;
+
 import java.util.List;
 
 /** A delegate interface for the photo picker. */
+@NullMarked
 public interface PhotoPickerDelegate {
     /**
      * Called to display the photo picker.
diff --git a/ui/android/java/src/org/chromium/ui/base/PhotoPickerListener.java b/ui/android/java/src/org/chromium/ui/base/PhotoPickerListener.java
index 1e74655..975c3e46 100644
--- a/ui/android/java/src/org/chromium/ui/base/PhotoPickerListener.java
+++ b/ui/android/java/src/org/chromium/ui/base/PhotoPickerListener.java
@@ -8,10 +8,13 @@
 
 import androidx.annotation.IntDef;
 
+import org.chromium.build.annotations.NullMarked;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 /** The callback used to indicate what action the user took in the picker. */
+@NullMarked
 public interface PhotoPickerListener {
     /** The action the user took in the picker. */
     @IntDef({
diff --git a/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java b/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java
index 4ac586d1e..0d865da 100644
--- a/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java
+++ b/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java
@@ -10,6 +10,8 @@
 import org.chromium.base.ApkAssets;
 import org.chromium.base.LocaleUtils;
 import org.chromium.base.Log;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 import java.util.Arrays;
 
@@ -22,9 +24,10 @@
  * {@link ResourceBundle#setNoAvailableLocalePaks()} before calling the getters in this class.
  */
 @JNINamespace("ui")
+@NullMarked
 public final class ResourceBundle {
     private static final String TAG = "ResourceBundle";
-    private static String[] sAvailableLocales;
+    private static String @Nullable [] sAvailableLocales;
 
     private ResourceBundle() {}
 
@@ -69,7 +72,7 @@
      * @return Asset path to .pak file, or null if the locale is not supported.
      */
     @CalledByNative
-    private static String getLocalePakResourcePath(
+    private static @Nullable String getLocalePakResourcePath(
             String locale, boolean inBundle, boolean logError) {
         if (sAvailableLocales == null) {
             // Locales may be null in unit tests.
diff --git a/ui/android/java/src/org/chromium/ui/base/SPenSupport.java b/ui/android/java/src/org/chromium/ui/base/SPenSupport.java
index a3a9133..a80433d 100644
--- a/ui/android/java/src/org/chromium/ui/base/SPenSupport.java
+++ b/ui/android/java/src/org/chromium/ui/base/SPenSupport.java
@@ -10,26 +10,29 @@
 import android.view.MotionEvent;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /** Support S-Pen event detection and conversion. */
+@NullMarked
 public final class SPenSupport {
     // These values are obtained from Samsung.
     private static final int SPEN_ACTION_DOWN = 211;
     private static final int SPEN_ACTION_UP = 212;
     private static final int SPEN_ACTION_MOVE = 213;
     private static final int SPEN_ACTION_CANCEL = 214;
-    private static Boolean sIsSPenSupported;
+    private static @Nullable Boolean sIsSPenSupported;
 
     /**
      * Initialize SPen support. This is done lazily at the first invocation of
      * {@link #convertSPenEventAction(int)}.
      */
-    private static void initialize() {
-        if (sIsSPenSupported != null) return;
+    private static boolean isSPenSupported() {
+        if (sIsSPenSupported != null) return sIsSPenSupported;
 
         if (!"SAMSUNG".equalsIgnoreCase(Build.MANUFACTURER)) {
             sIsSPenSupported = false;
-            return;
+            return false;
         }
 
         Context context = ContextUtils.getApplicationContext();
@@ -37,10 +40,11 @@
         for (FeatureInfo info : infos) {
             if ("com.sec.feature.spen_usp".equalsIgnoreCase(info.name)) {
                 sIsSPenSupported = true;
-                return;
+                return true;
             }
         }
         sIsSPenSupported = false;
+        return false;
     }
 
     /**
@@ -51,8 +55,9 @@
      * @return Event action after the conversion.
      */
     public static int convertSPenEventAction(int eventActionMasked) {
-        if (sIsSPenSupported == null) initialize();
-        if (!sIsSPenSupported.booleanValue()) return eventActionMasked;
+        if (!isSPenSupported()) {
+            return eventActionMasked;
+        }
 
         // S-Pen support: convert to normal stylus event handling
         switch (eventActionMasked) {
diff --git a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
index e21b78a..4b2b7738 100644
--- a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
+++ b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
@@ -24,7 +24,6 @@
 import android.webkit.MimeTypeMap;
 
 import androidx.annotation.IntDef;
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.content.ContextCompat;
 
@@ -46,6 +45,9 @@
 import org.chromium.base.task.AsyncTask;
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.R;
 import org.chromium.ui.UiUtils;
 
@@ -65,6 +67,7 @@
  * a set of accepted file types. The path of the selected file is passed to the native dialog.
  */
 @JNINamespace("ui")
+@NullMarked
 public class SelectFileDialog implements WindowAndroid.IntentCallback, PhotoPickerListener {
     private static final String TAG = "SelectFileDialog";
     private static final String IMAGE_TYPE = "image";
@@ -249,17 +252,24 @@
 
     /** If set, overrides the WindowAndroid passed in {@link selectFile()}. */
     @SuppressLint("StaticFieldLeak")
-    private static WindowAndroid sWindowAndroidForTesting;
+    private static @Nullable WindowAndroid sWindowAndroidForTesting;
 
     private long mNativeSelectFileDialog;
-    private String mIntentAction;
+    private @Nullable String mIntentAction;
+
     // File types may contain both file extensions and MIME types.
+    @SuppressWarnings("NullAway.Init")
     private List<String> mFileTypes;
+
     // Converted from `mFileTypes`, only contains deduped MIME types.
+    @SuppressWarnings("NullAway.Init")
     private List<String> mMimeTypes;
+
     private boolean mCapture;
     private boolean mAllowMultiple;
-    private Uri mCameraOutputUri;
+    private @Nullable Uri mCameraOutputUri;
+
+    @SuppressWarnings("NullAway.Init")
     private WindowAndroid mWindowAndroid;
 
     /** Whether an Activity is available on the system to support capturing images (i.e. Camera). */
@@ -282,10 +292,10 @@
     private boolean mMediaPickerWasUsed;
 
     /** A delegate for the photo picker. */
-    private static PhotoPickerDelegate sPhotoPickerDelegate;
+    private static @Nullable PhotoPickerDelegate sPhotoPickerDelegate;
 
     /** The active photo picker, or null if none is active. */
-    private static PhotoPicker sPhotoPicker;
+    private static @Nullable PhotoPicker sPhotoPicker;
 
     /**
      * Allows setting a delegate to override the default Android stock photo picker.
@@ -510,8 +520,7 @@
      * Returns a Video capture Intent. Can return null if video capture is not supported or the
      * camera permission has not been granted.
      */
-    @Nullable
-    private Intent getVideoCaptureIntent() {
+    private @Nullable Intent getVideoCaptureIntent() {
         boolean hasCameraPermission = mWindowAndroid.hasPermission(Manifest.permission.CAMERA);
         if (mSupportsVideoCapture && hasCameraPermission) {
             return new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
@@ -523,8 +532,7 @@
      * Returns a SoundRecorder Intent. Can return null if sound capture is not supported or the
      * sound permission has not been granted.
      */
-    @Nullable
-    private Intent getSoundRecorderIntent() {
+    private @Nullable Intent getSoundRecorderIntent() {
         boolean hasAudioPermission = mWindowAndroid.hasPermission(Manifest.permission.RECORD_AUDIO);
         if (mSupportsAudioCapture && hasAudioPermission) {
             return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
@@ -538,7 +546,7 @@
      * is allowed to choose files from the camera.
      * @param camera Intent for selecting files from camera.
      */
-    private void launchSelectFileWithCameraIntent(Intent camera) {
+    private void launchSelectFileWithCameraIntent(@Nullable Intent camera) {
         RecordHistogram.recordEnumeratedHistogram(
                 "Android.SelectFileDialogScope",
                 determineSelectFileDialogScope(),
@@ -585,7 +593,8 @@
      * @param camcorder A camcorder intent to supply as extra Intent data.
      * @param soundRecorder A soundRecorder intent to supply as extra Intent data.
      */
-    private void showExternalPicker(Intent camera, Intent camcorder, Intent soundRecorder) {
+    private void showExternalPicker(
+            @Nullable Intent camera, @Nullable Intent camcorder, @Nullable Intent soundRecorder) {
         if (UiAndroidFeatureMap.isEnabled(UiAndroidFeatures.DEPRECATED_EXTERNAL_PICKER_FUNCTION)) {
             showExternalPickerDeprecated(camera, camcorder, soundRecorder);
             return;
@@ -645,7 +654,7 @@
      * @param soundRecorder A soundRecorder intent to supply as extra Intent data.
      */
     private void showExternalPickerDeprecated(
-            Intent camera, Intent camcorder, Intent soundRecorder) {
+            @Nullable Intent camera, @Nullable Intent camcorder, @Nullable Intent soundRecorder) {
         Intent getContentIntent = new Intent(mIntentAction);
 
         if (mAllowMultiple) {
@@ -861,8 +870,9 @@
             mCallback = callback;
         }
 
+        @NullUnmarked
         @Override
-        public Uri doInBackground() {
+        public @Nullable Uri doInBackground() {
             try {
                 Context context = ContextUtils.getApplicationContext();
                 return FileProviderUtils.getContentUriFromFile(getFileForImageCapture(context));
@@ -873,7 +883,7 @@
         }
 
         @Override
-        protected void onPostExecute(Uri result) {
+        protected void onPostExecute(@Nullable Uri result) {
             mCameraOutputUri = result;
             if (mCameraOutputUri == null) {
                 if (captureImage() || mDirectToCamera) {
@@ -920,6 +930,7 @@
 
     // TODO(crbug.com/41484704): Merge the Chrome and WebView implementations
     // of isPathUnderAppDir into one.
+    @NullUnmarked
     private static boolean isPathUnderAppDir(String path, Context context) {
         File file = new File(path);
         File dataDir = ContextCompat.getDataDir(context);
@@ -932,6 +943,7 @@
         }
     }
 
+    @NullUnmarked
     public static boolean isContentUriUnderAppDir(Uri uri, Context context) {
         assert !ThreadUtils.runningOnUiThread();
         try {
@@ -955,6 +967,7 @@
      * @param resultCode The result code whether the intent returned successfully.
      * @param results The results of the requested intent.
      */
+    @NullUnmarked
     @Override
     public void onIntentCompleted(int resultCode, Intent results) {
         if (sPhotoPicker != null) {
@@ -1241,8 +1254,9 @@
                     && !FileUtils.getAbsoluteFilePath(mFilePath).isEmpty();
         }
 
+        @NullUnmarked
         @Override
-        protected void onPostExecute(Boolean result) {
+        protected void onPostExecute(@Nullable Boolean result) {
             if (result) {
                 onFileSelected(mNativeSelectFileDialog, mFilePath, "");
                 WindowAndroid.showError(R.string.opening_file_error);
@@ -1253,7 +1267,9 @@
     }
 
     class GetDisplayNameTask extends AsyncTask<String[]> {
+        @SuppressWarnings("NullAway.Init")
         String[] mFilePaths;
+
         final Context mContext;
         final boolean mIsMultiple;
         final Uri[] mUris;
@@ -1264,9 +1280,10 @@
             mUris = uris;
         }
 
+        @NullUnmarked
         @Override
         @SuppressLint("NewApi")
-        public String[] doInBackground() {
+        public String @Nullable [] doInBackground() {
             mFilePaths = new String[mUris.length];
             String[] displayNames = new String[mUris.length];
             try {
@@ -1306,7 +1323,7 @@
         }
 
         @Override
-        protected void onPostExecute(String[] result) {
+        protected void onPostExecute(String @Nullable [] result) {
             if (result == null) {
                 onFileNotSelected();
                 return;
@@ -1350,7 +1367,7 @@
         }
 
         @Override
-        protected void onPostExecute(Boolean result) {}
+        protected void onPostExecute(@Nullable Boolean result) {}
     }
 
     protected RecordUploadMetricsTask getUploadMetricTaskForTesting(
@@ -1384,7 +1401,9 @@
     }
 
     protected void onFileSelected(
-            long nativeSelectFileDialogImpl, String filePath, String displayName) {
+            long nativeSelectFileDialogImpl,
+            @Nullable String filePath,
+            @Nullable String displayName) {
         recordImageCountHistograms(new String[] {filePath});
         if (nativeSelectFileDialogImpl != 0) {
             SelectFileDialogJni.get()
@@ -1463,6 +1482,7 @@
         }
     }
 
+    @NullUnmarked
     private int getMediaType(
             Uri mediaUri, boolean mediaPickerWasUsed, ContentResolver contentResolver) {
         if (mediaUri == null) {
@@ -1809,8 +1829,8 @@
         void onFileSelected(
                 long nativeSelectFileDialogImpl,
                 SelectFileDialog caller,
-                String filePath,
-                String displayName);
+                @Nullable String filePath,
+                @Nullable String displayName);
 
         void onMultipleFilesSelected(
                 long nativeSelectFileDialogImpl,
diff --git a/ui/android/java/src/org/chromium/ui/base/TouchDevice.java b/ui/android/java/src/org/chromium/ui/base/TouchDevice.java
index 871ae50..b6eab86 100644
--- a/ui/android/java/src/org/chromium/ui/base/TouchDevice.java
+++ b/ui/android/java/src/org/chromium/ui/base/TouchDevice.java
@@ -11,9 +11,11 @@
 import org.jni_zero.JNINamespace;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.build.annotations.NullMarked;
 
 /** Simple proxy for querying input device properties from C++. */
 @JNINamespace("ui")
+@NullMarked
 public class TouchDevice {
 
     /** Static methods only so make constructor private. */
diff --git a/ui/android/java/src/org/chromium/ui/base/UiAndroidFeatureList.java b/ui/android/java/src/org/chromium/ui/base/UiAndroidFeatureList.java
index 660c03cd..d116e0c9 100644
--- a/ui/android/java/src/org/chromium/ui/base/UiAndroidFeatureList.java
+++ b/ui/android/java/src/org/chromium/ui/base/UiAndroidFeatureList.java
@@ -5,8 +5,10 @@
 package org.chromium.ui.base;
 
 import org.chromium.base.MutableFlagWithSafeDefault;
+import org.chromium.build.annotations.NullMarked;
 
 /** Helpers and state for features from {@link UiAndroidFeatures}. */
+@NullMarked
 public class UiAndroidFeatureList {
     private static MutableFlagWithSafeDefault newMutableFlagWithSafeDefault(
             String featureName, boolean defaultValue) {
diff --git a/ui/android/java/src/org/chromium/ui/base/UiAndroidFeatureMap.java b/ui/android/java/src/org/chromium/ui/base/UiAndroidFeatureMap.java
index e40192a..0826bbc 100644
--- a/ui/android/java/src/org/chromium/ui/base/UiAndroidFeatureMap.java
+++ b/ui/android/java/src/org/chromium/ui/base/UiAndroidFeatureMap.java
@@ -8,9 +8,11 @@
 import org.jni_zero.NativeMethods;
 
 import org.chromium.base.FeatureMap;
+import org.chromium.build.annotations.NullMarked;
 
 /** Java accessor for ui/android/ui_android_feature_map.cc state */
 @JNINamespace("ui")
+@NullMarked
 public class UiAndroidFeatureMap extends FeatureMap {
     private static final UiAndroidFeatureMap sInstance = new UiAndroidFeatureMap();
 
diff --git a/ui/android/java/src/org/chromium/ui/base/ViewAndroidDelegate.java b/ui/android/java/src/org/chromium/ui/base/ViewAndroidDelegate.java
index 6147db190b..4850a5f7 100644
--- a/ui/android/java/src/org/chromium/ui/base/ViewAndroidDelegate.java
+++ b/ui/android/java/src/org/chromium/ui/base/ViewAndroidDelegate.java
@@ -19,7 +19,6 @@
 import android.view.inputmethod.InputConnection;
 
 import androidx.annotation.CallSuper;
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.view.MarginLayoutParamsCompat;
 
@@ -29,6 +28,8 @@
 import org.chromium.base.Callback;
 import org.chromium.base.ObserverList;
 import org.chromium.base.ResettersForTesting;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.dragdrop.DragAndDropDelegate;
 import org.chromium.ui.dragdrop.DragAndDropDelegateImpl;
 import org.chromium.ui.dragdrop.DragStateTracker;
@@ -37,8 +38,9 @@
 
 /** Class to acquire, position, and remove anchor views from the implementing View. */
 @JNINamespace("ui")
+@NullMarked
 public class ViewAndroidDelegate {
-    private static DragAndDropDelegate sDragAndDropDelegateForTesting;
+    private static @Nullable DragAndDropDelegate sDragAndDropDelegateForTesting;
     private final DragAndDropDelegateImpl mDragAndDropDelegateImpl;
 
     /**
@@ -70,7 +72,7 @@
     private final ObserverList<VerticalScrollDirectionChangeListener>
             mVerticalScrollDirectionChangeListeners = new ObserverList<>();
 
-    private Callback<Boolean> mUpdateShouldShowStylusHoverIcon;
+    private @Nullable Callback<Boolean> mUpdateShouldShowStylusHoverIcon;
 
     /**
      * Sets a callback which should be called with the latest value of whether the element being
@@ -185,7 +187,7 @@
      * @return An anchor view that can be used to anchor decoration views like Autofill popup.
      */
     @CalledByNative
-    public View acquireView() {
+    public @Nullable View acquireView() {
         ViewGroup containerView = getContainerViewGroup();
         if (containerView == null || containerView.getParent() == null) return null;
         View anchorView = new View(containerView.getContext());
diff --git a/ui/android/java/src/org/chromium/ui/base/ViewUtils.java b/ui/android/java/src/org/chromium/ui/base/ViewUtils.java
index 41f092d..13709af 100644
--- a/ui/android/java/src/org/chromium/ui/base/ViewUtils.java
+++ b/ui/android/java/src/org/chromium/ui/base/ViewUtils.java
@@ -18,8 +18,10 @@
 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
 
 import org.chromium.base.TraceEvent;
+import org.chromium.build.annotations.NullMarked;
 
 /** A utility class that has helper methods for Android view. */
+@NullMarked
 public final class ViewUtils {
     private static final int[] sLocationTmp = new int[2];
 
diff --git a/ui/android/java/src/org/chromium/ui/base/ViewportInsets.java b/ui/android/java/src/org/chromium/ui/base/ViewportInsets.java
index 78e91db..fc212ed4 100644
--- a/ui/android/java/src/org/chromium/ui/base/ViewportInsets.java
+++ b/ui/android/java/src/org/chromium/ui/base/ViewportInsets.java
@@ -4,6 +4,8 @@
 
 package org.chromium.ui.base;
 
+import org.chromium.build.annotations.NullMarked;
+
 /**
  * Information about various kinds of insets on the application viewport.
  *
@@ -77,6 +79,7 @@
  *                              │┼───────────────────────┼│
  *                              └─────────────────────────┘
  */
+@NullMarked
 public class ViewportInsets {
     /**
      * The total vertical inset on the application viewport coming from all visible UI controls.
diff --git a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
index f0e9cf8..4c8baedc 100644
--- a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
@@ -4,6 +4,8 @@
 
 package org.chromium.ui.base;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.annotation.SuppressLint;
@@ -26,7 +28,6 @@
 import android.view.WindowManager;
 import android.window.TrustedPresentationThresholds;
 
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import org.jni_zero.CalledByNative;
@@ -49,6 +50,10 @@
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
 import org.chromium.build.BuildConfig;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
+import org.chromium.build.annotations.RequiresNonNull;
 import org.chromium.ui.InsetObserver;
 import org.chromium.ui.KeyboardVisibilityDelegate;
 import org.chromium.ui.display.DisplayAndroid;
@@ -68,6 +73,7 @@
 
 /** The window base class that has the minimum functionality. */
 @JNINamespace("ui")
+@NullMarked
 public class WindowAndroid
         implements AndroidPermissionDelegate,
                 DisplayAndroidObserver,
@@ -80,8 +86,8 @@
     // exactly match the target rate.
     private static final float MAX_REFRESH_RATE_DELTA = 2.f;
 
-    private final LifetimeAssert mLifetimeAssert;
-    private IntentRequestTrackerImpl mIntentRequestTracker;
+    private final @Nullable LifetimeAssert mLifetimeAssert;
+    private @Nullable IntentRequestTrackerImpl mIntentRequestTracker;
 
     private KeyboardVisibilityDelegate mKeyboardVisibilityDelegate =
             KeyboardVisibilityDelegate.getInstance();
@@ -105,20 +111,20 @@
 
     // We track all animations over content and provide a drawing placeholder for them.
     private HashSet<Animator> mAnimationsOverContent = new HashSet<>();
-    private View mAnimationPlaceholderView;
+    private @Nullable View mAnimationPlaceholderView;
 
     /** A mechanism for observing and updating the application window's bottom inset. */
     private ApplicationViewportInsetSupplier mApplicationBottomInsetSupplier =
             new ApplicationViewportInsetSupplier();
 
-    private AndroidPermissionDelegate mPermissionDelegate;
+    private @Nullable AndroidPermissionDelegate mPermissionDelegate;
 
     // Note that this state lives in Java, rather than in the native BeginFrameSource because
     // clients may pause VSync before the native WindowAndroid is created.
     private boolean mVSyncPaused;
 
     // List of display modes with the same dimensions as the current mode but varying refresh rate.
-    private List<Display.Mode> mSupportedRefreshRateModes;
+    private @Nullable List<Display.Mode> mSupportedRefreshRateModes;
 
     // A container for UnownedUserData objects that are not owned by, but can be accessed through
     // WindowAndroid.
@@ -126,7 +132,7 @@
 
     private float mRefreshRate;
     private boolean mHasFocus = true;
-    private OverlayTransformApiHelper mOverlayTransformApiHelper;
+    private @Nullable OverlayTransformApiHelper mOverlayTransformApiHelper;
 
     // The information required to draw a replica of the progress bar drawn in
     // java UI in composited UI.
@@ -147,7 +153,7 @@
         }
     }
 
-    private ProgressBarConfig.Provider mProgressBarConfigProvider;
+    private ProgressBarConfig.@Nullable Provider mProgressBarConfigProvider;
 
     /** An interface to notify listeners that a context menu is closed. */
     public interface OnCloseContextMenuListener {
@@ -185,16 +191,16 @@
     private final boolean mAllowChangeRefreshRate;
 
     /** Gets the view for readback. */
-    public View getReadbackView() {
+    public @Nullable View getReadbackView() {
         return null;
     }
 
     private final ObserverList<OnCloseContextMenuListener> mContextMenuCloseListeners =
             new ObserverList<>();
 
-    private ModalDialogManager mModalDialogManagerForTesting;
+    private @Nullable ModalDialogManager mModalDialogManagerForTesting;
 
-    private Consumer<Boolean> mOcclusionObserver;
+    private @Nullable Consumer<Boolean> mOcclusionObserver;
 
     private final boolean mTrackOcclusion;
 
@@ -213,7 +219,7 @@
     protected WindowAndroid(
             Context context,
             IntentRequestTracker tracker,
-            InsetObserver insetObserver,
+            @Nullable InsetObserver insetObserver,
             boolean trackOcclusion) {
         this(context, DisplayAndroid.getNonMultiDisplay(context), trackOcclusion);
         mIntentRequestTracker = (IntentRequestTrackerImpl) tracker;
@@ -286,13 +292,13 @@
         maybeUnregisterOcclusionObserver();
     }
 
-    private void maybeRegisterOcclusionObserver(IBinder windowToken) {
+    private void maybeRegisterOcclusionObserver(@Nullable IBinder windowToken) {
         if (!mTrackOcclusion || Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
             return;
         }
         assert mOcclusionObserver == null;
 
-        Context context = getContext().get();
+        Context context = assumeNonNull(getContext().get());
         WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
 
         var thresholds = new TrustedPresentationThresholds(Float.MIN_VALUE, Float.MIN_VALUE, 1);
@@ -320,7 +326,7 @@
         }
         assert mOcclusionObserver != null;
 
-        Context context = getContext().get();
+        Context context = assumeNonNull(getContext().get());
         WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         wm.unregisterTrustedPresentationListener(mOcclusionObserver);
 
@@ -361,8 +367,7 @@
     }
 
     /** Gets the {@link IntentRequestTracker} associated with the WindowAndroid's activity. */
-    @Nullable
-    public final IntentRequestTracker getIntentRequestTracker() {
+    public final @Nullable IntentRequestTracker getIntentRequestTracker() {
         if (mIntentRequestTracker == null) {
             Log.w(
                     TAG,
@@ -402,7 +407,7 @@
      *                 results, or null if no message is required.
      * @return Whether the intent was shown.
      */
-    public boolean showIntent(Intent intent, IntentCallback callback, Integer errorId) {
+    public boolean showIntent(@Nullable Intent intent, IntentCallback callback, Integer errorId) {
         if (mIntentRequestTracker == null) {
             Log.d(TAG, "Can't show intent as context is not an Activity: " + intent);
             return false;
@@ -849,8 +854,8 @@
 
     // Helper to get the android Window. Always null for application context. Need to null check
     // result returning value.
-    @Nullable
-    public Window getWindow() {
+
+    public @Nullable Window getWindow() {
         Activity activity = ContextUtils.activityFromContext(mContextRef.get());
         if (activity == null || activity.isFinishing()) return null;
         return activity.getWindow();
@@ -892,7 +897,7 @@
     }
 
     /** Returns the {@link InsetObserver} for the root view of the activity or null. */
-    public InsetObserver getInsetObserver() {
+    public @Nullable InsetObserver getInsetObserver() {
         return mInsetObserver;
     }
 
@@ -957,12 +962,13 @@
         // returning to the default optimized state.
         animation.addListener(
                 new AnimatorListenerAdapter() {
+                    @NullUnmarked
                     @Override
                     public void onAnimationEnd(Animator animation) {
                         animation.removeListener(this);
                         mAnimationsOverContent.remove(animation);
                         if (mAnimationsOverContent.isEmpty()) {
-                            mAnimationPlaceholderView.setWillNotDraw(true);
+                            assumeNonNull(mAnimationPlaceholderView).setWillNotDraw(true);
                         }
                     }
                 });
@@ -979,14 +985,14 @@
     }
 
     /** Return the decor view, or null. */
-    private View getDecorView() {
+    private @Nullable View getDecorView() {
         Window window = getWindow();
         if (window == null) return null;
         return window.getDecorView();
     }
 
     /** Return the current window token, or null. */
-    public IBinder getWindowToken() {
+    public @Nullable IBinder getWindowToken() {
         Window window = getWindow();
         if (window == null) return null;
         View decorView = window.peekDecorView();
@@ -1035,12 +1041,12 @@
     }
 
     @Override
-    public void onCurrentModeChanged(Display.Mode currentMode) {
+    public void onCurrentModeChanged(Display.@Nullable Mode currentMode) {
         recomputeSupportedRefreshRates();
     }
 
     @Override
-    public void onDisplayModesChanged(List<Display.Mode> supportedModes) {
+    public void onDisplayModesChanged(@Nullable List<Display.Mode> supportedModes) {
         recomputeSupportedRefreshRates();
     }
 
@@ -1109,7 +1115,7 @@
     @SuppressLint("NewApi")
     // mSupportedRefreshRateModes should only be set if Display.Mode is available.
     @CalledByNative
-    private float[] getSupportedRefreshRates() {
+    private float @Nullable [] getSupportedRefreshRates() {
         if (mSupportedRefreshRateModes == null || !mAllowChangeRefreshRate) return null;
 
         float[] supportedRefreshRates = new float[mSupportedRefreshRateModes.size()];
@@ -1139,8 +1145,10 @@
         window.setAttributes(params);
     }
 
+    @NullUnmarked
     @SuppressLint("NewApi")
     // mSupportedRefreshRateModes should only be set if Display.Mode is available.
+    @RequiresNonNull("mSupportedRefreshRateModes")
     private int getPreferredModeId(float preferredRefreshRate) {
         if (preferredRefreshRate == 0) return 0;
 
@@ -1232,7 +1240,9 @@
         void destroy(long nativeWindowAndroid, WindowAndroid caller);
 
         void onSupportedRefreshRatesUpdated(
-                long nativeWindowAndroid, WindowAndroid caller, float[] supportedRefreshRates);
+                long nativeWindowAndroid,
+                WindowAndroid caller,
+                float @Nullable [] supportedRefreshRates);
 
         void onOverlayTransformUpdated(long nativeWindowAndroid, WindowAndroid caller);
 
diff --git a/ui/android/java/src/org/chromium/ui/base/WindowDelegate.java b/ui/android/java/src/org/chromium/ui/base/WindowDelegate.java
index f09d508..b31ee8a 100644
--- a/ui/android/java/src/org/chromium/ui/base/WindowDelegate.java
+++ b/ui/android/java/src/org/chromium/ui/base/WindowDelegate.java
@@ -7,7 +7,10 @@
 import android.graphics.Rect;
 import android.view.Window;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** This is a delegate that handles communication about a window's current state and properties. */
+@NullMarked
 public class WindowDelegate {
     private final Window mWindow;
 
diff --git a/ui/android/java/src/org/chromium/ui/display/DisplayAndroid.java b/ui/android/java/src/org/chromium/ui/display/DisplayAndroid.java
index 76856d9..975fd18 100644
--- a/ui/android/java/src/org/chromium/ui/display/DisplayAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/display/DisplayAndroid.java
@@ -4,6 +4,8 @@
 
 package org.chromium.ui.display;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.content.Context;
 import android.graphics.Insets;
 import android.graphics.Rect;
@@ -13,6 +15,10 @@
 
 import androidx.annotation.RequiresApi;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
+
 import java.util.List;
 import java.util.WeakHashMap;
 
@@ -23,6 +29,7 @@
  * anywhere, as long as the corresponding WindowAndroids are destroyed. The observers are
  * held weakly so to not lead to leaks.
  */
+@NullMarked
 public class DisplayAndroid {
     /** DisplayAndroidObserver interface for changes to this Display. */
     public interface DisplayAndroidObserver {
@@ -52,14 +59,14 @@
          *
          * @param supportedModes the array of supported modes.
          */
-        default void onDisplayModesChanged(List<Display.Mode> supportedModes) {}
+        default void onDisplayModesChanged(@Nullable List<Display.Mode> supportedModes) {}
 
         /**
          * Called whenever the attached display's current mode is changed.
          *
          * @param currentMode the current display mode.
          */
-        default void onCurrentModeChanged(Display.Mode currentMode) {}
+        default void onCurrentModeChanged(Display.@Nullable Mode currentMode) {}
     }
 
     private static final DisplayAndroidObserver[] EMPTY_OBSERVER_ARRAY =
@@ -69,9 +76,9 @@
     // Do NOT add strong references to objects with potentially complex lifetime, like Context.
 
     private final int mDisplayId;
-    private String mName;
+    private @Nullable String mName;
     private Rect mBounds;
-    private Insets mInsets;
+    private @Nullable Insets mInsets;
     private float mDipScale;
     private float mXdpi;
     private float mYdpi;
@@ -79,8 +86,8 @@
     private int mBitsPerComponent;
     private int mRotation;
     private float mRefreshRate;
-    private Display.Mode mCurrentDisplayMode;
-    private List<Display.Mode> mDisplayModes;
+    private Display.@Nullable Mode mCurrentDisplayMode;
+    private @Nullable List<Display.Mode> mDisplayModes;
     private boolean mIsHdr;
     private float mHdrMaxLuminanceRatio = 1.0f;
     private boolean mIsInternal;
@@ -119,7 +126,7 @@
     }
 
     /** Returns the name of the display. */
-    public String getDisplayName() {
+    public @Nullable String getDisplayName() {
         return mName;
     }
 
@@ -146,13 +153,14 @@
     /** Returns the insets of the display. */
     @RequiresApi(Build.VERSION_CODES.R)
     public Insets getInsets() {
-        return mInsets;
+        return assumeNonNull(mInsets);
     }
 
     /** Returns the insets as an array. */
     @RequiresApi(Build.VERSION_CODES.R)
     public int[] getInsetsAsArray() {
-        return new int[] {mInsets.left, mInsets.top, mInsets.right, mInsets.bottom};
+        Insets insets = assumeNonNull(mInsets);
+        return new int[] {insets.left, insets.top, insets.right, insets.bottom};
     }
 
     /** Returns current orientation. One of Surface.ORIENTATION_* values. */
@@ -217,12 +225,12 @@
     }
 
     /** Returns Display.Modes supported by this Display. */
-    public List<Display.Mode> getSupportedModes() {
+    public @Nullable List<Display.Mode> getSupportedModes() {
         return mDisplayModes;
     }
 
     /** Returns current Display.Mode for the display. */
-    public Display.Mode getCurrentMode() {
+    public Display.@Nullable Mode getCurrentMode() {
         return mCurrentDisplayMode;
     }
 
@@ -255,7 +263,7 @@
     /**
      * Return window context for display android. Implemented by @{@link PhysicalDisplayAndroid}.
      */
-    public Context getWindowContext() {
+    public @Nullable Context getWindowContext() {
         return null;
     }
 
@@ -286,7 +294,8 @@
         return mObservers.keySet().toArray(EMPTY_OBSERVER_ARRAY);
     }
 
-    public void updateIsDisplayServerWideColorGamut(Boolean isDisplayServerWideColorGamut) {
+    public void updateIsDisplayServerWideColorGamut(
+            @Nullable Boolean isDisplayServerWideColorGamut) {
         update(
                 /* name= */ null,
                 /* bounds= */ null,
@@ -308,24 +317,25 @@
     }
 
     /** Update the display to the provided parameters. Null values leave the parameter unchanged. */
+    @NullUnmarked
     protected void update(
-            String name,
-            Rect bounds,
-            Insets insets,
-            Float dipScale,
-            Float xdpi,
-            Float ydpi,
-            Integer bitsPerPixel,
-            Integer bitsPerComponent,
-            Integer rotation,
-            Boolean isDisplayWideColorGamut,
-            Boolean isDisplayServerWideColorGamut,
-            Float refreshRate,
-            Display.Mode currentMode,
-            List<Display.Mode> supportedModes,
-            Boolean isHdr,
-            Float hdrMaxLuminanceRatio,
-            Boolean isInternal) {
+            @Nullable String name,
+            @Nullable Rect bounds,
+            @Nullable Insets insets,
+            @Nullable Float dipScale,
+            @Nullable Float xdpi,
+            @Nullable Float ydpi,
+            @Nullable Integer bitsPerPixel,
+            @Nullable Integer bitsPerComponent,
+            @Nullable Integer rotation,
+            @Nullable Boolean isDisplayWideColorGamut,
+            @Nullable Boolean isDisplayServerWideColorGamut,
+            @Nullable Float refreshRate,
+            Display.@Nullable Mode currentMode,
+            @Nullable List<Display.Mode> supportedModes,
+            @Nullable Boolean isHdr,
+            @Nullable Float hdrMaxLuminanceRatio,
+            @Nullable Boolean isInternal) {
         boolean nameChanged = name != null && !name.equals(mName);
         boolean boundsChanged = bounds != null && !bounds.equals(mBounds);
         boolean insetsChanged = insets != null && !insets.equals(mInsets);
diff --git a/ui/android/java/src/org/chromium/ui/display/DisplayAndroidManager.java b/ui/android/java/src/org/chromium/ui/display/DisplayAndroidManager.java
index e3fad5b..1840454 100644
--- a/ui/android/java/src/org/chromium/ui/display/DisplayAndroidManager.java
+++ b/ui/android/java/src/org/chromium/ui/display/DisplayAndroidManager.java
@@ -21,9 +21,12 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.ThreadUtils;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /** DisplayAndroidManager is a class that informs its observers Display changes. */
 @JNINamespace("ui")
+@NullMarked
 public class DisplayAndroidManager {
     /**
      * DisplayListenerBackend is used to handle the actual listening of display changes. It handles
@@ -72,7 +75,7 @@
         }
     }
 
-    private static DisplayAndroidManager sDisplayAndroidManager;
+    private static @Nullable DisplayAndroidManager sDisplayAndroidManager;
 
     private static boolean sDisableHdrSdkRatioCallback;
 
@@ -220,7 +223,7 @@
                 long nativeDisplayAndroidManager,
                 DisplayAndroidManager caller,
                 int sdkDisplayId,
-                String label,
+                @Nullable String label,
                 int[] bounds, // the order is: left, top, right, bottom
                 int[] insets, // the order is: left, top, right, bottom
                 float dipScale,
diff --git a/ui/android/java/src/org/chromium/ui/display/DisplaySwitches.java b/ui/android/java/src/org/chromium/ui/display/DisplaySwitches.java
index dcfb64f..3a54add1 100644
--- a/ui/android/java/src/org/chromium/ui/display/DisplaySwitches.java
+++ b/ui/android/java/src/org/chromium/ui/display/DisplaySwitches.java
@@ -4,7 +4,10 @@
 
 package org.chromium.ui.display;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Contains all of the command line switches that are specific to the display. */
+@NullMarked
 public abstract class DisplaySwitches {
     // Native switch - display_switches::kForceDeviceScaleFactor
     public static final String FORCE_DEVICE_SCALE_FACTOR = "force-device-scale-factor";
diff --git a/ui/android/java/src/org/chromium/ui/display/DisplayUtil.java b/ui/android/java/src/org/chromium/ui/display/DisplayUtil.java
index 3e4775e..11da4b1f 100644
--- a/ui/android/java/src/org/chromium/ui/display/DisplayUtil.java
+++ b/ui/android/java/src/org/chromium/ui/display/DisplayUtil.java
@@ -4,6 +4,8 @@
 
 package org.chromium.ui.display;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Insets;
@@ -16,12 +18,14 @@
 import android.view.WindowInsets;
 import android.view.WindowManager;
 
-import androidx.annotation.Nullable;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * Helper functions relevant to working with displays, but have no parallel in the native
  * DisplayAndroid class.
  */
+@NullMarked
 public abstract class DisplayUtil {
     private static @Nullable Float sUiScalingFactorForAutomotiveOverride;
 
@@ -41,7 +45,7 @@
      */
     @Deprecated
     public static float getUiScalingFactorForAutomotive() {
-        return sUiScalingFactorForAutomotiveOverride;
+        return assumeNonNull(sUiScalingFactorForAutomotiveOverride);
     }
 
     public static int getUiDensityForAutomotive(Context context, int baseDensity) {
diff --git a/ui/android/java/src/org/chromium/ui/display/PhysicalDisplayAndroid.java b/ui/android/java/src/org/chromium/ui/display/PhysicalDisplayAndroid.java
index 8b4ecea..90a9c7d 100644
--- a/ui/android/java/src/org/chromium/ui/display/PhysicalDisplayAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/display/PhysicalDisplayAndroid.java
@@ -27,12 +27,16 @@
 import org.chromium.base.Log;
 import org.chromium.base.StrictModeContext;
 import org.chromium.base.ThreadUtils;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 
 import java.util.Arrays;
 import java.util.List;
 import java.util.function.Consumer;
 
 /** A DisplayAndroid implementation tied to a physical Display. */
+@NullMarked
 /* package */ class PhysicalDisplayAndroid extends DisplayAndroid {
     private static final String TAG = "DisplayAndroid";
 
@@ -42,9 +46,10 @@
     // When this object exists, a positive value means that the forced DIP scale is set and
     // the zero means it is not. The non existing object (i.e. null reference) means that
     // the existence and value of the forced DIP scale has not yet been determined.
+    @SuppressWarnings("NullAway.Init")
     private static Float sForcedDIPScale;
 
-    private static Float getHdrSdrRatio(Display display) {
+    private static @Nullable Float getHdrSdrRatio(Display display) {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) return null;
         return display.getHdrSdrRatio();
     }
@@ -147,10 +152,10 @@
         }
     }
 
-    private final Context mWindowContext;
-    private final ComponentCallbacks mComponentCallbacks;
+    private final @Nullable Context mWindowContext;
+    private final @Nullable ComponentCallbacks mComponentCallbacks;
     private final Display mDisplay;
-    private Consumer<Display> mHdrSdrRatioCallback;
+    private @Nullable Consumer<Display> mHdrSdrRatioCallback;
 
     /* package */ PhysicalDisplayAndroid(Display display, boolean disableHdrSdkRatioCallback) {
         super(display.getDisplayId());
@@ -197,10 +202,11 @@
     }
 
     @Override
-    public Context getWindowContext() {
+    public @Nullable Context getWindowContext() {
         return mWindowContext;
     }
 
+    @NullUnmarked
     @RequiresApi(VERSION_CODES.R)
     private void updateFromConfiguration() {
         WindowManager windowManager = mWindowContext.getSystemService(WindowManager.class);
@@ -230,7 +236,8 @@
                 mWindowContext.getDisplay());
     }
 
-    /* package */ void onDisplayRemoved() {
+    /* package */ @NullUnmarked
+    void onDisplayRemoved() {
         if (USE_CONFIGURATION) {
             mWindowContext.unregisterComponentCallbacks(mComponentCallbacks);
         }
@@ -292,8 +299,14 @@
                 /* isInternal= */ null);
     }
 
+    @NullUnmarked
     private void updateCommon(
-            Rect bounds, Insets insets, float density, float xdpi, float ydpi, Display display) {
+            Rect bounds,
+            @Nullable Insets insets,
+            float density,
+            float xdpi,
+            float ydpi,
+            Display display) {
         if (hasForcedDIPScale()) density = sForcedDIPScale.floatValue();
         boolean isWideColorGamut = false;
         // Although this API was added in Android O, it was buggy.
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/AnimatedImageDragShadowBuilder.java b/ui/android/java/src/org/chromium/ui/dragdrop/AnimatedImageDragShadowBuilder.java
index b6fe175..7f9b80c 100644
--- a/ui/android/java/src/org/chromium/ui/dragdrop/AnimatedImageDragShadowBuilder.java
+++ b/ui/android/java/src/org/chromium/ui/dragdrop/AnimatedImageDragShadowBuilder.java
@@ -21,6 +21,7 @@
 
 import androidx.core.content.res.ResourcesCompat;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.R;
 
 /**
@@ -28,6 +29,7 @@
  * to the center of the touch point. See go/animated-image-drag-shadow-corner-cases for known edge
  * cases.
  */
+@NullMarked
 class AnimatedImageDragShadowBuilder extends View.DragShadowBuilder {
     /**
      * Animatable progress for the drag shadow. When the progress is 0, the drag shadow is full size
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropBrowserDelegate.java b/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropBrowserDelegate.java
index 5370e0a9..2dbf0fb 100644
--- a/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropBrowserDelegate.java
+++ b/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropBrowserDelegate.java
@@ -9,9 +9,11 @@
 import android.view.DragAndDropPermissions;
 import android.view.DragEvent;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.dragdrop.DragDropMetricUtils.UrlIntentSource;
 
 /** Delegate for browser related functions used by Drag and Drop. */
+@NullMarked
 public interface DragAndDropBrowserDelegate {
     /** Get whether to support the image drop into Chrome. */
     boolean getSupportDropInChrome();
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegate.java b/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegate.java
index 33d2f76..c6783c6 100644
--- a/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegate.java
+++ b/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegate.java
@@ -9,10 +9,14 @@
 import android.view.View;
 import android.view.View.DragShadowBuilder;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
 /**
  * Delegate to facilitate Drag and Drop operations, for example re-routing the call to {@link
  * #startDragAndDrop(Bitmap, DropDataAndroid).}
  */
+@NullMarked
 public interface DragAndDropDelegate {
     /**
      * @see View#startDragAndDrop
@@ -21,7 +25,7 @@
             View containerView,
             Bitmap shadowImage,
             DropDataAndroid dropData,
-            Context context,
+            @Nullable Context context,
             int cursorOffsetX,
             int cursorOffsetY,
             int dragObjRectWidth,
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegateImpl.java b/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegateImpl.java
index 58b8b41..caf33f7 100644
--- a/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegateImpl.java
+++ b/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegateImpl.java
@@ -24,8 +24,6 @@
 import android.widget.ImageView;
 
 import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.core.graphics.drawable.RoundedBitmapDrawable;
@@ -34,6 +32,9 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.MathUtils;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.R;
 import org.chromium.ui.accessibility.AccessibilityState;
 import org.chromium.ui.base.MimeTypeUtils;
@@ -50,6 +51,7 @@
  * Drag and drop helper class in charge of building the clip data, wrapping calls to {@link
  * android.view.View#startDragAndDrop}. Also used for mocking out real function calls to Android.
  */
+@NullMarked
 public class DragAndDropDelegateImpl implements DragAndDropDelegate, DragStateTracker {
     /**
      * Java Enum of AndroidDragTargetType used for histogram recording for
@@ -107,12 +109,13 @@
      * @param dragObjRectWidth The width of the drag object.
      * @param dragObjRectHeight The height of the drag object.
      */
+    @NullUnmarked
     @Override
     public boolean startDragAndDrop(
-            @NonNull View containerView,
-            @NonNull Bitmap shadowImage,
-            @NonNull DropDataAndroid dropData,
-            @NonNull Context context,
+            View containerView,
+            Bitmap shadowImage,
+            DropDataAndroid dropData,
+            @Nullable Context context,
             int cursorOffsetX,
             int cursorOffsetY,
             int dragObjRectWidth,
@@ -137,9 +140,7 @@
 
     @Override
     public boolean startDragAndDrop(
-            @NonNull View containerView,
-            @NonNull DragShadowBuilder dragShadowBuilder,
-            @NonNull DropDataAndroid dropData) {
+            View containerView, DragShadowBuilder dragShadowBuilder, DropDataAndroid dropData) {
         if (isA11yStateEnabled()) return false;
         return startDragAndDropInternal(containerView, dragShadowBuilder, dropData);
     }
@@ -152,9 +153,7 @@
     }
 
     private boolean startDragAndDropInternal(
-            @NonNull View containerView,
-            @NonNull DragShadowBuilder dragShadowBuilder,
-            @NonNull DropDataAndroid dropData) {
+            View containerView, DragShadowBuilder dragShadowBuilder, DropDataAndroid dropData) {
         ClipData clipdata = buildClipData(dropData);
         if (clipdata == null
                 && !UiAndroidFeatureMap.isEnabled(UiAndroidFeatureList.DRAG_DROP_EMPTY)) {
@@ -240,8 +239,8 @@
      * @param dropData The data to be dropped.
      * @return ClipData based on the dropData type.
      */
-    @Nullable
-    protected ClipData buildClipData(DropDataAndroid dropData) {
+    @NullUnmarked
+    protected @Nullable ClipData buildClipData(DropDataAndroid dropData) {
         @DragTargetType int type = getDragTargetType(dropData);
         switch (type) {
             case DragTargetType.TEXT:
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/DragDropGlobalState.java b/ui/android/java/src/org/chromium/ui/dragdrop/DragDropGlobalState.java
index dead210..659a70c 100644
--- a/ui/android/java/src/org/chromium/ui/dragdrop/DragDropGlobalState.java
+++ b/ui/android/java/src/org/chromium/ui/dragdrop/DragDropGlobalState.java
@@ -8,11 +8,10 @@
 import android.view.DragEvent;
 import android.view.View.DragShadowBuilder;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
 import org.chromium.base.Log;
 import org.chromium.base.ResettersForTesting;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * Drag-Drop objects to be shared across instances. General usage:
@@ -25,6 +24,7 @@
  * <li>When drag ends, client that starts the drag need to do {@link #clear(TrackerToken)} to reset
  *     the global state.
  */
+@NullMarked
 public class DragDropGlobalState {
     private static final String TAG = "DnDGlobalState";
     private @Nullable static GlobalStateHolder sGlobalStateHolder;
@@ -57,7 +57,7 @@
      */
     public static TrackerToken store(
             int dragSourceInstanceId,
-            @NonNull DropDataAndroid dropData,
+            DropDataAndroid dropData,
             @Nullable DragShadowBuilder dragShadowBuilder) {
         if (sGlobalStateHolder != null) {
             Log.w(
@@ -88,7 +88,7 @@
     }
 
     /** Get the global state using DragEvent with {@link DragEvent#ACTION_DROP}. */
-    public static @Nullable DragDropGlobalState getState(@NonNull DragEvent dropEvent) {
+    public static @Nullable DragDropGlobalState getState(DragEvent dropEvent) {
         if (sGlobalStateHolder == null || dropEvent.getAction() != DragEvent.ACTION_DROP) {
             return null;
         }
@@ -99,7 +99,7 @@
      * Return the drag shadow builder during this drag and drop process, if provided to the
      * DragDropGlobalState.
      */
-    public static DragShadowBuilder getDragShadowBuilder() {
+    public static @Nullable DragShadowBuilder getDragShadowBuilder() {
         if (sGlobalStateHolder == null) return null;
         return sGlobalStateHolder.mDragShadowBuilder;
     }
@@ -108,16 +108,16 @@
      * Tokens are released when startDragAndDrop fails or by listeners on drag end event. If a
      * caller fails to release token, sHolder is not cleared and the next build call will fail.
      */
-    public static void clear(@NonNull TrackerToken token) {
+    public static void clear(TrackerToken token) {
         assert sGlobalStateHolder == null || sGlobalStateHolder.mToken.equals(token)
                 : "Token mismatch.";
         sGlobalStateHolder = null;
     }
 
     private final int mDragSourceInstanceId;
-    private final @NonNull DropDataAndroid mDropData;
+    private final DropDataAndroid mDropData;
 
-    DragDropGlobalState(int dragSourceInstanceId, @NonNull DropDataAndroid dropData) {
+    DragDropGlobalState(int dragSourceInstanceId, DropDataAndroid dropData) {
         mDragSourceInstanceId = dragSourceInstanceId;
         mDropData = dropData;
     }
@@ -133,11 +133,10 @@
     }
 
     /** Return the {@link DropDataAndroid} held by the global state. */
-    public @NonNull DropDataAndroid getData() {
+    public DropDataAndroid getData() {
         return mDropData;
     }
 
-    @NonNull
     @Override
     public String toString() {
         return "DragDropGlobalState" + " sourceId:" + mDragSourceInstanceId;
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/DragDropMetricUtils.java b/ui/android/java/src/org/chromium/ui/dragdrop/DragDropMetricUtils.java
index f009dbb9..453c67a 100644
--- a/ui/android/java/src/org/chromium/ui/dragdrop/DragDropMetricUtils.java
+++ b/ui/android/java/src/org/chromium/ui/dragdrop/DragDropMetricUtils.java
@@ -7,11 +7,13 @@
 import androidx.annotation.IntDef;
 
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.build.annotations.NullMarked;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 /** Define enums for Drag and Drop metrics. This class is not supposed to be instantiated. */
+@NullMarked
 public class DragDropMetricUtils {
     public static String HISTOGRAM_DRAG_DROP_TAB_TYPE = "Android.DragDrop.Tab.Type";
 
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/DragEventDispatchHelper.java b/ui/android/java/src/org/chromium/ui/dragdrop/DragEventDispatchHelper.java
index 9ca755b..9c1d33ac 100644
--- a/ui/android/java/src/org/chromium/ui/dragdrop/DragEventDispatchHelper.java
+++ b/ui/android/java/src/org/chromium/ui/dragdrop/DragEventDispatchHelper.java
@@ -9,9 +9,11 @@
 import android.view.View;
 import android.view.View.OnDragListener;
 
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
 /**
  * Wrapper class that accounts for drag event coordinate differences when forwarding a
  * {@link DragEvent} from View A to View B. This class currently only support destinations that
@@ -38,6 +40,7 @@
  * }
  * </pre>
  */
+@NullMarked
 public class DragEventDispatchHelper implements OnDragListener {
     static final int[] ALL_DRAG_ACTIONS =
             new int[] {
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/DragStateTracker.java b/ui/android/java/src/org/chromium/ui/dragdrop/DragStateTracker.java
index 6e55d804..4b4ec7a 100644
--- a/ui/android/java/src/org/chromium/ui/dragdrop/DragStateTracker.java
+++ b/ui/android/java/src/org/chromium/ui/dragdrop/DragStateTracker.java
@@ -6,7 +6,10 @@
 
 import android.view.View;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Helper class the listen and track the latest drag event for the view. */
+@NullMarked
 public interface DragStateTracker extends View.OnDragListener {
     /** Return whether there's an active drag process started. */
     default boolean isDragStarted() {
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/DropDataAndroid.java b/ui/android/java/src/org/chromium/ui/dragdrop/DropDataAndroid.java
index a04f89d..e2ae399c 100644
--- a/ui/android/java/src/org/chromium/ui/dragdrop/DropDataAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/dragdrop/DropDataAndroid.java
@@ -11,10 +11,12 @@
 import org.jni_zero.CalledByNative;
 import org.jni_zero.JNINamespace;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.url.GURL;
 
 /** Bare minimal wrapper class of native content::DropData. */
 @JNINamespace("ui")
+@NullMarked
 public class DropDataAndroid {
     public final String text;
     public final GURL gurl;
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/DropDataContentProvider.java b/ui/android/java/src/org/chromium/ui/dragdrop/DropDataContentProvider.java
index 2d07454..8f3be9d 100644
--- a/ui/android/java/src/org/chromium/ui/dragdrop/DropDataContentProvider.java
+++ b/ui/android/java/src/org/chromium/ui/dragdrop/DropDataContentProvider.java
@@ -12,10 +12,11 @@
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
 import java.io.FileNotFoundException;
 
 /**
@@ -26,6 +27,7 @@
  * the feature from different platforms as other platform won't be able to access the impl
  * class directly as it lives in other classloader than the app's one (Chromium classloader).
  */
+@NullMarked
 public class DropDataContentProvider extends ContentProvider {
     private DropDataProviderImpl mDropDataProviderImpl;
 
@@ -41,54 +43,58 @@
     }
 
     @Override
-    public String getType(Uri uri) {
+    public @Nullable String getType(Uri uri) {
         return mDropDataProviderImpl.getType(uri);
     }
 
     @Override
-    public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
+    public String @Nullable [] getStreamTypes(Uri uri, String mimeTypeFilter) {
         return mDropDataProviderImpl.getStreamTypes(uri, mimeTypeFilter);
     }
 
     @Override
-    public AssetFileDescriptor openAssetFile(Uri uri, String mode)
+    public @Nullable AssetFileDescriptor openAssetFile(Uri uri, String mode)
             throws FileNotFoundException, SecurityException {
         return mDropDataProviderImpl.openAssetFile(this, uri, mode);
     }
 
     @Override
-    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+    public @Nullable ParcelFileDescriptor openFile(Uri uri, String mode)
+            throws FileNotFoundException {
         return mDropDataProviderImpl.openFile(this, uri);
     }
 
     @Override
     public Cursor query(
             Uri uri,
-            String[] projection,
-            String selection,
-            String[] selectionArgs,
-            String sortOrder) {
+            String @Nullable [] projection,
+            @Nullable String selection,
+            String @Nullable [] selectionArgs,
+            @Nullable String sortOrder) {
         return mDropDataProviderImpl.query(uri, projection);
     }
 
     @Override
-    public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
+    public int update(
+            Uri uri,
+            @Nullable ContentValues values,
+            @Nullable String where,
+            String @Nullable [] whereArgs) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public int delete(Uri uri, String selection, String[] selectionArgs) {
+    public int delete(Uri uri, @Nullable String selection, String @Nullable [] selectionArgs) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public Uri insert(Uri uri, ContentValues values) {
+    public Uri insert(Uri uri, @Nullable ContentValues values) {
         throw new UnsupportedOperationException();
     }
 
-    @Nullable
     @Override
-    public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
+    public @Nullable Bundle call(String method, @Nullable String arg, @Nullable Bundle extras) {
         return mDropDataProviderImpl.call(method, arg, extras);
     }
 
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/DropDataProviderImpl.java b/ui/android/java/src/org/chromium/ui/dragdrop/DropDataProviderImpl.java
index b8df2ba3..c24a88d 100644
--- a/ui/android/java/src/org/chromium/ui/dragdrop/DropDataProviderImpl.java
+++ b/ui/android/java/src/org/chromium/ui/dragdrop/DropDataProviderImpl.java
@@ -18,11 +18,11 @@
 import android.provider.OpenableColumns;
 import android.webkit.MimeTypeMap;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
 import org.chromium.base.ContextUtils;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.build.annotations.UsedByReflection;
 
 import java.io.FileNotFoundException;
@@ -38,6 +38,7 @@
  *     provider to this java doc.
  */
 @UsedByReflection("Webview Support Lib")
+@NullMarked
 public class DropDataProviderImpl {
     public static final String CACHE_METHOD_NAME = "cache";
     public static final String SET_INTERVAL_METHOD_NAME = "setClearCachedDataIntervalMs";
@@ -70,8 +71,8 @@
                 ParcelFileDescriptor output,
                 Uri uri,
                 String mimeType,
-                Bundle opts,
-                byte[] imageBytes) {
+                @Nullable Bundle opts,
+                byte @Nullable [] imageBytes) {
             try (OutputStream out = new FileOutputStream(output.getFileDescriptor())) {
                 if (imageBytes != null) {
                     out.write(imageBytes);
@@ -91,21 +92,25 @@
     private static final Object LOCK = new Object();
 
     private int mClearCachedDataIntervalMs = DEFAULT_CLEAR_CACHED_DATA_INTERVAL_MS;
+
+    @SuppressWarnings("NullAway.Init")
     private byte[] mImageBytes;
-    private String mImageFilename;
-    private String mMimeType;
+
+    private @Nullable String mImageFilename;
+    private @Nullable String mMimeType;
 
     /** The URI handled by this content provider. */
-    private Uri mContentProviderUri;
+    private @Nullable Uri mContentProviderUri;
 
-    private Handler mHandler;
+    private @Nullable Handler mHandler;
     private long mDragEndTime;
     private long mOpenFileLastAccessTime;
-    private Uri mLastUri;
+    private @Nullable Uri mLastUri;
     private long mLastUriClearedTimestamp;
     private long mLastUriCreatedTimestamp;
     private boolean mLastUriRecorded;
 
+    @SuppressWarnings("NullAway.Init")
     private DropPipeDataWriter mDropPipeDataWriter;
 
     /** This constructor is being used to initialize the pipeWriter. */
@@ -134,7 +139,8 @@
     /**
      * Cache the passed-in image data of Drag and Drop. It is expected for filename to be non-empty.
      */
-    public Uri cache(byte[] imageBytes, String encodingFormat, String filename) {
+    public Uri cache(
+            byte[] imageBytes, @Nullable String encodingFormat, @Nullable String filename) {
         long elapsedRealtime = SystemClock.elapsedRealtime();
         long lastUriCreatedTimestamp = mLastUriCreatedTimestamp;
         String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(encodingFormat);
@@ -199,6 +205,7 @@
     }
 
     /** Clear the image data of Drag and Drop. */
+    @NullUnmarked
     private void clearCacheData() {
         mImageBytes = null;
         mImageFilename = null;
@@ -240,7 +247,7 @@
     /**
      * @see ContentProvider#getType(Uri)
      */
-    public String getType(Uri uri) {
+    public @Nullable String getType(Uri uri) {
         synchronized (LOCK) {
             if (uri == null || !uri.equals(mContentProviderUri)) {
                 return null;
@@ -252,7 +259,7 @@
     /**
      * @see ContentProvider#getStreamTypes(Uri, String)
      */
-    public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
+    public String @Nullable [] getStreamTypes(Uri uri, String mimeTypeFilter) {
         String mimeType;
         synchronized (LOCK) {
             if (uri == null || !uri.equals(mContentProviderUri)) {
@@ -263,7 +270,7 @@
         return matchMimeType(mimeType, mimeTypeFilter) ? new String[] {mimeType} : null;
     }
 
-    private boolean matchMimeType(String mimeType, String mimeTypeFilter) {
+    private boolean matchMimeType(@Nullable String mimeType, String mimeTypeFilter) {
         if (mimeType == null || mimeTypeFilter == null) {
             return false;
         }
@@ -283,7 +290,9 @@
     /**
      * @see ContentProvider#openAssetFile(Uri, String)
      */
-    public AssetFileDescriptor openAssetFile(ContentProvider providerWrapper, Uri uri, String mode)
+    @NullUnmarked
+    public @Nullable AssetFileDescriptor openAssetFile(
+            ContentProvider providerWrapper, Uri uri, String mode)
             throws FileNotFoundException, SecurityException {
         if (uri == null) {
             return null;
@@ -322,7 +331,7 @@
     /**
      * @see ContentProvider#openFile(Uri, String)
      */
-    public ParcelFileDescriptor openFile(ContentProvider providerWrapper, Uri uri)
+    public @Nullable ParcelFileDescriptor openFile(ContentProvider providerWrapper, Uri uri)
             throws FileNotFoundException {
         AssetFileDescriptor afd = openAssetFile(providerWrapper, uri, "r");
         return afd != null ? afd.getParcelFileDescriptor() : null;
@@ -331,7 +340,8 @@
     /**
      * @see ContentProvider#query(Uri, String[], String, String[], String)
      */
-    public Cursor query(Uri uri, String[] projection) {
+    @NullUnmarked
+    public Cursor query(Uri uri, String @Nullable [] projection) {
         byte[] imageBytes;
         String imageFilename;
         synchronized (LOCK) {
@@ -378,8 +388,8 @@
     /**
      * @see ContentProvider#call(String, String, Bundle)
      */
-    @Nullable
-    public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
+    @NullUnmarked
+    public @Nullable Bundle call(String method, @Nullable String arg, @Nullable Bundle extras) {
         switch (method) {
             case CACHE_METHOD_NAME:
                 Bundle bundleToReturn = new Bundle();
@@ -410,6 +420,7 @@
         }
     }
 
+    @Nullable
     Handler getHandlerForTesting() {
         synchronized (LOCK) {
             return mHandler;
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/DropDataProviderUtils.java b/ui/android/java/src/org/chromium/ui/dragdrop/DropDataProviderUtils.java
index a588641d..b7f03014 100644
--- a/ui/android/java/src/org/chromium/ui/dragdrop/DropDataProviderUtils.java
+++ b/ui/android/java/src/org/chromium/ui/dragdrop/DropDataProviderUtils.java
@@ -11,14 +11,16 @@
 import android.net.Uri;
 import android.os.Bundle;
 
-import androidx.annotation.Nullable;
-
 import org.chromium.base.ContextUtils;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * This class wraps all the calls to ContentResolver#call.
  *
  */
+@NullMarked
 public class DropDataProviderUtils {
     /**
      * Wraps the call to onDragEnd in the provider, we call it to clear the cached image data after
@@ -57,8 +59,8 @@
      * Wraps the call to cache in the provider and returns the cached Uri or null if it failed to
      * call the content provider.
      */
-    @Nullable
-    static Uri cacheImageData(DropDataAndroid dropData) {
+    @NullUnmarked
+    static @Nullable Uri cacheImageData(DropDataAndroid dropData) {
         Bundle bundle = new Bundle();
         bundle.putSerializable(DropDataProviderImpl.BYTES_PARAM, dropData.imageContent);
         bundle.putString(
diff --git a/ui/android/java/src/org/chromium/ui/drawable/AnimationLooper.java b/ui/android/java/src/org/chromium/ui/drawable/AnimationLooper.java
index bee2b8c..ce71d12 100644
--- a/ui/android/java/src/org/chromium/ui/drawable/AnimationLooper.java
+++ b/ui/android/java/src/org/chromium/ui/drawable/AnimationLooper.java
@@ -9,16 +9,18 @@
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 
-import androidx.annotation.Nullable;
 import androidx.vectordrawable.graphics.drawable.Animatable2Compat;
 import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;
 
 import org.chromium.base.ResettersForTesting;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * Encapsulates the logic to loop animated drawables from both Android Framework. The animation
  * should be started and stopped using {@link #start()} and {@link #stop()}.
  */
+@NullMarked
 public class AnimationLooper {
     private static @Nullable Boolean sAreAnimatorsEnabledForTests;
 
diff --git a/ui/android/java/src/org/chromium/ui/drawable/StateListDrawableBuilder.java b/ui/android/java/src/org/chromium/ui/drawable/StateListDrawableBuilder.java
index bc3475c..fbeb933 100644
--- a/ui/android/java/src/org/chromium/ui/drawable/StateListDrawableBuilder.java
+++ b/ui/android/java/src/org/chromium/ui/drawable/StateListDrawableBuilder.java
@@ -13,6 +13,8 @@
 import androidx.annotation.DrawableRes;
 import androidx.appcompat.content.res.AppCompatResources;
 
+import org.chromium.build.annotations.NullMarked;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -35,6 +37,7 @@
  * builder.addTransition(unchecked, checked, R.drawable.transition_unchecked_checked);
  * StateListDrawable drawable = builder.build();
  */
+@NullMarked
 public class StateListDrawableBuilder {
     /** Identifies single state of the drawable. Used by {@link #addTransition}. */
     public static class State {
diff --git a/ui/android/java/src/org/chromium/ui/events/devices/InputDeviceObserver.java b/ui/android/java/src/org/chromium/ui/events/devices/InputDeviceObserver.java
index 91f169d2..7cb9b98 100644
--- a/ui/android/java/src/org/chromium/ui/events/devices/InputDeviceObserver.java
+++ b/ui/android/java/src/org/chromium/ui/events/devices/InputDeviceObserver.java
@@ -17,12 +17,16 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * A singleton that helps detecting changes in input devices through the interface
  * {@link InputDeviceObserver}.
  */
 @JNINamespace("ui")
+@NullMarked
 public class InputDeviceObserver implements InputDeviceListener {
     private static final InputDeviceObserver INSTANCE = new InputDeviceObserver();
     private static final String KEYBOARD_CONNECTION_HISTOGRAM_NAME =
@@ -50,7 +54,7 @@
         INSTANCE.detachObserver();
     }
 
-    private InputManager mInputManager;
+    private @Nullable InputManager mInputManager;
     private int mObserversCounter;
 
     // Override InputDeviceListener methods
@@ -96,6 +100,7 @@
         }
     }
 
+    @NullUnmarked
     private void detachObserver() {
         assert mObserversCounter > 0;
         if (--mObserversCounter == 0) {
diff --git a/ui/android/java/src/org/chromium/ui/gfx/Animation.java b/ui/android/java/src/org/chromium/ui/gfx/Animation.java
index cd7fd1d9..2a18c83b 100644
--- a/ui/android/java/src/org/chromium/ui/gfx/Animation.java
+++ b/ui/android/java/src/org/chromium/ui/gfx/Animation.java
@@ -10,12 +10,14 @@
 import org.jni_zero.JNINamespace;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.build.annotations.NullMarked;
 
 /**
  * Provides utility methods relating to system animation state on the current platform (i.e. Android
  * in this case). See ui/gfx/animation/animation_android.cc.
  */
 @JNINamespace("gfx")
+@NullMarked
 public class Animation {
     @CalledByNative
     private static boolean prefersReducedMotion() {
diff --git a/ui/android/java/src/org/chromium/ui/gfx/BitmapHelper.java b/ui/android/java/src/org/chromium/ui/gfx/BitmapHelper.java
index f2eb0a8..bb36419 100644
--- a/ui/android/java/src/org/chromium/ui/gfx/BitmapHelper.java
+++ b/ui/android/java/src/org/chromium/ui/gfx/BitmapHelper.java
@@ -10,14 +10,17 @@
 import org.jni_zero.JNINamespace;
 
 import org.chromium.base.Log;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /** Helper class to decode and sample down bitmap resources. */
 @JNINamespace("gfx")
+@NullMarked
 public class BitmapHelper {
     private static final String TAG = "BitmapHelper";
 
     @CalledByNative
-    private static Bitmap createBitmap(
+    private static @Nullable Bitmap createBitmap(
             int width, int height, int bitmapFormatValue, boolean catchOom) {
         Bitmap.Config bitmapConfig = getBitmapConfigForFormat(bitmapFormatValue);
         try {
diff --git a/ui/android/java/src/org/chromium/ui/gfx/ViewConfigurationHelper.java b/ui/android/java/src/org/chromium/ui/gfx/ViewConfigurationHelper.java
index bcaa328..1eed5a8 100644
--- a/ui/android/java/src/org/chromium/ui/gfx/ViewConfigurationHelper.java
+++ b/ui/android/java/src/org/chromium/ui/gfx/ViewConfigurationHelper.java
@@ -16,6 +16,7 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.StrictModeContext;
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.R;
 
 /**
@@ -24,6 +25,7 @@
  *
  */
 @JNINamespace("gfx")
+@NullMarked
 public class ViewConfigurationHelper {
 
     // Fallback constants when resource lookup fails, see
diff --git a/ui/android/java/src/org/chromium/ui/gl/ChromeSurfaceTexture.java b/ui/android/java/src/org/chromium/ui/gl/ChromeSurfaceTexture.java
index 731b74d..581789b 100644
--- a/ui/android/java/src/org/chromium/ui/gl/ChromeSurfaceTexture.java
+++ b/ui/android/java/src/org/chromium/ui/gl/ChromeSurfaceTexture.java
@@ -11,8 +11,11 @@
 import org.jni_zero.JNINamespace;
 import org.jni_zero.NativeMethods;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Exposes SurfaceTexture APIs to native. */
 @JNINamespace("gl")
+@NullMarked
 class ChromeSurfaceTexture extends SurfaceTexture
         implements SurfaceTexture.OnFrameAvailableListener {
     private static final String TAG = "SurfaceTexture";
diff --git a/ui/android/java/src/org/chromium/ui/gl/ScopedJavaSurfaceControl.java b/ui/android/java/src/org/chromium/ui/gl/ScopedJavaSurfaceControl.java
index 6e7bbab..54a62f2 100644
--- a/ui/android/java/src/org/chromium/ui/gl/ScopedJavaSurfaceControl.java
+++ b/ui/android/java/src/org/chromium/ui/gl/ScopedJavaSurfaceControl.java
@@ -12,8 +12,11 @@
 import org.jni_zero.CalledByNative;
 import org.jni_zero.JNINamespace;
 
+import org.chromium.build.annotations.NullMarked;
+
 @RequiresApi(Build.VERSION_CODES.Q)
 @JNINamespace("gl")
+@NullMarked
 class ScopedJavaSurfaceControl {
     @CalledByNative
     private static void releaseSurfaceControl(SurfaceControl surfaceControl) {
diff --git a/ui/android/java/src/org/chromium/ui/interpolators/AndroidxInterpolators.java b/ui/android/java/src/org/chromium/ui/interpolators/AndroidxInterpolators.java
index 8590301..2b082c19 100644
--- a/ui/android/java/src/org/chromium/ui/interpolators/AndroidxInterpolators.java
+++ b/ui/android/java/src/org/chromium/ui/interpolators/AndroidxInterpolators.java
@@ -7,7 +7,10 @@
 import androidx.core.animation.Interpolator;
 import androidx.core.animation.PathInterpolator;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Reference to one of each standard interpolator to avoid allocations. */
+@NullMarked
 public class AndroidxInterpolators {
     public static final Interpolator STANDARD_INTERPOLATOR = new PathInterpolator(0.2f, 0f, 0f, 1f);
 }
diff --git a/ui/android/java/src/org/chromium/ui/interpolators/Interpolators.java b/ui/android/java/src/org/chromium/ui/interpolators/Interpolators.java
index 6e4074e0..b61c6a1 100644
--- a/ui/android/java/src/org/chromium/ui/interpolators/Interpolators.java
+++ b/ui/android/java/src/org/chromium/ui/interpolators/Interpolators.java
@@ -16,7 +16,10 @@
 import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
 import androidx.interpolator.view.animation.LinearOutSlowInInterpolator;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Reference to one of each standard interpolator to avoid allocations. */
+@NullMarked
 public class Interpolators {
     public static final Interpolator STANDARD_INTERPOLATOR =
             PathInterpolatorCompat.create(0.2f, 0f, 0f, 1f);
diff --git a/ui/android/java/src/org/chromium/ui/listmenu/BasicListMenu.java b/ui/android/java/src/org/chromium/ui/listmenu/BasicListMenu.java
index 929a47d..d70db50c 100644
--- a/ui/android/java/src/org/chromium/ui/listmenu/BasicListMenu.java
+++ b/ui/android/java/src/org/chromium/ui/listmenu/BasicListMenu.java
@@ -15,11 +15,12 @@
 
 import androidx.annotation.ColorRes;
 import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.core.content.ContextCompat;
 import androidx.core.view.ViewCompat;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.R;
 import org.chromium.ui.UiUtils;
 import org.chromium.ui.modelutil.LayoutViewBuilder;
@@ -37,6 +38,7 @@
  * An implementation of a list menu. Uses app_menu_layout as the default layout of menu and
  * list_menu_item as the default layout of a menu item.
  */
+@NullMarked
 public class BasicListMenu implements ListMenu, OnItemClickListener {
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({ListMenuItemType.DIVIDER, ListMenuItemType.MENU_ITEM})
@@ -78,7 +80,7 @@
             boolean isIconTintable,
             boolean groupContainsIcon,
             boolean enabled,
-            @Nullable View.OnClickListener clickListener,
+            View.@Nullable OnClickListener clickListener,
             @Nullable Intent intent) {
         PropertyModel.Builder modelBuilder =
                 new PropertyModel.Builder(ListMenuItemProperties.ALL_KEYS)
@@ -102,11 +104,11 @@
         return new ListItem(ListMenuItemType.MENU_ITEM, modelBuilder.build());
     }
 
-    private final @NonNull ListView mListView;
-    private final @NonNull ModelListAdapter mAdapter;
-    private final @NonNull View mContentView;
-    private final @NonNull List<Runnable> mClickRunnables;
-    private final @NonNull Delegate mDelegate;
+    private final ListView mListView;
+    private final ModelListAdapter mAdapter;
+    private final View mContentView;
+    private final List<Runnable> mClickRunnables;
+    private final Delegate mDelegate;
 
     /**
      * @param context The {@link Context} to inflate the layout.
@@ -117,11 +119,11 @@
      * @param backgroundTintColor The background tint color of the menu.
      */
     public BasicListMenu(
-            @NonNull Context context,
-            @NonNull ModelList data,
-            @NonNull View contentView,
-            @NonNull ListView listView,
-            @NonNull Delegate delegate,
+            Context context,
+            ModelList data,
+            View contentView,
+            ListView listView,
+            Delegate delegate,
             @ColorRes int backgroundTintColor) {
         mAdapter = new ListMenuItemAdapter(data);
         mContentView = contentView;
@@ -140,13 +142,11 @@
         }
     }
 
-    @NonNull
     @Override
     public View getContentView() {
         return mContentView;
     }
 
-    @NonNull
     public ListView getListView() {
         return mListView;
     }
@@ -183,6 +183,7 @@
         return result;
     }
 
+    @NullUnmarked
     private void registerListItemTypes() {
         mAdapter.registerType(
                 ListMenuItemType.MENU_ITEM,
diff --git a/ui/android/java/src/org/chromium/ui/listmenu/ListMenu.java b/ui/android/java/src/org/chromium/ui/listmenu/ListMenu.java
index c32e00f..1e93ecbb 100644
--- a/ui/android/java/src/org/chromium/ui/listmenu/ListMenu.java
+++ b/ui/android/java/src/org/chromium/ui/listmenu/ListMenu.java
@@ -6,12 +6,14 @@
 
 import android.view.View;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modelutil.PropertyModel;
 
 /**
  * Representation of a list menu. Contains and manages a content view by {@link #getContentView()}.
  * Handles click events of list items by {@link Delegate#onItemSelected(PropertyModel)}.
  */
+@NullMarked
 public interface ListMenu {
     /** Delegate handling list item click event of {@link ListMenu}. */
     @FunctionalInterface
diff --git a/ui/android/java/src/org/chromium/ui/listmenu/ListMenuButton.java b/ui/android/java/src/org/chromium/ui/listmenu/ListMenuButton.java
index 992d19ab..aa635a7 100644
--- a/ui/android/java/src/org/chromium/ui/listmenu/ListMenuButton.java
+++ b/ui/android/java/src/org/chromium/ui/listmenu/ListMenuButton.java
@@ -16,6 +16,9 @@
 import android.view.ViewParent;
 
 import org.chromium.base.ObserverList;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.R;
 import org.chromium.ui.widget.AnchoredPopupWindow;
 import org.chromium.ui.widget.ChromeImageButton;
@@ -27,6 +30,7 @@
  * parameter in the XML layout of the ListMenuButton. The default content description that
  * corresponds to context.getString(R.string.accessibility_list_menu_button, "") is used otherwise.
  */
+@NullMarked
 public class ListMenuButton extends ChromeImageButton
         implements AnchoredPopupWindow.LayoutObserver {
     /** A listener that is notified when the popup menu is shown or dismissed. */
@@ -41,8 +45,11 @@
     private final boolean mMenuHorizontalOverlapAnchor;
 
     private int mMenuMaxWidth;
+
+    @SuppressWarnings("NullAway.Init")
     private AnchoredPopupWindow mPopupMenu;
-    private ListMenuButtonDelegate mDelegate;
+
+    private @Nullable ListMenuButtonDelegate mDelegate;
     private ObserverList<PopupMenuShownListener> mPopupListeners = new ObserverList<>();
     private boolean mTryToFitLargestItem;
     private boolean mPositionedAtEnd;
@@ -141,6 +148,7 @@
     }
 
     /** Init the popup window with provided attributes, called before {@link #showMenu()} */
+    @NullUnmarked
     private void initPopupWindow() {
         if (mDelegate == null) throw new IllegalStateException("Delegate was not set.");
 
diff --git a/ui/android/java/src/org/chromium/ui/listmenu/ListMenuButtonDelegate.java b/ui/android/java/src/org/chromium/ui/listmenu/ListMenuButtonDelegate.java
index 797c377..7d2ab505 100644
--- a/ui/android/java/src/org/chromium/ui/listmenu/ListMenuButtonDelegate.java
+++ b/ui/android/java/src/org/chromium/ui/listmenu/ListMenuButtonDelegate.java
@@ -6,10 +6,12 @@
 
 import android.view.View;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.widget.RectProvider;
 import org.chromium.ui.widget.ViewRectProvider;
 
 /** A delegate used to populate the menu. */
+@NullMarked
 public interface ListMenuButtonDelegate {
     /**
      * @param listMenuButton The anchor for the {@link ListMenu}.
diff --git a/ui/android/java/src/org/chromium/ui/listmenu/ListMenuItemAdapter.java b/ui/android/java/src/org/chromium/ui/listmenu/ListMenuItemAdapter.java
index edd288de..2a844cb 100644
--- a/ui/android/java/src/org/chromium/ui/listmenu/ListMenuItemAdapter.java
+++ b/ui/android/java/src/org/chromium/ui/listmenu/ListMenuItemAdapter.java
@@ -8,10 +8,12 @@
 import android.view.ViewGroup;
 import android.widget.ListView;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.listmenu.BasicListMenu.ListMenuItemType;
 import org.chromium.ui.modelutil.ModelListAdapter;
 
 /** Default adapter for use with {@link ListMenu}. */
+@NullMarked
 public class ListMenuItemAdapter extends ModelListAdapter {
     public ListMenuItemAdapter(ModelList data) {
         super(data);
diff --git a/ui/android/java/src/org/chromium/ui/listmenu/ListMenuItemProperties.java b/ui/android/java/src/org/chromium/ui/listmenu/ListMenuItemProperties.java
index 07dd225..36a1815 100644
--- a/ui/android/java/src/org/chromium/ui/listmenu/ListMenuItemProperties.java
+++ b/ui/android/java/src/org/chromium/ui/listmenu/ListMenuItemProperties.java
@@ -8,6 +8,7 @@
 import android.graphics.drawable.Drawable;
 import android.view.View;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.ReadableBooleanPropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.ReadableIntPropertyKey;
@@ -19,6 +20,7 @@
  * The properties controlling the state of the list menu items. Any given list item can have either
  * one start icon or one end icon but not both.
  */
+@NullMarked
 public class ListMenuItemProperties {
     // TODO(crbug.com/40738791): Consider passing menu item title through TITLE property instead of
     // TITLE_ID.
diff --git a/ui/android/java/src/org/chromium/ui/listmenu/ListMenuItemViewBinder.java b/ui/android/java/src/org/chromium/ui/listmenu/ListMenuItemViewBinder.java
index 68703f9..4ceaaba8 100644
--- a/ui/android/java/src/org/chromium/ui/listmenu/ListMenuItemViewBinder.java
+++ b/ui/android/java/src/org/chromium/ui/listmenu/ListMenuItemViewBinder.java
@@ -11,11 +11,13 @@
 import android.widget.TextView;
 
 import androidx.annotation.ColorRes;
-import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.core.widget.ImageViewCompat;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.R;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -30,8 +32,11 @@
  * As for when a list item contains an icon, it is expected that it either has a start icon
  * OR an end icon, not both.
  */
+@NullMarked
 public class ListMenuItemViewBinder {
-    public static void binder(PropertyModel model, View view, PropertyKey propertyKey) {
+    @NullUnmarked
+    public static void binder(
+            PropertyModel model, @Nullable View view, @Nullable PropertyKey propertyKey) {
         TextView textView = view.findViewById(R.id.menu_item_text);
         ImageView startIcon = view.findViewById(R.id.menu_item_icon);
         ImageView endIcon = view.findViewById(R.id.menu_item_end_icon);
diff --git a/ui/android/java/src/org/chromium/ui/listmenu/ListSectionDividerProperties.java b/ui/android/java/src/org/chromium/ui/listmenu/ListSectionDividerProperties.java
index b37e1e85..43b650c 100644
--- a/ui/android/java/src/org/chromium/ui/listmenu/ListSectionDividerProperties.java
+++ b/ui/android/java/src/org/chromium/ui/listmenu/ListSectionDividerProperties.java
@@ -4,10 +4,12 @@
 
 package org.chromium.ui.listmenu;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.WritableIntPropertyKey;
 
 /** Properties for customizing the list section divider. */
+@NullMarked
 public class ListSectionDividerProperties {
     public static final WritableIntPropertyKey LEFT_PADDING_DIMEN_ID = new WritableIntPropertyKey();
     public static final WritableIntPropertyKey RIGHT_PADDING_DIMEN_ID =
diff --git a/ui/android/java/src/org/chromium/ui/listmenu/ListSectionDividerViewBinder.java b/ui/android/java/src/org/chromium/ui/listmenu/ListSectionDividerViewBinder.java
index 1b48de4..76909ce3 100644
--- a/ui/android/java/src/org/chromium/ui/listmenu/ListSectionDividerViewBinder.java
+++ b/ui/android/java/src/org/chromium/ui/listmenu/ListSectionDividerViewBinder.java
@@ -9,6 +9,7 @@
 import androidx.annotation.DimenRes;
 import androidx.annotation.Px;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
@@ -16,6 +17,7 @@
  * Class responsible for binding the list section divider. This is primarily needed to enable
  * customization of the list section divider.
  */
+@NullMarked
 public class ListSectionDividerViewBinder {
 
     public static void bind(PropertyModel model, View view, PropertyKey propertyKey) {
diff --git a/ui/android/java/src/org/chromium/ui/modaldialog/DialogDismissalCause.java b/ui/android/java/src/org/chromium/ui/modaldialog/DialogDismissalCause.java
index b309d85..775b637 100644
--- a/ui/android/java/src/org/chromium/ui/modaldialog/DialogDismissalCause.java
+++ b/ui/android/java/src/org/chromium/ui/modaldialog/DialogDismissalCause.java
@@ -6,6 +6,8 @@
 
 import androidx.annotation.IntDef;
 
+import org.chromium.build.annotations.NullMarked;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -30,6 +32,7 @@
     DialogDismissalCause.CLIENT_TIMEOUT
 })
 @Retention(RetentionPolicy.SOURCE)
+@NullMarked
 public @interface DialogDismissalCause {
     // Dismissal causes that are fully controlled by clients (i.e. are not used inside the
     // dialog manager or the dialog presenters) are marked "Controlled by client" on comments.
diff --git a/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManager.java b/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManager.java
index ebc46f239..afc361e 100644
--- a/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManager.java
+++ b/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManager.java
@@ -9,13 +9,14 @@
 
 import androidx.activity.ComponentDialog;
 import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 
 import org.chromium.base.Callback;
 import org.chromium.base.CommandLine;
 import org.chromium.base.ObserverList;
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.InsetObserver;
 import org.chromium.ui.UiSwitches;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -30,6 +31,7 @@
 import java.util.Set;
 
 /** Manager for managing the display of a queue of {@link PropertyModel}s. */
+@NullMarked
 public class ModalDialogManager {
     /**
      * An observer of the ModalDialogManager intended to broadcast notifications about any dialog
@@ -80,8 +82,8 @@
 
     /** Present a {@link PropertyModel} in a container. */
     public abstract static class Presenter {
-        private Callback<Integer> mDismissCallback;
-        private PropertyModel mDialogModel;
+        private @Nullable Callback<Integer> mDismissCallback;
+        private @Nullable PropertyModel mDialogModel;
 
         /**
          * @param model The dialog model that's currently showing in this presenter. If null, no
@@ -119,7 +121,7 @@
         /**
          * @return The dialog model that this presenter is showing.
          */
-        public final PropertyModel getDialogModel() {
+        public final @Nullable PropertyModel getDialogModel() {
             return mDialogModel;
         }
 
@@ -154,7 +156,7 @@
          *
          * @param model The dialog model that needs to be removed.
          */
-        protected abstract void removeDialogView(PropertyModel model);
+        protected abstract void removeDialogView(@Nullable PropertyModel model);
 
         /**
          * An {@link InsetObserver} to get insets for the window associated with a modal dialog.
@@ -244,7 +246,7 @@
      * The presenter of the type of the dialog that is currently showing. Note that if there is no
      * matching {@link Presenter} for {@link #mCurrentType}, this will be the default presenter.
      */
-    private Presenter mCurrentPresenter;
+    private @Nullable Presenter mCurrentPresenter;
 
     /**
      * The type of the current dialog. This can be different from the type of the current
@@ -258,7 +260,7 @@
     /** True if the current dialog is in the process of being dismissed. */
     private boolean mDismissingCurrentDialog;
 
-    private ModalDialogManagerBridge mModalDialogManagerBridge;
+    private @Nullable ModalDialogManagerBridge mModalDialogManagerBridge;
 
     private boolean mDestroyed;
 
@@ -275,10 +277,10 @@
     private final PendingDialogContainer mPendingDialogContainer = new PendingDialogContainer();
 
     /** An {@link InsetObserver} to provide system window insets. */
-    private InsetObserver mInsetObserver;
+    private @Nullable InsetObserver mInsetObserver;
 
     /** A supplier to determine whether edge-to-edge is active in the enclosing window. */
-    private final ObservableSupplier<Boolean> mEdgeToEdgeStateSupplier;
+    private final @Nullable ObservableSupplier<Boolean> mEdgeToEdgeStateSupplier;
 
     /**
      * Constructor for initializing default {@link Presenter}. TODO (crbug.com/41492646): Remove
@@ -287,8 +289,7 @@
      * @param defaultPresenter The default presenter to be used when no presenter specified.
      * @param defaultType The dialog type of the default presenter.
      */
-    public ModalDialogManager(
-            @NonNull Presenter defaultPresenter, @ModalDialogType int defaultType) {
+    public ModalDialogManager(Presenter defaultPresenter, @ModalDialogType int defaultType) {
         this(defaultPresenter, defaultType, /* edgeToEdgeStateSupplier= */ null);
     }
 
@@ -303,9 +304,9 @@
      *     applicable.
      */
     public ModalDialogManager(
-            @NonNull Presenter defaultPresenter,
+            Presenter defaultPresenter,
             @ModalDialogType int defaultType,
-            ObservableSupplier<Boolean> edgeToEdgeStateSupplier) {
+            @Nullable ObservableSupplier<Boolean> edgeToEdgeStateSupplier) {
         mDefaultPresenter = defaultPresenter;
         mEdgeToEdgeStateSupplier = edgeToEdgeStateSupplier;
         registerPresenter(defaultPresenter, defaultType);
@@ -513,7 +514,8 @@
      * @param dismissalCause The {@link DialogDismissalCause} that describes why the dialog is
      *     dismissed.
      */
-    public void dismissDialog(PropertyModel model, @DialogDismissalCause int dismissalCause) {
+    public void dismissDialog(
+            @Nullable PropertyModel model, @DialogDismissalCause int dismissalCause) {
         if (model == null) return;
         if (dismissalCause == DialogDismissalCause.NAVIGATE_BACK_OR_TOUCH_OUTSIDE) {
             assert mCurrentType == ModalDialogType.APP;
@@ -553,6 +555,7 @@
      * @param dismissalCause The {@link DialogDismissalCause} that describes why the dialogs are
      *                       dismissed.
      */
+    @NullUnmarked
     public void dismissAllDialogs(@DialogDismissalCause int dismissalCause) {
         for (@ModalDialogType int dialogType = ModalDialogType.RANGE_MIN;
                 dialogType <= ModalDialogType.RANGE_MAX;
@@ -586,6 +589,7 @@
      *                       dismissed.
      * @return true if a dialog was showing and was dismissed.
      */
+    @NullUnmarked
     public boolean dismissActiveDialogOfType(
             @ModalDialogType int dialogType, @DialogDismissalCause int dismissalCause) {
         if (isShowing() && dialogType == mCurrentType) {
@@ -621,6 +625,7 @@
      * @param dialogType The specified type of dialogs to be suspended.
      * @return A token to use when resuming the suspended type.
      */
+    @NullUnmarked
     public int suspendType(@ModalDialogType int dialogType) {
         mSuspendedTypes.add(dialogType);
         if (isShowing()
@@ -638,6 +643,7 @@
      * @param dialogType The specified type of dialogs to be resumed.
      * @param token The token generated from suspending the dialog type.
      */
+    @NullUnmarked
     public void resumeType(@ModalDialogType int dialogType, int token) {
         mTokenHolders.get(dialogType).releaseToken(token);
     }
@@ -657,6 +663,7 @@
      *
      * @param dialogType The specified type of dialogs to be resumed.
      */
+    @NullUnmarked
     private void resumeTypeInternal(@ModalDialogType int dialogType) {
         if (mTokenHolders.get(dialogType).hasTokens()) return;
         mSuspendedTypes.remove(dialogType);
@@ -664,6 +671,7 @@
     }
 
     /** Hide the current dialog and put it back to the front of the pending list. */
+    @NullUnmarked
     private void suspendCurrentDialog() {
         assert isShowing();
         PropertyModel dialogView = mCurrentPresenter.getDialogModel();
@@ -702,7 +710,7 @@
         }
     }
 
-    public PropertyModel getCurrentDialogForTest() {
+    public @Nullable PropertyModel getCurrentDialogForTest() {
         return mCurrentPresenter == null ? null : mCurrentPresenter.getDialogModel();
     }
 
@@ -715,6 +723,7 @@
         return mPresenters.get(dialogType);
     }
 
+    @NullUnmarked
     public Presenter getCurrentPresenterForTest() {
         return mCurrentPresenter;
     }
diff --git a/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManagerBridge.java b/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManagerBridge.java
index 2fa6cf6..8bfbd1d 100644
--- a/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManagerBridge.java
+++ b/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManagerBridge.java
@@ -4,22 +4,22 @@
 
 package org.chromium.ui.modaldialog;
 
-import androidx.annotation.NonNull;
-
 import org.jni_zero.CalledByNative;
 import org.jni_zero.JNINamespace;
 import org.jni_zero.NativeMethods;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.ModalDialogWrapper;
 import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType;
 
 @JNINamespace("ui")
+@NullMarked
 public class ModalDialogManagerBridge {
 
     private final ModalDialogManager mModalDialogManager;
     private long mNativePtr;
 
-    public ModalDialogManagerBridge(@NonNull ModalDialogManager manager) {
+    public ModalDialogManagerBridge(ModalDialogManager manager) {
         mModalDialogManager = manager;
         mNativePtr = ModalDialogManagerBridgeJni.get().create(this);
     }
diff --git a/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManagerHolder.java b/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManagerHolder.java
index 57708147..780a85f 100644
--- a/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManagerHolder.java
+++ b/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManagerHolder.java
@@ -4,7 +4,10 @@
 
 package org.chromium.ui.modaldialog;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Classes that hold an instance of {@link ModalDialogManager} should implement this interface. */
+@NullMarked
 public interface ModalDialogManagerHolder {
     /**
      * @return The {@link ModalDialogManager} associated with this class
diff --git a/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogProperties.java b/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogProperties.java
index ce499691..2c1bdd6 100644
--- a/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogProperties.java
+++ b/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogProperties.java
@@ -10,6 +10,7 @@
 import androidx.activity.OnBackPressedCallback;
 import androidx.annotation.IntDef;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModel.ReadableBooleanPropertyKey;
@@ -24,6 +25,7 @@
 import java.lang.annotation.RetentionPolicy;
 
 /** The model properties for a modal dialog. */
+@NullMarked
 public class ModalDialogProperties {
     /** Interface that controls the actions on the modal dialog. */
     public interface Controller {
diff --git a/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogUtils.java b/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogUtils.java
index 77f187c..87eeed54 100644
--- a/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogUtils.java
+++ b/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogUtils.java
@@ -8,12 +8,14 @@
 
 import androidx.annotation.StringRes;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType;
 import org.chromium.ui.modaldialog.ModalDialogProperties.ButtonStyles;
 import org.chromium.ui.modaldialog.ModalDialogProperties.ButtonType;
 import org.chromium.ui.modelutil.PropertyModel;
 
 /** Set of shared helper functions for using {@link ModalDialogManager}. */
+@NullMarked
 public final class ModalDialogUtils {
     /** Do not allow instantiation for utils class. */
     private ModalDialogUtils() {}
diff --git a/ui/android/java/src/org/chromium/ui/modaldialog/PendingDialogContainer.java b/ui/android/java/src/org/chromium/ui/modaldialog/PendingDialogContainer.java
index dd1b878..2ab87547 100644
--- a/ui/android/java/src/org/chromium/ui/modaldialog/PendingDialogContainer.java
+++ b/ui/android/java/src/org/chromium/ui/modaldialog/PendingDialogContainer.java
@@ -4,8 +4,8 @@
 
 package org.chromium.ui.modaldialog;
 
-import androidx.annotation.Nullable;
-
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogPriority;
 import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -22,6 +22,7 @@
  * A container class to provide basic operations for pending dialogs with attributes {@link
  * ModalDialogType} and {@link ModalDialogPriority}.
  */
+@NullMarked
 class PendingDialogContainer {
     /** A class representing the attributes of a pending dialog. */
     static class PendingDialogType {
@@ -75,7 +76,7 @@
     void put(
             @ModalDialogType int dialogType,
             @ModalDialogPriority int dialogPriority,
-            PropertyModel model,
+            @Nullable PropertyModel model,
             boolean showAsNext) {
         Integer key = computeKey(dialogType, dialogPriority);
         List<PropertyModel> dialogs = mPendingDialogs.get(key);
diff --git a/ui/android/java/src/org/chromium/ui/modaldialog/SimpleModalDialogController.java b/ui/android/java/src/org/chromium/ui/modaldialog/SimpleModalDialogController.java
index f7210b4e..0540448 100644
--- a/ui/android/java/src/org/chromium/ui/modaldialog/SimpleModalDialogController.java
+++ b/ui/android/java/src/org/chromium/ui/modaldialog/SimpleModalDialogController.java
@@ -4,9 +4,10 @@
 
 package org.chromium.ui.modaldialog;
 
-import androidx.annotation.NonNull;
-
 import org.chromium.base.Callback;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.modelutil.PropertyModel;
 
 /**
@@ -14,16 +15,17 @@
  *
  * The result of the dialog is passed back via a Callback.
  */
+@NullMarked
 public class SimpleModalDialogController implements ModalDialogProperties.Controller {
     private final ModalDialogManager mModalDialogManager;
-    private Callback<Integer> mActionCallback;
+    private @Nullable Callback<Integer> mActionCallback;
 
     /**
      * @param modalDialogManager the dialog manager where the dialog will be shown.
      * @param action a callback which will be run with the result of the confirmation.
      */
     public SimpleModalDialogController(
-            ModalDialogManager modalDialogManager, @NonNull Callback<Integer> action) {
+            ModalDialogManager modalDialogManager, Callback<Integer> action) {
         mModalDialogManager = modalDialogManager;
         mActionCallback = action;
     }
@@ -37,6 +39,7 @@
         }
     }
 
+    @NullUnmarked
     @Override
     public void onDismiss(PropertyModel model, int dismissalCause) {
         Callback<Integer> action = mActionCallback;
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/ForwardingListObservable.java b/ui/android/java/src/org/chromium/ui/modelutil/ForwardingListObservable.java
index 3faad27..8767384 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/ForwardingListObservable.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/ForwardingListObservable.java
@@ -3,7 +3,8 @@
 // found in the LICENSE file.
 package org.chromium.ui.modelutil;
 
-import androidx.annotation.Nullable;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * Helper class for implementing a {@link ListObserver} that just forwards to its own observers.
@@ -12,6 +13,7 @@
  *     partial updates. TODO(bauerb): Remove this class if it turns out we can shortcut
  *     notifications
  */
+@NullMarked
 public class ForwardingListObservable<P> extends ListObservableImpl<P>
         implements ListObservable.ListObserver<P> {
     @Override
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/LayoutViewBuilder.java b/ui/android/java/src/org/chromium/ui/modelutil/LayoutViewBuilder.java
index 52b9825a..dd6e4a0 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/LayoutViewBuilder.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/LayoutViewBuilder.java
@@ -10,12 +10,15 @@
 
 import androidx.annotation.LayoutRes;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.modelutil.MVCListAdapter.ViewBuilder;
 
 /** Helper class that inflates view from XML layout. */
+@NullMarked
 public class LayoutViewBuilder<T extends View> implements ViewBuilder<T> {
     @LayoutRes private final int mLayoutResId;
-    private LayoutInflater mInflater;
+    private @Nullable LayoutInflater mInflater;
 
     public LayoutViewBuilder(@LayoutRes int res) {
         mLayoutResId = res;
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/LazyConstructionPropertyMcp.java b/ui/android/java/src/org/chromium/ui/modelutil/LazyConstructionPropertyMcp.java
index 7d20beb..7473abf 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/LazyConstructionPropertyMcp.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/LazyConstructionPropertyMcp.java
@@ -4,8 +4,8 @@
 
 package org.chromium.ui.modelutil;
 
-import androidx.annotation.Nullable;
-
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.ViewProvider;
 
 import java.util.HashSet;
@@ -19,6 +19,7 @@
  * @param <V> The view type
  * @param <P> The property type for the model
  */
+@NullMarked
 public class LazyConstructionPropertyMcp<M extends PropertyObservable<P>, V, P>
         implements PropertyObservable.PropertyObserver<P> {
     /**
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/ListModel.java b/ui/android/java/src/org/chromium/ui/modelutil/ListModel.java
index 11ba6d0..330e304 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/ListModel.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/ListModel.java
@@ -3,6 +3,8 @@
 // found in the LICENSE file.
 package org.chromium.ui.modelutil;
 
+import org.chromium.build.annotations.NullMarked;
+
 /**
  * Base class for a {@link ListObservable} containing a {@link SimpleList} of items.
  * It allows models to compose different ListObservables.
@@ -11,4 +13,5 @@
  * support partial change notification.
  * @param <T> The object type that this class manages in a list.
  */
+@NullMarked
 public class ListModel<T> extends ListModelBase<T, Void> {}
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/ListModelBase.java b/ui/android/java/src/org/chromium/ui/modelutil/ListModelBase.java
index 31cea15..63a0936 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/ListModelBase.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/ListModelBase.java
@@ -4,7 +4,7 @@
 
 package org.chromium.ui.modelutil;
 
-import androidx.annotation.NonNull;
+import org.chromium.build.annotations.NullMarked;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -20,6 +20,7 @@
  * @param <T> The object type that this class manages in a list.
  * @param <P> The payload type for partial change notifications.
  */
+@NullMarked
 public class ListModelBase<T, P> extends ListObservableImpl<P> implements SimpleList<T> {
     private final List<T> mItems = new ArrayList<>();
 
@@ -38,7 +39,6 @@
         return mItems.size();
     }
 
-    @NonNull
     @Override
     public Iterator<T> iterator() {
         return mItems.iterator();
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/ListModelChangeProcessor.java b/ui/android/java/src/org/chromium/ui/modelutil/ListModelChangeProcessor.java
index 9a35cb8..0211e16 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/ListModelChangeProcessor.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/ListModelChangeProcessor.java
@@ -4,7 +4,8 @@
 
 package org.chromium.ui.modelutil;
 
-import androidx.annotation.Nullable;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * A model change processor for use with a {@link ListObservable} model. The
@@ -18,6 +19,7 @@
  * @param <V> The view object that is changing.
  * @param <P> The payload for partial updates. Void can be used if a payload is not needed.
  */
+@NullMarked
 public class ListModelChangeProcessor<M extends ListObservable<P>, V, P>
         implements ListObservable.ListObserver<P> {
     /**
@@ -34,7 +36,7 @@
 
         void onItemsRemoved(M model, V view, int index, int count);
 
-        void onItemsChanged(M model, V view, int index, int count, P payload);
+        void onItemsChanged(M model, V view, int index, int count, @Nullable P payload);
     }
 
     private final V mView;
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/ListObservable.java b/ui/android/java/src/org/chromium/ui/modelutil/ListObservable.java
index 4cdb356d..004e525d 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/ListObservable.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/ListObservable.java
@@ -3,7 +3,8 @@
 // found in the LICENSE file.
 package org.chromium.ui.modelutil;
 
-import androidx.annotation.Nullable;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * An interface for models notifying about changes to a list of items. Note that ListObservable
@@ -16,6 +17,7 @@
  * @param <P> The parameter type for the payload for partial updates. Use {@link Void} for
  *         implementations that don't support partial updates.
  */
+@NullMarked
 public interface ListObservable<P> {
     /**
      * @param observer An observer to be notified of changes to the model.
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/ListObservableImpl.java b/ui/android/java/src/org/chromium/ui/modelutil/ListObservableImpl.java
index 5c79e5b..a4f14c0 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/ListObservableImpl.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/ListObservableImpl.java
@@ -4,9 +4,9 @@
 
 package org.chromium.ui.modelutil;
 
-import androidx.annotation.Nullable;
-
 import org.chromium.base.ObserverList;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * Helper class for implementations of {@link ListObservable}, with some convenience methods for
@@ -14,6 +14,7 @@
  * @param <P> The parameter type for the payload for partial updates. Use {@link Void} for
  *         implementations that don't support partial updates.
  */
+@NullMarked
 public abstract class ListObservableImpl<P> implements ListObservable<P> {
     private final ObserverList<ListObserver<P>> mObservers = new ObserverList<>();
 
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/MVCListAdapter.java b/ui/android/java/src/org/chromium/ui/modelutil/MVCListAdapter.java
index 1ba7325..03d87738 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/MVCListAdapter.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/MVCListAdapter.java
@@ -7,8 +7,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import androidx.annotation.NonNull;
-
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor.ViewBinder;
 
 /**
@@ -18,6 +17,7 @@
  * different types of views that can be shown by the list, i.e.:
  * {@link #registerType(int, ViewBuilder, ViewBinder)}.
  */
+@NullMarked
 public interface MVCListAdapter {
     /** A basic container for {@link PropertyModel}s with a type. */
     class ListItem {
@@ -50,7 +50,7 @@
          * @param parent Parent view.
          * @return A new view to show in the list.
          */
-        T buildView(@NonNull ViewGroup parent);
+        T buildView(ViewGroup parent);
     }
 
     /**
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/ModelListAdapter.java b/ui/android/java/src/org/chromium/ui/modelutil/ModelListAdapter.java
index 0b8819a3..c7b9978 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/ModelListAdapter.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/ModelListAdapter.java
@@ -10,9 +10,10 @@
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
 
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.R;
 import org.chromium.ui.modelutil.ListObservable.ListObserver;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor.ViewBinder;
@@ -37,6 +38,7 @@
  * Additionally, ModelListAdapter will hook up a {@link PropertyModelChangeProcessor} when binding
  * views to ensure that changes to the PropertyModel for that list item are bound to the view.
  */
+@NullMarked
 public class ModelListAdapter extends BaseAdapter implements MVCListAdapter {
     private final ModelList mModelList;
     private final SparseArray<Pair<ViewBuilder, ViewBinder>> mViewBuilderMap = new SparseArray<>();
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/ModelListPropertyChangeFilter.java b/ui/android/java/src/org/chromium/ui/modelutil/ModelListPropertyChangeFilter.java
index fb835e70..362c70ab 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/ModelListPropertyChangeFilter.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/ModelListPropertyChangeFilter.java
@@ -4,8 +4,8 @@
 
 package org.chromium.ui.modelutil;
 
-import androidx.annotation.NonNull;
-
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.modelutil.ListObservable.ListObserver;
 import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
 import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
@@ -19,6 +19,7 @@
  * Observes and notifies when any of the filtered {@link PropertyKey}s are changed inside the
  * {@link ModelList}.
  */
+@NullMarked
 public class ModelListPropertyChangeFilter
         implements ListObserver<Void>, PropertyObserver<PropertyKey> {
     private final Runnable mOnPropertyChange;
@@ -67,7 +68,8 @@
     }
 
     @Override
-    public void onPropertyChanged(PropertyObservable<PropertyKey> source, PropertyKey propertyKey) {
+    public void onPropertyChanged(
+            PropertyObservable<PropertyKey> source, @Nullable PropertyKey propertyKey) {
         if (mPropertyKeySet.contains(propertyKey)) {
             mOnPropertyChange.run();
         }
@@ -88,7 +90,7 @@
      * set and the new set, and call  {@link PropertyModel#removeObserver(PropertyObserver)} on any
      * we figure out have been removed.
      */
-    private void prunePropertyModels(@NonNull Set<PropertyModel> newPropertyModels) {
+    private void prunePropertyModels(Set<PropertyModel> newPropertyModels) {
         for (PropertyModel existingPropertyModel : mTrackedPropertyModels) {
             if (!newPropertyModels.contains(existingPropertyModel)) {
                 existingPropertyModel.removeObserver(this);
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/PropertyKey.java b/ui/android/java/src/org/chromium/ui/modelutil/PropertyKey.java
index 73fa74a..0063818 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/PropertyKey.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/PropertyKey.java
@@ -3,8 +3,11 @@
 // found in the LICENSE file.
 package org.chromium.ui.modelutil;
 
+import org.chromium.build.annotations.NullMarked;
+
 /**
  * Place holder interface to allow key definitions. Should not be used directly and only exposed to
  * allow use as generic placeholders.
  */
+@NullMarked
 public interface PropertyKey {}
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/PropertyListModel.java b/ui/android/java/src/org/chromium/ui/modelutil/PropertyListModel.java
index 9166ad45..5d0b769 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/PropertyListModel.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/PropertyListModel.java
@@ -4,7 +4,8 @@
 
 package org.chromium.ui.modelutil;
 
-import androidx.annotation.Nullable;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 import java.util.Collection;
 
@@ -14,6 +15,7 @@
  * @param <T> The type of item in the list.
  * @param <P> The property key type for {@code T} to be used as payload for partial updates.
  */
+@NullMarked
 public class PropertyListModel<T extends PropertyObservable<P>, P> extends ListModelBase<T, P> {
     private final PropertyObservable.PropertyObserver<P> mPropertyObserver =
             this::onPropertyChanged;
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/PropertyModel.java b/ui/android/java/src/org/chromium/ui/modelutil/PropertyModel.java
index b7691d4a..fbd0876 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/PropertyModel.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/PropertyModel.java
@@ -9,13 +9,14 @@
 import android.graphics.drawable.Drawable;
 
 import androidx.annotation.DrawableRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.core.util.ObjectsCompat;
 
 import org.chromium.build.BuildConfig;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -27,10 +28,11 @@
 /**
  * Generic property model that aims to provide an extensible and efficient model for ease of use.
  */
+@NullMarked
 public class PropertyModel extends PropertyObservable<PropertyKey> {
     /** A PropertyKey implementation that associates a name with the property for easy debugging. */
     private static class NamedPropertyKey implements PropertyKey {
-        private final String mPropertyName;
+        private final @Nullable String mPropertyName;
 
         public NamedPropertyKey(@Nullable String propertyName) {
             mPropertyName = propertyName;
@@ -246,7 +248,7 @@
      */
     public static class ReadableTransformingObjectPropertyKey<T, V> extends NamedPropertyKey {
         /** Constructor for a named {@link ReadableTransformingObjectPropertyKey}. */
-        public ReadableTransformingObjectPropertyKey(String name) {
+        public ReadableTransformingObjectPropertyKey(@Nullable String name) {
             super(name);
         }
 
@@ -266,7 +268,7 @@
     public static final class WritableTransformingObjectPropertyKey<T, V>
             extends ReadableTransformingObjectPropertyKey<T, V> {
         /** Constructor for a named {@link WritableTransformingObjectPropertyKey}. */
-        public WritableTransformingObjectPropertyKey(String name) {
+        public WritableTransformingObjectPropertyKey(@Nullable String name) {
             super(name);
         }
 
@@ -277,7 +279,8 @@
     }
 
     private final Map<PropertyKey, ValueContainer> mData;
-    private final Map<ReadableTransformingObjectPropertyKey<?, ?>, Function<?, ?>> mTransformers;
+    private final @Nullable Map<ReadableTransformingObjectPropertyKey<?, ?>, Function<?, ?>>
+            mTransformers;
 
     /**
      * Constructs a model for the given list of keys.
@@ -303,7 +306,8 @@
 
     private PropertyModel(
             Map<PropertyKey, ValueContainer> startingValues,
-            Map<ReadableTransformingObjectPropertyKey<?, ?>, Function<?, ?>> transformers) {
+            @Nullable
+                    Map<ReadableTransformingObjectPropertyKey<?, ?>, Function<?, ?>> transformers) {
         mData = startingValues;
         mTransformers = transformers;
     }
@@ -408,6 +412,7 @@
     }
 
     /** Get the current value from the object based key. */
+    @NullUnmarked
     @SuppressWarnings("unchecked")
     public <T> T get(ReadableObjectPropertyKey<T> key) {
         validateKey(key);
@@ -432,8 +437,9 @@
     }
 
     /** Get the transformed value from the current value of an object based key. */
+    @NullUnmarked
     @SuppressWarnings("unchecked")
-    public <T, V> V get(ReadableTransformingObjectPropertyKey<T, V> key) {
+    public <T, V> @Nullable V get(ReadableTransformingObjectPropertyKey<T, V> key) {
         validateKey(key);
         ObjectContainer<T> container = (ObjectContainer<T>) mData.get(key);
         Function<T, V> transformer = (Function<T, V>) mTransformers.get(key);
@@ -505,9 +511,7 @@
      * @return The value from the model or the default if the value is not found.
      */
     public static int getFromModelOrDefault(
-            @NonNull PropertyModel model,
-            @NonNull PropertyModel.ReadableIntPropertyKey key,
-            int defaultValue) {
+            PropertyModel model, PropertyModel.ReadableIntPropertyKey key, int defaultValue) {
         // We need to check first because PropertyModel#get throws an exception if a key
         // is not present in the Map.
         if (model.containsKey(key)) {
@@ -525,10 +529,9 @@
      * @param defaultValue The default value if the the property is not found.
      * @return The value from the model or the default if the value is not found.
      */
-    @Nullable
-    public static <T> T getFromModelOrDefault(
-            @NonNull PropertyModel model,
-            @NonNull PropertyModel.ReadableObjectPropertyKey<T> key,
+    public static <T> @Nullable T getFromModelOrDefault(
+            PropertyModel model,
+            PropertyModel.ReadableObjectPropertyKey<T> key,
             @Nullable T defaultValue) {
         // We need to check first because PropertyModel#get throws an exception if a key
         // is not present in the Map.
@@ -541,7 +544,8 @@
     /** Allows constructing a new {@link PropertyModel} with read-only properties. */
     public static class Builder {
         private final Map<PropertyKey, ValueContainer> mData;
-        private Map<ReadableTransformingObjectPropertyKey<?, ?>, Function<?, ?>> mTransformers;
+        private @Nullable Map<ReadableTransformingObjectPropertyKey<?, ?>, Function<?, ?>>
+                mTransformers;
 
         public Builder(PropertyKey... keys) {
             this(buildData(keys));
@@ -589,7 +593,7 @@
             return this;
         }
 
-        public <T> Builder with(ReadableObjectPropertyKey<T> key, T value) {
+        public <T> Builder with(ReadableObjectPropertyKey<T> key, @Nullable T value) {
             validateKey(key);
             ObjectContainer<T> container = new ObjectContainer<>();
             container.value = value;
@@ -763,7 +767,7 @@
     }
 
     private static class ObjectContainer<T> extends ValueContainer {
-        public T value;
+        public @Nullable T value;
 
         @Override
         public String toString() {
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/PropertyModelAnimatorFactory.java b/ui/android/java/src/org/chromium/ui/modelutil/PropertyModelAnimatorFactory.java
index 1f62b419..0a836d8 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/PropertyModelAnimatorFactory.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/PropertyModelAnimatorFactory.java
@@ -7,12 +7,14 @@
 import android.animation.ObjectAnimator;
 import android.util.FloatProperty;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.modelutil.PropertyModel.WritableFloatPropertyKey;
 
 /**
  * Static factory class that creates Animators for MVC properties by providing implementations of
  * android.util.Property that mutate a given property in a given model.
  */
+@NullMarked
 public class PropertyModelAnimatorFactory {
     /**
      * Builds an Animator for the given model, key, and target value.
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/PropertyModelChangeProcessor.java b/ui/android/java/src/org/chromium/ui/modelutil/PropertyModelChangeProcessor.java
index 5ad37f2..69f810fe 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/PropertyModelChangeProcessor.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/PropertyModelChangeProcessor.java
@@ -4,6 +4,8 @@
 
 package org.chromium.ui.modelutil;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.modelutil.PropertyObservable.PropertyObserver;
 
 /**
@@ -14,6 +16,7 @@
  * @param <V> The view object that is changing.
  * @param <P> The property of the view that changed.
  */
+@NullMarked
 public class PropertyModelChangeProcessor<M extends PropertyObservable<P>, V, P> {
     /**
      * A generic view binder that associates a view with a model.
@@ -23,7 +26,7 @@
      * @param <P> The property of the view that changed.
      */
     public interface ViewBinder<M, V, P> {
-        void bind(M model, V view, P propertyKey);
+        void bind(M model, @Nullable V view, @Nullable P propertyKey);
     }
 
     private final V mView;
@@ -87,7 +90,7 @@
         mModel.removeObserver(mPropertyObserver);
     }
 
-    private void onPropertyChanged(PropertyObservable<P> source, P propertyKey) {
+    private void onPropertyChanged(PropertyObservable<P> source, @Nullable P propertyKey) {
         assert source == mModel;
 
         // TODO(bauerb): Add support for batching updates.
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/PropertyObservable.java b/ui/android/java/src/org/chromium/ui/modelutil/PropertyObservable.java
index 9e79030..49dd0cf4 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/PropertyObservable.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/PropertyObservable.java
@@ -4,9 +4,9 @@
 
 package org.chromium.ui.modelutil;
 
-import androidx.annotation.Nullable;
-
 import org.chromium.base.ObserverList;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 import java.util.Collection;
 
@@ -15,6 +15,7 @@
  *
  * @param <T> The type of the property key used for uniquely identifying properties.
  */
+@NullMarked
 public abstract class PropertyObservable<T> {
     /**
      * An observer to be notified of changes to a {@link PropertyObservable}.
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/RecyclerViewAdapter.java b/ui/android/java/src/org/chromium/ui/modelutil/RecyclerViewAdapter.java
index 4433ccf..c1ff817f 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/RecyclerViewAdapter.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/RecyclerViewAdapter.java
@@ -6,10 +6,12 @@
 
 import android.view.ViewGroup;
 
-import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.recyclerview.widget.RecyclerView.ViewHolder;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
 import java.util.List;
 
 /**
@@ -21,6 +23,7 @@
  * @param <P> The payload type for partial updates, or {@link Void} if the adapter does not support
  *     partial updates.
  */
+@NullMarked
 public class RecyclerViewAdapter<VH extends ViewHolder, P> extends RecyclerView.Adapter<VH>
         implements ListObservable.ListObserver<P> {
     /**
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/SimpleList.java b/ui/android/java/src/org/chromium/ui/modelutil/SimpleList.java
index 5b0133b..b4d64e6 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/SimpleList.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/SimpleList.java
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 package org.chromium.ui.modelutil;
 
-import androidx.annotation.NonNull;
+import org.chromium.build.annotations.NullMarked;
 
 import java.util.AbstractList;
 import java.util.Iterator;
@@ -14,6 +14,7 @@
  * classes that already extend another class and therefore can't inherit from {@link AbstractList}.
  * @param <T> The type of list item.
  */
+@NullMarked
 public interface SimpleList<T> extends Iterable<T> {
     /**
      * @return The size of the list.
@@ -34,7 +35,6 @@
      * modifications and does not check whether the underlying list is being modified.
      */
     @Override
-    @NonNull
     default Iterator<T> iterator() {
         return new Iterator<T>() {
             private int mI;
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/SimpleRecyclerViewAdapter.java b/ui/android/java/src/org/chromium/ui/modelutil/SimpleRecyclerViewAdapter.java
index 7bdf96e0..6a5ab71 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/SimpleRecyclerViewAdapter.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/SimpleRecyclerViewAdapter.java
@@ -9,9 +9,10 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.RecyclerView;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.modelutil.ListObservable.ListObserver;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor.ViewBinder;
 
@@ -22,6 +23,7 @@
  * adapter how to display a particular item. Updates to the {@link ListObservable} list provided in
  * the constructor will immediately be reflected in the list.
  */
+@NullMarked
 public class SimpleRecyclerViewAdapter
         extends RecyclerView.Adapter<SimpleRecyclerViewAdapter.ViewHolder>
         implements MVCListAdapter {
@@ -30,13 +32,14 @@
      */
     public static class ViewHolder extends RecyclerView.ViewHolder {
         /** The model change processor currently associated with this view and model. */
-        private PropertyModelChangeProcessor<PropertyModel, View, PropertyKey> mCurrentMcp;
+        private @Nullable PropertyModelChangeProcessor<PropertyModel, View, PropertyKey>
+                mCurrentMcp;
 
         /** The view binder that knows how to apply a model to the view this holder owns. */
         private ViewBinder<PropertyModel, View, PropertyKey> mBinder;
 
         /** A handle to the model currently held by this view holder. */
-        public PropertyModel model;
+        public @Nullable PropertyModel model;
 
         /**
          * @param itemView The view to manage.
@@ -51,10 +54,10 @@
          * Set the model for this view holder to manage.
          * @param model The model that should be bound to the view.
          */
-        void setModel(PropertyModel model) {
+        void setModel(@Nullable PropertyModel model) {
             if (mCurrentMcp != null) mCurrentMcp.destroy();
             this.model = model;
-            if (this.model == null) return;
+            if (model == null) return;
             mCurrentMcp = PropertyModelChangeProcessor.create(model, itemView, mBinder);
         }
     }
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/SimpleRecyclerViewMcp.java b/ui/android/java/src/org/chromium/ui/modelutil/SimpleRecyclerViewMcp.java
index 3cdbd33..215eacbe 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/SimpleRecyclerViewMcp.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/SimpleRecyclerViewMcp.java
@@ -3,9 +3,11 @@
 // found in the LICENSE file.
 package org.chromium.ui.modelutil;
 
-import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.RecyclerView;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
 /**
  * A model change processor (MCP), i.e. an implementation of {@link RecyclerViewAdapter.Delegate},
  * which represents a homogeneous {@link SimpleList} of items that are independent of each other.
@@ -13,6 +15,7 @@
  * @param <T> The type of items in the list.
  * @param <VH> The view holder type that shows items.
  */
+@NullMarked
 public class SimpleRecyclerViewMcp<T, VH> extends SimpleRecyclerViewMcpBase<T, VH, Void> {
     /**
      * View binding interface.
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/SimpleRecyclerViewMcpBase.java b/ui/android/java/src/org/chromium/ui/modelutil/SimpleRecyclerViewMcpBase.java
index b8073af..e7ef787c 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/SimpleRecyclerViewMcpBase.java
+++ b/ui/android/java/src/org/chromium/ui/modelutil/SimpleRecyclerViewMcpBase.java
@@ -4,9 +4,11 @@
 
 package org.chromium.ui.modelutil;
 
-import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.RecyclerView;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
 /**
  * A model change processor (MCP), i.e. an implementation of {@link RecyclerViewAdapter.Delegate},
  * which represents a homogeneous {@link SimpleList} of items that are independent of each other. It
@@ -17,10 +19,11 @@
  * @param <P> The payload type for partial updates. If the model change processor doesn't support
  *     partial updates, use the {@link SimpleRecyclerViewMcp} subclass.
  */
+@NullMarked
 public class SimpleRecyclerViewMcpBase<T, VH, P> extends ForwardingListObservable<P>
         implements RecyclerViewAdapter.Delegate<VH, P> {
     private final SimpleList<T> mModel;
-    private final ItemViewTypeCallback<T> mItemViewTypeCallback;
+    private final @Nullable ItemViewTypeCallback<T> mItemViewTypeCallback;
     private final ViewBinder<T, VH, P> mViewBinder;
 
     public SimpleRecyclerViewMcpBase(
diff --git a/ui/android/java/src/org/chromium/ui/permissions/ActivityAndroidPermissionDelegate.java b/ui/android/java/src/org/chromium/ui/permissions/ActivityAndroidPermissionDelegate.java
index 3f0b77f..a2a1325 100644
--- a/ui/android/java/src/org/chromium/ui/permissions/ActivityAndroidPermissionDelegate.java
+++ b/ui/android/java/src/org/chromium/ui/permissions/ActivityAndroidPermissionDelegate.java
@@ -6,9 +6,12 @@
 
 import android.app.Activity;
 
+import org.chromium.build.annotations.NullMarked;
+
 import java.lang.ref.WeakReference;
 
 /** AndroidPermissionDelegate implementation for Activity. */
+@NullMarked
 public class ActivityAndroidPermissionDelegate extends AndroidPermissionDelegateWithRequester {
     private WeakReference<Activity> mActivity;
 
diff --git a/ui/android/java/src/org/chromium/ui/permissions/AndroidPermissionDelegate.java b/ui/android/java/src/org/chromium/ui/permissions/AndroidPermissionDelegate.java
index f2ac40d..6541c62 100644
--- a/ui/android/java/src/org/chromium/ui/permissions/AndroidPermissionDelegate.java
+++ b/ui/android/java/src/org/chromium/ui/permissions/AndroidPermissionDelegate.java
@@ -4,7 +4,10 @@
 
 package org.chromium.ui.permissions;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Contains the functionality for interacting with the android permissions system. */
+@NullMarked
 public interface AndroidPermissionDelegate {
     /**
      * Determine whether access to a particular permission is granted.
diff --git a/ui/android/java/src/org/chromium/ui/permissions/AndroidPermissionDelegateWithRequester.java b/ui/android/java/src/org/chromium/ui/permissions/AndroidPermissionDelegateWithRequester.java
index 9254eaa..74b52db3 100644
--- a/ui/android/java/src/org/chromium/ui/permissions/AndroidPermissionDelegateWithRequester.java
+++ b/ui/android/java/src/org/chromium/ui/permissions/AndroidPermissionDelegateWithRequester.java
@@ -12,6 +12,7 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ContextUtils;
+import org.chromium.build.annotations.NullMarked;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -22,6 +23,7 @@
  * AndroidPermissionDelegate that implements much of the logic around requesting permissions.
  * Subclasses need to implement only the basic permissions checking and requesting methods.
  */
+@NullMarked
 public abstract class AndroidPermissionDelegateWithRequester implements AndroidPermissionDelegate {
     private Handler mHandler;
     private SparseArray<PermissionRequestInfo> mOutstandingPermissionRequests;
diff --git a/ui/android/java/src/org/chromium/ui/permissions/ContextualNotificationPermissionRequester.java b/ui/android/java/src/org/chromium/ui/permissions/ContextualNotificationPermissionRequester.java
index 2b41d034..760cc3ec 100644
--- a/ui/android/java/src/org/chromium/ui/permissions/ContextualNotificationPermissionRequester.java
+++ b/ui/android/java/src/org/chromium/ui/permissions/ContextualNotificationPermissionRequester.java
@@ -4,7 +4,8 @@
 
 package org.chromium.ui.permissions;
 
-import androidx.annotation.Nullable;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * Contains functionality to request Android notification permission contextually. This will result
@@ -12,12 +13,12 @@
  * the implementation provided from chrome layer. Internally delegates the permission request to
  * {@link NotificationPermissionController}.
  */
+@NullMarked
 public abstract class ContextualNotificationPermissionRequester {
-    private static ContextualNotificationPermissionRequester sInstance;
+    private static @Nullable ContextualNotificationPermissionRequester sInstance;
 
     /** @return The singleton instance of this class. */
-    @Nullable
-    public static ContextualNotificationPermissionRequester getInstance() {
+    public static @Nullable ContextualNotificationPermissionRequester getInstance() {
         return sInstance;
     }
 
diff --git a/ui/android/java/src/org/chromium/ui/permissions/PermissionCallback.java b/ui/android/java/src/org/chromium/ui/permissions/PermissionCallback.java
index 4e05e6b..ba908c1 100644
--- a/ui/android/java/src/org/chromium/ui/permissions/PermissionCallback.java
+++ b/ui/android/java/src/org/chromium/ui/permissions/PermissionCallback.java
@@ -4,7 +4,10 @@
 
 package org.chromium.ui.permissions;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Callback for permission requests. */
+@NullMarked
 public interface PermissionCallback {
     /**
      * Called upon completing a permission request.
diff --git a/ui/android/java/src/org/chromium/ui/permissions/PermissionPrefs.java b/ui/android/java/src/org/chromium/ui/permissions/PermissionPrefs.java
index 87378537..7e903f1 100644
--- a/ui/android/java/src/org/chromium/ui/permissions/PermissionPrefs.java
+++ b/ui/android/java/src/org/chromium/ui/permissions/PermissionPrefs.java
@@ -10,12 +10,14 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.TimeUtils;
+import org.chromium.build.annotations.NullMarked;
 
 import java.util.List;
 
 /**
  * Provides helper methods for shared preference access to store permission request related info.
  */
+@NullMarked
 public class PermissionPrefs {
     /**
      * Shared preference key prefix for remembering Android permissions denied by the user.
diff --git a/ui/android/java/src/org/chromium/ui/resources/HandleViewResources.java b/ui/android/java/src/org/chromium/ui/resources/HandleViewResources.java
index e1c9db5..bd6d9c77 100644
--- a/ui/android/java/src/org/chromium/ui/resources/HandleViewResources.java
+++ b/ui/android/java/src/org/chromium/ui/resources/HandleViewResources.java
@@ -18,10 +18,13 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ContextUtils;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.R;
 
 /** Helper class for retrieving resources related to selection handles. */
 @JNINamespace("ui")
+@NullMarked
 public class HandleViewResources {
     // Android handle drawables have a transparent horizontal padding,
     // which is one-fourth of the image. This variable is to take the
@@ -40,19 +43,19 @@
         android.R.attr.textSelectHandleRight,
     };
 
-    public static Drawable getLeftHandleDrawable(Context context) {
+    public static @Nullable Drawable getLeftHandleDrawable(Context context) {
         return getHandleDrawable(context, LEFT_HANDLE_ATTRS);
     }
 
-    public static Drawable getCenterHandleDrawable(Context context) {
+    public static @Nullable Drawable getCenterHandleDrawable(Context context) {
         return getHandleDrawable(context, CENTER_HANDLE_ATTRS);
     }
 
-    public static Drawable getRightHandleDrawable(Context context) {
+    public static @Nullable Drawable getRightHandleDrawable(Context context) {
         return getHandleDrawable(context, RIGHT_HANDLE_ATTRS);
     }
 
-    private static Drawable getHandleDrawable(Context context, final int[] attrs) {
+    private static @Nullable Drawable getHandleDrawable(Context context, final int[] attrs) {
         TypedArray a = context.getTheme().obtainStyledAttributes(attrs);
         Drawable drawable = a.getDrawable(0);
         if (drawable == null) {
diff --git a/ui/android/java/src/org/chromium/ui/resources/LayoutResource.java b/ui/android/java/src/org/chromium/ui/resources/LayoutResource.java
index fe521bd2..8d70957 100644
--- a/ui/android/java/src/org/chromium/ui/resources/LayoutResource.java
+++ b/ui/android/java/src/org/chromium/ui/resources/LayoutResource.java
@@ -7,9 +7,11 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.resources.statics.NinePatchData;
 
 /** A resource that provides sizing information for layouts. */
+@NullMarked
 public class LayoutResource {
     private final RectF mPadding;
     private final RectF mBitmapSize;
diff --git a/ui/android/java/src/org/chromium/ui/resources/Resource.java b/ui/android/java/src/org/chromium/ui/resources/Resource.java
index 1247b2f25..6937157 100644
--- a/ui/android/java/src/org/chromium/ui/resources/Resource.java
+++ b/ui/android/java/src/org/chromium/ui/resources/Resource.java
@@ -7,12 +7,15 @@
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.resources.statics.NinePatchData;
 
 /**
  * A basic resource interface that all assets must use to be exposed to the CC layer as
  * UIResourceIds.
  */
+@NullMarked
 public interface Resource {
     /**
      * This can only be called in
@@ -44,6 +47,7 @@
      * cases, this will be null.
      * @return The nine patch data for the bitmap or null.
      */
+    @Nullable
     NinePatchData getNinePatchData();
 
     /**
diff --git a/ui/android/java/src/org/chromium/ui/resources/ResourceFactory.java b/ui/android/java/src/org/chromium/ui/resources/ResourceFactory.java
index 4c3da2b..dd17cb6 100644
--- a/ui/android/java/src/org/chromium/ui/resources/ResourceFactory.java
+++ b/ui/android/java/src/org/chromium/ui/resources/ResourceFactory.java
@@ -9,12 +9,15 @@
 import org.jni_zero.JNINamespace;
 import org.jni_zero.NativeMethods;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.resources.statics.NinePatchData;
 
 /** A utility class for creating native resources. */
 @JNINamespace("ui")
+@NullMarked
 public class ResourceFactory {
-    public static long createBitmapResource(NinePatchData ninePatchData) {
+    public static long createBitmapResource(@Nullable NinePatchData ninePatchData) {
         return ninePatchData == null
                 ? ResourceFactoryJni.get().createBitmapResource()
                 : createNinePatchBitmapResource(
diff --git a/ui/android/java/src/org/chromium/ui/resources/ResourceLoader.java b/ui/android/java/src/org/chromium/ui/resources/ResourceLoader.java
index 323752c..c8881ed 100644
--- a/ui/android/java/src/org/chromium/ui/resources/ResourceLoader.java
+++ b/ui/android/java/src/org/chromium/ui/resources/ResourceLoader.java
@@ -4,7 +4,11 @@
 
 package org.chromium.ui.resources;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
 /** A class responsible for loading {@link Resource}s for the {@link ResourceManager}. */
+@NullMarked
 public abstract class ResourceLoader {
     /**
      * A callback that specifies when a {@link Resource} has been loaded and can be exposed to the
@@ -19,7 +23,8 @@
          * @param resource The {@link Resource} of the resource, or {@code null} if one could
          *                 not be loaded.
          */
-        void onResourceLoaded(@AndroidResourceType int resType, int resId, Resource resource);
+        void onResourceLoaded(
+                @AndroidResourceType int resType, int resId, @Nullable Resource resource);
 
         /**
          * Called when a resource is unregistered (unneeded). This should only be called for
@@ -73,7 +78,7 @@
      * @param resId    The id of the {@link Resource} that loaded or failed.
      * @param resource The {@link Resource}, or {@code null} if the load failed.
      */
-    protected void notifyLoadFinished(int resId, Resource resource) {
+    protected void notifyLoadFinished(int resId, @Nullable Resource resource) {
         if (mCallback != null) mCallback.onResourceLoaded(getResourceType(), resId, resource);
     }
 
diff --git a/ui/android/java/src/org/chromium/ui/resources/ResourceManager.java b/ui/android/java/src/org/chromium/ui/resources/ResourceManager.java
index bdd7d5e7..23ef753f 100644
--- a/ui/android/java/src/org/chromium/ui/resources/ResourceManager.java
+++ b/ui/android/java/src/org/chromium/ui/resources/ResourceManager.java
@@ -13,6 +13,8 @@
 import org.jni_zero.JNINamespace;
 import org.jni_zero.NativeMethods;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.display.DisplayAndroid;
 import org.chromium.ui.resources.ResourceLoader.ResourceLoaderCallback;
@@ -26,6 +28,7 @@
  * This class does not hold any resource state, but passes it directly to native as they are loaded.
  */
 @JNINamespace("ui")
+@NullMarked
 public class ResourceManager implements ResourceLoaderCallback {
     private final SparseArray<ResourceLoader> mResourceLoaders = new SparseArray<ResourceLoader>();
     private final SparseArray<SparseArray<LayoutResource>> mLoadedResources =
@@ -117,14 +120,15 @@
      * @param resId   The id of the Android resource.
      * @return The corresponding {@link LayoutResource}.
      */
-    public LayoutResource getResource(@AndroidResourceType int resType, int resId) {
+    public @Nullable LayoutResource getResource(@AndroidResourceType int resType, int resId) {
         SparseArray<LayoutResource> bucket = mLoadedResources.get(resType);
         return bucket != null ? bucket.get(resId) : null;
     }
 
     @SuppressWarnings("cast")
     @Override
-    public void onResourceLoaded(@AndroidResourceType int resType, int resId, Resource resource) {
+    public void onResourceLoaded(
+            @AndroidResourceType int resType, int resId, @Nullable Resource resource) {
         if (resource == null) return;
         Bitmap bitmap = resource.getBitmap();
         if (bitmap == null) {
diff --git a/ui/android/java/src/org/chromium/ui/resources/async/AsyncPreloadResourceLoader.java b/ui/android/java/src/org/chromium/ui/resources/async/AsyncPreloadResourceLoader.java
index 3895b8f..5bed797 100644
--- a/ui/android/java/src/org/chromium/ui/resources/async/AsyncPreloadResourceLoader.java
+++ b/ui/android/java/src/org/chromium/ui/resources/async/AsyncPreloadResourceLoader.java
@@ -11,12 +11,16 @@
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskRunner;
 import org.chromium.base.task.TaskTraits;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.resources.Resource;
 import org.chromium.ui.resources.ResourceLoader;
 
 import java.util.concurrent.ExecutionException;
 
 /** Handles loading Android resources from disk asynchronously and synchronously. */
+@NullMarked
 public class AsyncPreloadResourceLoader extends ResourceLoader {
     /** Responsible for actually creating a {@link Resource} from a specific resource id. */
     public interface ResourceCreator {
@@ -28,6 +32,7 @@
          * @return      A {@link Resource} instance that represents {@code resId} or {@code null} if
          *              none can be loaded.
          */
+        @Nullable
         Resource create(int resId);
     }
 
@@ -91,7 +96,7 @@
         mOutstandingLoads.put(resId, task);
     }
 
-    private Resource createResource(int resId) {
+    private @Nullable Resource createResource(int resId) {
         try {
             TraceEvent.begin("AsyncPreloadResourceLoader.createResource");
             return mCreator.create(resId);
@@ -100,7 +105,7 @@
         }
     }
 
-    private void registerResource(Resource resource, int resourceId) {
+    private void registerResource(@Nullable Resource resource, int resourceId) {
         notifyLoadFinished(resourceId, resource);
         mOutstandingLoads.remove(resourceId);
     }
@@ -112,13 +117,14 @@
             mResourceId = resourceId;
         }
 
+        @NullUnmarked
         @Override
-        protected Resource doInBackground() {
+        protected @Nullable Resource doInBackground() {
             return createResource(mResourceId);
         }
 
         @Override
-        protected void onPostExecute(Resource resource) {
+        protected void onPostExecute(@Nullable Resource resource) {
             // If we've been removed from the list of outstanding load tasks, don't broadcast the
             // callback.
             if (mOutstandingLoads.get(mResourceId) == null) return;
diff --git a/ui/android/java/src/org/chromium/ui/resources/dynamics/BitmapDynamicResource.java b/ui/android/java/src/org/chromium/ui/resources/dynamics/BitmapDynamicResource.java
index 5e639bd..e1f08bd 100644
--- a/ui/android/java/src/org/chromium/ui/resources/dynamics/BitmapDynamicResource.java
+++ b/ui/android/java/src/org/chromium/ui/resources/dynamics/BitmapDynamicResource.java
@@ -9,13 +9,16 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.ObserverList;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.resources.Resource;
 import org.chromium.ui.resources.ResourceFactory;
 
 /** A basic implementation of {@link DynamicResource} to handle updatable bitmaps. */
+@NullMarked
 public class BitmapDynamicResource implements DynamicResource {
     private final int mResId;
-    private Bitmap mBitmap;
+    private @Nullable Bitmap mBitmap;
     private final Rect mSize = new Rect();
 
     private final ObserverList<Callback<Resource>> mOnResourceReadyObservers = new ObserverList<>();
diff --git a/ui/android/java/src/org/chromium/ui/resources/dynamics/CaptureObserver.java b/ui/android/java/src/org/chromium/ui/resources/dynamics/CaptureObserver.java
index bb6d87f..5ac600c 100644
--- a/ui/android/java/src/org/chromium/ui/resources/dynamics/CaptureObserver.java
+++ b/ui/android/java/src/org/chromium/ui/resources/dynamics/CaptureObserver.java
@@ -7,14 +7,18 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
 /** Observer that's notified before and after a bitmap capture happens. */
+@NullMarked
 public interface CaptureObserver {
     /**
      * Called before the bitmap capture occurs.
      * @param canvas    The {@link Canvas} that will be drawn to.
      * @param dirtyRect The dirty {@link Rect} or {@code null} if the entire area is being redrawn.
      */
-    default void onCaptureStart(Canvas canvas, Rect dirtyRect) {}
+    default void onCaptureStart(Canvas canvas, @Nullable Rect dirtyRect) {}
 
     /** Called after bitmap capture occurs. */
     default void onCaptureEnd() {}
diff --git a/ui/android/java/src/org/chromium/ui/resources/dynamics/CaptureUtils.java b/ui/android/java/src/org/chromium/ui/resources/dynamics/CaptureUtils.java
index 8652fa7..805a445 100644
--- a/ui/android/java/src/org/chromium/ui/resources/dynamics/CaptureUtils.java
+++ b/ui/android/java/src/org/chromium/ui/resources/dynamics/CaptureUtils.java
@@ -9,7 +9,10 @@
 import android.graphics.Rect;
 import android.view.View;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Shared stateless capture utility functions. */
+@NullMarked
 public class CaptureUtils {
     /** Creates a bitmap with the given size. */
     public static Bitmap createBitmap(int width, int height) {
diff --git a/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResource.java b/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResource.java
index 80fe64f7..0038951 100644
--- a/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResource.java
+++ b/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResource.java
@@ -5,6 +5,7 @@
 package org.chromium.ui.resources.dynamics;
 
 import org.chromium.base.Callback;
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.resources.Resource;
 
 /**
@@ -13,6 +14,7 @@
  * {@link DynamicResource} is in charge of tracking when it has changed and should actually be
  * returning a copy of itself.
  */
+@NullMarked
 public interface DynamicResource {
     /**
      * Will be called every render frame to notify the resource. The expectation is that this call
diff --git a/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResourceLoader.java b/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResourceLoader.java
index fba4f0e..1ad8997f 100644
--- a/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResourceLoader.java
+++ b/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResourceLoader.java
@@ -7,6 +7,8 @@
 import android.util.SparseArray;
 
 import org.chromium.base.Callback;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.resources.Resource;
 import org.chromium.ui.resources.ResourceLoader;
 
@@ -16,6 +18,7 @@
  * render frames are happening, and hands the captured {@link org.chromium.ui.resources.Resource}
  * back in our {@link ResourceLoaderCallback}.
  */
+@NullMarked
 public class DynamicResourceLoader extends ResourceLoader {
     /**
      * Adapter for holding a callback and {@link DynamicResource}. The callback must be held so
@@ -86,7 +89,7 @@
      * @return The {@link DynamicResource} corresponding to the provided {@code resId}, or {@code
      *     null} if no matching resource is found.
      */
-    public DynamicResource getResource(int resId) {
+    public @Nullable DynamicResource getResource(int resId) {
         DynamicResourceHolder dynamicResourceHolder = mDynamicResourceHolders.get(resId);
         if (dynamicResourceHolder == null) return null;
         return dynamicResourceHolder.getDynamicResource();
diff --git a/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResourceReadyOnceCallback.java b/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResourceReadyOnceCallback.java
index a11900c..b4a54d0 100644
--- a/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResourceReadyOnceCallback.java
+++ b/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResourceReadyOnceCallback.java
@@ -5,9 +5,11 @@
 package org.chromium.ui.resources.dynamics;
 
 import org.chromium.base.Callback;
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.resources.Resource;
 
 /** A OnceCallback for observing the next {@link ViewResourceAdapter} produced {@link Resource}. */
+@NullMarked
 public class DynamicResourceReadyOnceCallback implements Callback<Resource> {
     private final DynamicResource mDynamicResource;
     private final Callback<Resource> mCallback;
diff --git a/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResourceSnapshot.java b/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResourceSnapshot.java
index 5f053cb..b412058 100644
--- a/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResourceSnapshot.java
+++ b/ui/android/java/src/org/chromium/ui/resources/dynamics/DynamicResourceSnapshot.java
@@ -7,10 +7,13 @@
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.resources.Resource;
 import org.chromium.ui.resources.statics.NinePatchData;
 
 /** The current state of a dynamic resource. */
+@NullMarked
 public class DynamicResourceSnapshot implements Resource {
     private final Bitmap mBitmap;
     private final boolean mShouldRemoveResourceOnNullBitmap;
@@ -44,7 +47,7 @@
     }
 
     @Override
-    public NinePatchData getNinePatchData() {
+    public @Nullable NinePatchData getNinePatchData() {
         return null;
     }
 
diff --git a/ui/android/java/src/org/chromium/ui/resources/dynamics/SoftwareDraw.java b/ui/android/java/src/org/chromium/ui/resources/dynamics/SoftwareDraw.java
index 04aa3c4c..e4ee598 100644
--- a/ui/android/java/src/org/chromium/ui/resources/dynamics/SoftwareDraw.java
+++ b/ui/android/java/src/org/chromium/ui/resources/dynamics/SoftwareDraw.java
@@ -12,10 +12,13 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.TraceEvent;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /** Simple bitmap capture approach simply calling {@link View#draw(Canvas)}. */
+@NullMarked
 public class SoftwareDraw implements ViewResourceAdapter.CaptureMechanism {
-    private Bitmap mBitmap;
+    private @Nullable Bitmap mBitmap;
 
     @Override
     public boolean shouldRemoveResourceOnNullBitmap() {
diff --git a/ui/android/java/src/org/chromium/ui/resources/dynamics/ViewResourceAdapter.java b/ui/android/java/src/org/chromium/ui/resources/dynamics/ViewResourceAdapter.java
index 6f8b4345..80d59d36 100644
--- a/ui/android/java/src/org/chromium/ui/resources/dynamics/ViewResourceAdapter.java
+++ b/ui/android/java/src/org/chromium/ui/resources/dynamics/ViewResourceAdapter.java
@@ -17,6 +17,8 @@
 import org.chromium.base.ObserverList;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.TraceEvent;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.resources.Resource;
 import org.chromium.ui.resources.ResourceFactory;
 
@@ -26,6 +28,7 @@
  * {@link View} are invalidated.  For {@link ViewGroup}s the easiest way to do this is to override
  * {@link ViewGroup#invalidateChildInParent(int[], Rect)}.
  */
+@NullMarked
 public class ViewResourceAdapter
         implements DynamicResource, OnLayoutChangeListener, CaptureObserver {
     /** Abstraction around the mechanism for actually capturing bitmaps.  */
@@ -183,7 +186,7 @@
      * @param dirtyRect The region to invalidate, or {@code null} if the entire {@code Bitmap}
      *                  should be redrawn.
      */
-    public void invalidate(Rect dirtyRect) {
+    public void invalidate(@Nullable Rect dirtyRect) {
         if (dirtyRect == null) {
             mDirtyRect.set(0, 0, mView.getWidth(), mView.getHeight());
         } else {
diff --git a/ui/android/java/src/org/chromium/ui/resources/dynamics/ViewResourceInflater.java b/ui/android/java/src/org/chromium/ui/resources/dynamics/ViewResourceInflater.java
index 3f6a303..88674a6 100644
--- a/ui/android/java/src/org/chromium/ui/resources/dynamics/ViewResourceInflater.java
+++ b/ui/android/java/src/org/chromium/ui/resources/dynamics/ViewResourceInflater.java
@@ -10,6 +10,10 @@
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
+
 /**
  * ViewResourceInflater is a utility class that facilitates using an Android View as a dynamic
  * resource, which can be later used as a compositor layer. This class assumes that the View
@@ -32,6 +36,7 @@
  * It's possible to specify custom size constraints by overriding the methods
  * {@link #getWidthMeasureSpec()} and {@link #getHeightMeasureSpec()}.
  */
+@NullMarked
 public class ViewResourceInflater {
 
     /** The id of the XML Layout that describes the View. */
@@ -41,18 +46,19 @@
     private int mViewId;
 
     /** The Context used to inflate the View. */
-    private Context mContext;
+    private @Nullable Context mContext;
 
     /** The ViewGroup container used to inflate the View. */
     private ViewGroup mContainer;
 
     /** The DynamicResourceLoader used to manage resources generated dynamically. */
-    private DynamicResourceLoader mResourceLoader;
+    private @Nullable DynamicResourceLoader mResourceLoader;
 
     /** The ViewResourceAdapter used to capture snapshots of the View. */
-    private ViewResourceAdapter mResourceAdapter;
+    private @Nullable ViewResourceAdapter mResourceAdapter;
 
     /** The inflated View. */
+    @SuppressWarnings("NullAway.Init")
     private View mView;
 
     /** Whether the View needs a layout update. */
@@ -65,7 +71,7 @@
     private boolean mIsAttached;
 
     /** The ViewInflaterOnDrawListener used to track changes in the View when attached. */
-    private ViewInflaterOnDrawListener mOnDrawListener;
+    private @Nullable ViewInflaterOnDrawListener mOnDrawListener;
 
     /** The invalid ID. */
     private static final int INVALID_ID = -1;
@@ -152,6 +158,7 @@
     }
 
     /** Destroy the instance. */
+    @NullUnmarked
     public void destroy() {
         if (mView == null) return;
 
@@ -257,7 +264,7 @@
     /**
      * @return The Context used to inflate the View.
      */
-    protected Context getContext() {
+    protected @Nullable Context getContext() {
         return mContext;
     }
 
diff --git a/ui/android/java/src/org/chromium/ui/resources/statics/NinePatchData.java b/ui/android/java/src/org/chromium/ui/resources/statics/NinePatchData.java
index 1f49e35..c9db346 100644
--- a/ui/android/java/src/org/chromium/ui/resources/statics/NinePatchData.java
+++ b/ui/android/java/src/org/chromium/ui/resources/statics/NinePatchData.java
@@ -8,11 +8,15 @@
 import android.graphics.NinePatch;
 import android.graphics.Rect;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 
 /** A helper class to decode and expose relevant 9-patch data from a Bitmap. */
+@NullMarked
 public class NinePatchData {
     private final int mWidth;
     private final int mHeight;
@@ -76,7 +80,7 @@
      *               encoded in {@code bitmap} or {@code null} if the {@link Bitmap} wasn't a
      *               9-patch.
      */
-    public static NinePatchData create(Bitmap bitmap) {
+    public static @Nullable NinePatchData create(Bitmap bitmap) {
         if (bitmap == null) return null;
 
         try {
diff --git a/ui/android/java/src/org/chromium/ui/resources/statics/StaticResource.java b/ui/android/java/src/org/chromium/ui/resources/statics/StaticResource.java
index 9d5a834..66f7166a 100644
--- a/ui/android/java/src/org/chromium/ui/resources/statics/StaticResource.java
+++ b/ui/android/java/src/org/chromium/ui/resources/statics/StaticResource.java
@@ -12,6 +12,9 @@
 import android.graphics.drawable.Drawable;
 
 import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.resources.Resource;
 import org.chromium.ui.resources.ResourceFactory;
 
@@ -19,9 +22,10 @@
  * A representation of a static resource and all related information for drawing it.  In general
  * this means a {@link Bitmap} and a potential {@link NinePatchData}.
  */
+@NullMarked
 public class StaticResource implements Resource {
-    private Bitmap mBitmap;
-    private final NinePatchData mNinePatchData;
+    private @Nullable Bitmap mBitmap;
+    private final @Nullable NinePatchData mNinePatchData;
     private final Rect mBitmapSize;
 
     /**
@@ -36,7 +40,7 @@
     }
 
     @Override
-    public NinePatchData getNinePatchData() {
+    public @Nullable NinePatchData getNinePatchData() {
         return mNinePatchData;
     }
 
@@ -77,7 +81,7 @@
      * @return The loaded {@link StaticResource} or {@code null} if the resource could not be
      *     loaded.
      */
-    public static StaticResource create(
+    public static @Nullable StaticResource create(
             Resources resources, int resId, int fitWidth, int fitHeight) {
         if (resId <= 0) return null;
         Bitmap bitmap = decodeBitmap(resources, resId, fitWidth, fitHeight);
@@ -87,7 +91,7 @@
         return new StaticResource(bitmap);
     }
 
-    private static Bitmap decodeBitmap(
+    private static @Nullable Bitmap decodeBitmap(
             Resources resources, int resId, int fitWidth, int fitHeight) {
         BitmapFactory.Options options = createOptions(resources, resId, fitWidth, fitHeight);
         options.inPreferredConfig = Bitmap.Config.ARGB_8888;
@@ -105,7 +109,8 @@
         return convertedBitmap;
     }
 
-    private static Bitmap decodeDrawable(
+    @NullUnmarked
+    private static @Nullable Bitmap decodeDrawable(
             Resources resources, int resId, int fitWidth, int fitHeight) {
         try {
             Drawable drawable = ApiCompatibilityUtils.getDrawable(resources, resId);
diff --git a/ui/android/java/src/org/chromium/ui/resources/statics/StaticResourceLoader.java b/ui/android/java/src/org/chromium/ui/resources/statics/StaticResourceLoader.java
index 0ff2e663..4341edc4 100644
--- a/ui/android/java/src/org/chromium/ui/resources/statics/StaticResourceLoader.java
+++ b/ui/android/java/src/org/chromium/ui/resources/statics/StaticResourceLoader.java
@@ -6,10 +6,13 @@
 
 import android.content.res.Resources;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.resources.Resource;
 import org.chromium.ui.resources.async.AsyncPreloadResourceLoader;
 
 /** Handles loading Android resources from disk asynchronously and synchronously. */
+@NullMarked
 public class StaticResourceLoader extends AsyncPreloadResourceLoader {
     /**
      * Creates a {@link StaticResourceLoader}.
@@ -26,7 +29,7 @@
                 callback,
                 new ResourceCreator() {
                     @Override
-                    public Resource create(int resId) {
+                    public @Nullable Resource create(int resId) {
                         return StaticResource.create(resources, resId, 0, 0);
                     }
                 });
diff --git a/ui/android/java/src/org/chromium/ui/resources/system/SystemResourceLoader.java b/ui/android/java/src/org/chromium/ui/resources/system/SystemResourceLoader.java
index 735c394f..bfbc7a79 100644
--- a/ui/android/java/src/org/chromium/ui/resources/system/SystemResourceLoader.java
+++ b/ui/android/java/src/org/chromium/ui/resources/system/SystemResourceLoader.java
@@ -10,12 +10,15 @@
 import android.graphics.Paint.Style;
 import android.graphics.RectF;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.resources.Resource;
 import org.chromium.ui.resources.SystemUIResourceType;
 import org.chromium.ui.resources.async.AsyncPreloadResourceLoader;
 import org.chromium.ui.resources.statics.StaticResource;
 
 /** Handles loading system specific resources like overscroll and edge glows. */
+@NullMarked
 public class SystemResourceLoader extends AsyncPreloadResourceLoader {
     private static final float SIN_PI_OVER_6 = 0.5f;
     private static final float COS_PI_OVER_6 = 0.866f;
@@ -34,13 +37,13 @@
                 callback,
                 new ResourceCreator() {
                     @Override
-                    public Resource create(int resId) {
+                    public @Nullable Resource create(int resId) {
                         return createResource(minScreenSideLengthPx, resId);
                     }
                 });
     }
 
-    private static Resource createResource(int minScreenSideLengthPx, int resId) {
+    private static @Nullable Resource createResource(int minScreenSideLengthPx, int resId) {
         switch (resId) {
             case SystemUIResourceType.OVERSCROLL_GLOW:
                 return createOverscrollGlowBitmap(minScreenSideLengthPx);
diff --git a/ui/android/java/src/org/chromium/ui/text/ChromeClickableSpan.java b/ui/android/java/src/org/chromium/ui/text/ChromeClickableSpan.java
index b714a80..dd6417e 100644
--- a/ui/android/java/src/org/chromium/ui/text/ChromeClickableSpan.java
+++ b/ui/android/java/src/org/chromium/ui/text/ChromeClickableSpan.java
@@ -13,10 +13,12 @@
 import androidx.annotation.ColorRes;
 
 import org.chromium.base.Callback;
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.R;
 import org.chromium.ui.util.AttrUtils;
 
 /** Shows a blue clickable link with underlines turned on. */
+@NullMarked
 public class ChromeClickableSpan extends ClickableSpan {
     private final int mColor;
     private final Callback<View> mOnClick;
diff --git a/ui/android/java/src/org/chromium/ui/text/DownloadableFontTextAppearanceSpan.java b/ui/android/java/src/org/chromium/ui/text/DownloadableFontTextAppearanceSpan.java
index df2f3020..f5c87dda 100644
--- a/ui/android/java/src/org/chromium/ui/text/DownloadableFontTextAppearanceSpan.java
+++ b/ui/android/java/src/org/chromium/ui/text/DownloadableFontTextAppearanceSpan.java
@@ -15,11 +15,14 @@
 import androidx.annotation.StyleRes;
 import androidx.core.content.res.ResourcesCompat;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.R;
 
 /** {@link TextAppearanceSpan} that supports downloadable fonts, e.g. google sans. */
+@NullMarked
 public class DownloadableFontTextAppearanceSpan extends TextAppearanceSpan {
-    private final Typeface mTypeface;
+    private final @Nullable Typeface mTypeface;
 
     public DownloadableFontTextAppearanceSpan(Context context, int appearance) {
         super(context, appearance);
diff --git a/ui/android/java/src/org/chromium/ui/text/EmptyTextWatcher.java b/ui/android/java/src/org/chromium/ui/text/EmptyTextWatcher.java
index ac42dde0..912e986 100644
--- a/ui/android/java/src/org/chromium/ui/text/EmptyTextWatcher.java
+++ b/ui/android/java/src/org/chromium/ui/text/EmptyTextWatcher.java
@@ -7,7 +7,10 @@
 import android.text.Editable;
 import android.text.TextWatcher;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Simple no-op default interface that allows subclasses to only implement methods as needed. */
+@NullMarked
 public interface EmptyTextWatcher extends TextWatcher {
     @Override
     default void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
diff --git a/ui/android/java/src/org/chromium/ui/text/SpanApplier.java b/ui/android/java/src/org/chromium/ui/text/SpanApplier.java
index ee51481..d5b009a 100644
--- a/ui/android/java/src/org/chromium/ui/text/SpanApplier.java
+++ b/ui/android/java/src/org/chromium/ui/text/SpanApplier.java
@@ -6,7 +6,8 @@
 
 import android.text.SpannableString;
 
-import androidx.annotation.Nullable;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 import java.util.Arrays;
 
@@ -22,6 +23,7 @@
  *   SpannableString output = SpanApplier.applySpans(input,
  *           new Span("<tos>", "</tos>", tosSpan), new Span("<pn>", "</pn>", privacySpan));
  */
+@NullMarked
 public class SpanApplier {
     private static final int INVALID_INDEX = -1;
 
@@ -29,7 +31,7 @@
     public static final class SpanInfo implements Comparable<SpanInfo> {
         final String mStartTag;
         final String mEndTag;
-        final @Nullable Object[] mSpans;
+        final Object @Nullable [] mSpans;
         int mStartTagIndex;
         int mEndTagIndex;
 
diff --git a/ui/android/java/src/org/chromium/ui/util/AccessibilityUtil.java b/ui/android/java/src/org/chromium/ui/util/AccessibilityUtil.java
index 8204f2b1..8817cbd 100644
--- a/ui/android/java/src/org/chromium/ui/util/AccessibilityUtil.java
+++ b/ui/android/java/src/org/chromium/ui/util/AccessibilityUtil.java
@@ -4,14 +4,15 @@
 
 package org.chromium.ui.util;
 
-import androidx.annotation.Nullable;
-
 import org.chromium.base.ObserverList;
 import org.chromium.base.ThreadUtils;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.accessibility.AccessibilityState;
 import org.chromium.ui.accessibility.AccessibilityState.State;
 
 /** Exposes information about the current accessibility state. */
+@NullMarked
 public class AccessibilityUtil implements AccessibilityState.Listener {
     /** An observer to be notified of accessibility status changes. */
     @Deprecated
@@ -24,7 +25,7 @@
         void onAccessibilityModeChanged(boolean enabled);
     }
 
-    private ObserverList<Observer> mObservers;
+    private @Nullable ObserverList<Observer> mObservers;
 
     protected AccessibilityUtil() {}
 
@@ -54,7 +55,7 @@
 
     @Override
     public void onAccessibilityStateChanged(
-            State oldAccessibilityState, State newAccessibilityState) {
+            @Nullable State oldAccessibilityState, State newAccessibilityState) {
         notifyModeChange(AccessibilityState.isAccessibilityEnabled());
     }
 
diff --git a/ui/android/java/src/org/chromium/ui/util/AttrUtils.java b/ui/android/java/src/org/chromium/ui/util/AttrUtils.java
index 602cb7d6..3a938d1 100644
--- a/ui/android/java/src/org/chromium/ui/util/AttrUtils.java
+++ b/ui/android/java/src/org/chromium/ui/util/AttrUtils.java
@@ -11,7 +11,10 @@
 import androidx.annotation.ColorInt;
 import androidx.annotation.ColorRes;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Helper functions for working with attributes. */
+@NullMarked
 public final class AttrUtils {
     /** Private constructor to stop instantiation. */
     private AttrUtils() {}
diff --git a/ui/android/java/src/org/chromium/ui/util/ColorBlendAnimationFactory.java b/ui/android/java/src/org/chromium/ui/util/ColorBlendAnimationFactory.java
index 6ef11987..fd0b931 100644
--- a/ui/android/java/src/org/chromium/ui/util/ColorBlendAnimationFactory.java
+++ b/ui/android/java/src/org/chromium/ui/util/ColorBlendAnimationFactory.java
@@ -11,11 +11,13 @@
 
 import androidx.annotation.ColorInt;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.interpolators.Interpolators;
 
 import java.util.function.Consumer;
 
 /** Factory class for creating animations for blending two colors together. */
+@NullMarked
 public class ColorBlendAnimationFactory {
 
     /**
diff --git a/ui/android/java/src/org/chromium/ui/util/ColorUtils.java b/ui/android/java/src/org/chromium/ui/util/ColorUtils.java
index 2942309..3c4248e 100644
--- a/ui/android/java/src/org/chromium/ui/util/ColorUtils.java
+++ b/ui/android/java/src/org/chromium/ui/util/ColorUtils.java
@@ -13,8 +13,10 @@
 import androidx.annotation.IntRange;
 
 import org.chromium.base.MathUtils;
+import org.chromium.build.annotations.NullMarked;
 
 /** Helper functions for working with colors. */
+@NullMarked
 public class ColorUtils {
     // Value used by ui::OptionalSkColorToJavaColor() to represent invalid color.
     public static final long INVALID_COLOR = ((long) Integer.MAX_VALUE) + 1;
diff --git a/ui/android/java/src/org/chromium/ui/util/StyleUtils.java b/ui/android/java/src/org/chromium/ui/util/StyleUtils.java
index 96885440..7d3bb23c 100644
--- a/ui/android/java/src/org/chromium/ui/util/StyleUtils.java
+++ b/ui/android/java/src/org/chromium/ui/util/StyleUtils.java
@@ -13,9 +13,11 @@
 import androidx.annotation.StyleableRes;
 import androidx.core.content.res.ResourcesCompat;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.R;
 
 /** Helper functions for working with styles. */
+@NullMarked
 public class StyleUtils {
     private static final String TAG = "StyleUtils";
     private static final int INVALID_RESOURCE_ID = -1;
diff --git a/ui/android/java/src/org/chromium/ui/util/TokenHolder.java b/ui/android/java/src/org/chromium/ui/util/TokenHolder.java
index e856e1d..597d785 100644
--- a/ui/android/java/src/org/chromium/ui/util/TokenHolder.java
+++ b/ui/android/java/src/org/chromium/ui/util/TokenHolder.java
@@ -4,6 +4,8 @@
 
 package org.chromium.ui.util;
 
+import org.chromium.build.annotations.NullMarked;
+
 import java.util.HashSet;
 import java.util.Set;
 
@@ -11,6 +13,7 @@
  * Helper class for holding tokens, useful when multiple entities need to manipulate the same
  * boolean state, e.g. visibility of a view.
  */
+@NullMarked
 public class TokenHolder {
     /** An invalid token; this can be used to indicate no token is being held. */
     public static final int INVALID_TOKEN = -1;
diff --git a/ui/android/java/src/org/chromium/ui/util/ValueUtils.java b/ui/android/java/src/org/chromium/ui/util/ValueUtils.java
index 861bd70..ae2f416 100644
--- a/ui/android/java/src/org/chromium/ui/util/ValueUtils.java
+++ b/ui/android/java/src/org/chromium/ui/util/ValueUtils.java
@@ -9,7 +9,10 @@
 
 import androidx.annotation.DimenRes;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Helper functions for working with {@TypedValue}s. */
+@NullMarked
 public final class ValueUtils {
 
     /** Private constructor to stop instantiation. */
diff --git a/ui/android/java/src/org/chromium/ui/util/WindowInsetsUtils.java b/ui/android/java/src/org/chromium/ui/util/WindowInsetsUtils.java
index 44ba1d2..8c32485a 100644
--- a/ui/android/java/src/org/chromium/ui/util/WindowInsetsUtils.java
+++ b/ui/android/java/src/org/chromium/ui/util/WindowInsetsUtils.java
@@ -10,17 +10,19 @@
 import android.util.Size;
 import android.view.WindowInsets;
 
-import androidx.annotation.NonNull;
 import androidx.core.graphics.Insets;
 import androidx.core.view.WindowInsetsCompat.Type.InsetsType;
 
 import org.chromium.base.Callback;
 import org.chromium.base.Log;
 import org.chromium.base.ResettersForTesting;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 import java.util.List;
 
 /** Helper functions for working with WindowInsets and Rects. */
+@NullMarked
 public final class WindowInsetsUtils {
     private static final String TAG = "WindowInsetsUtils";
 
@@ -30,8 +32,8 @@
     private static boolean sGetFrameMethodNotFound;
     private static boolean sGetBoundingRectsMethodNotFound;
 
-    private static Size sFrameForTesting;
-    private static Rect sWidestUnoccludedRectForTesting;
+    private static @Nullable Size sFrameForTesting;
+    private static @Nullable Rect sWidestUnoccludedRectForTesting;
 
     /** Private constructor to stop instantiation. */
     private WindowInsetsUtils() {}
@@ -67,7 +69,7 @@
      * @return Rect that the insets represent in the windowRect. Empty rect if insets represent more
      *     than one edge.
      */
-    public static @NonNull Rect toRectInWindow(@NonNull Rect windowRect, @NonNull Insets insets) {
+    public static Rect toRectInWindow(Rect windowRect, Insets insets) {
         int sides = 0;
         Rect res = new Rect(windowRect);
 
@@ -109,8 +111,7 @@
      * @param blockedRects Areas within the regionRect that are blocked.
      * @return The widest Rect seen in the regionRect that's not blocked by any blockedRects.
      */
-    public static @NonNull Rect getWidestUnoccludedRect(
-            @NonNull Rect regionRect, List<Rect> blockedRects) {
+    public static Rect getWidestUnoccludedRect(Rect regionRect, List<Rect> blockedRects) {
         if (sWidestUnoccludedRectForTesting != null) return sWidestUnoccludedRectForTesting;
         if (regionRect.isEmpty()) return regionRect;
 
@@ -131,7 +132,7 @@
 
     /** See {@link WindowInsets#getFrame()} for details. */
     @SuppressWarnings("NewApi")
-    public static Size getFrameFromInsets(WindowInsets windowInsets) {
+    public static Size getFrameFromInsets(@Nullable WindowInsets windowInsets) {
         if (sFrameForTesting != null) return sFrameForTesting;
 
         // This invocation is wrapped in a try-catch block to allow backporting of the #getFrame()
@@ -150,7 +151,7 @@
     /** See {@link WindowInsets#getBoundingRects(int)} for details. */
     @SuppressWarnings("NewApi")
     public static List<Rect> getBoundingRectsFromInsets(
-            WindowInsets windowInsets, @InsetsType int insetType) {
+            @Nullable WindowInsets windowInsets, @InsetsType int insetType) {
         // This invocation is wrapped in a try-catch block to allow backporting of the
         // #getBoundingRects() API on pre-V devices. On pre-V devices not supporting this API, a
         // default value will be cached on the first failure and returned subsequently.
diff --git a/ui/android/java/src/org/chromium/ui/widget/AnchoredPopupWindow.java b/ui/android/java/src/org/chromium/ui/widget/AnchoredPopupWindow.java
index 8e1bc5e..2bbbb48 100644
--- a/ui/android/java/src/org/chromium/ui/widget/AnchoredPopupWindow.java
+++ b/ui/android/java/src/org/chromium/ui/widget/AnchoredPopupWindow.java
@@ -22,12 +22,13 @@
 import android.widget.PopupWindow.OnDismissListener;
 
 import androidx.annotation.IntDef;
-import androidx.annotation.Nullable;
 import androidx.annotation.StyleRes;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.ObserverList;
 import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.R;
 import org.chromium.ui.base.LocalizationUtils;
 
@@ -38,6 +39,7 @@
  * UI component that handles showing a {@link PopupWindow}. Positioning this popup happens through a
  * {@link RectProvider} provided during construction.
  */
+@NullMarked
 public class AnchoredPopupWindow implements OnTouchListener, RectProvider.Observer {
     private static final int MINIMAL_POPUP_HEIGHT_DIP = 50; // 48dp touch target plus 1dp margin.
     private static final int MINIMAL_POPUP_WIDTH_DIP = 50; // 48dp touch target plus 1dp margin.
@@ -207,8 +209,8 @@
     // Pass through for the internal PopupWindow.  This class needs to intercept these for API
     // purposes, but they are still useful to callers.
     private ObserverList<OnDismissListener> mDismissListeners = new ObserverList<>();
-    private OnTouchListener mTouchListener;
-    private LayoutObserver mLayoutObserver;
+    private @Nullable OnTouchListener mTouchListener;
+    private @Nullable LayoutObserver mLayoutObserver;
 
     /** The margin to add to the popup so it doesn't bump against the edges of the screen. */
     private int mMarginPx;
diff --git a/ui/android/java/src/org/chromium/ui/widget/ButtonCompat.java b/ui/android/java/src/org/chromium/ui/widget/ButtonCompat.java
index 6472a02..9b6c356 100644
--- a/ui/android/java/src/org/chromium/ui/widget/ButtonCompat.java
+++ b/ui/android/java/src/org/chromium/ui/widget/ButtonCompat.java
@@ -16,6 +16,8 @@
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.appcompat.widget.AppCompatButton;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.R;
 
 /**
@@ -39,6 +41,7 @@
  *
  * See {@link R.styleable#ButtonCompat ButtonCompat Attributes}.
  */
+@NullMarked
 public class ButtonCompat extends AppCompatButton {
     private RippleBackgroundHelper mRippleBackgroundHelper;
 
@@ -57,7 +60,8 @@
         this(context, attrs, R.style.FilledButtonThemeOverlay);
     }
 
-    private ButtonCompat(Context context, AttributeSet attrs, @StyleRes int themeOverlay) {
+    private ButtonCompat(
+            Context context, @Nullable AttributeSet attrs, @StyleRes int themeOverlay) {
         super(new ContextThemeWrapper(context, themeOverlay), attrs, android.R.attr.buttonStyle);
 
         TypedArray a =
diff --git a/ui/android/java/src/org/chromium/ui/widget/CheckableImageView.java b/ui/android/java/src/org/chromium/ui/widget/CheckableImageView.java
index 0c450758..400ac77b 100644
--- a/ui/android/java/src/org/chromium/ui/widget/CheckableImageView.java
+++ b/ui/android/java/src/org/chromium/ui/widget/CheckableImageView.java
@@ -9,12 +9,14 @@
 import android.util.AttributeSet;
 import android.widget.Checkable;
 
-import androidx.annotation.Nullable;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * ImageView that has checkable state. Checkable state can be used with StateListDrawable and
  * AnimatedStateListDrawable to dynamically change the appearance of this widget.
  */
+@NullMarked
 public class CheckableImageView extends ChromeImageView implements Checkable {
     private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
 
diff --git a/ui/android/java/src/org/chromium/ui/widget/ChromeBulletSpan.java b/ui/android/java/src/org/chromium/ui/widget/ChromeBulletSpan.java
index 95a7d006..ba7c0b3 100644
--- a/ui/android/java/src/org/chromium/ui/widget/ChromeBulletSpan.java
+++ b/ui/android/java/src/org/chromium/ui/widget/ChromeBulletSpan.java
@@ -10,12 +10,15 @@
 import android.text.Layout;
 import android.text.style.BulletSpan;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.R;
 
 /**
  * A wrapper around Android's BulletSpan that provides default styling and adjusts the bullet
  * positioning to prevent it from being cut off.
  */
+@NullMarked
 public class ChromeBulletSpan extends BulletSpan {
     private int mXOffset;
 
@@ -42,7 +45,7 @@
             int start,
             int end,
             boolean first,
-            Layout l) {
+            @Nullable Layout l) {
         // Android cuts off the bullet points. Adjust the x-position so that the bullets aren't
         // cut off.
         super.drawLeadingMargin(
diff --git a/ui/android/java/src/org/chromium/ui/widget/ChromeImageButton.java b/ui/android/java/src/org/chromium/ui/widget/ChromeImageButton.java
index ec7be2ad..21103bd 100644
--- a/ui/android/java/src/org/chromium/ui/widget/ChromeImageButton.java
+++ b/ui/android/java/src/org/chromium/ui/widget/ChromeImageButton.java
@@ -10,11 +10,14 @@
 
 import androidx.appcompat.widget.AppCompatImageButton;
 
+import org.chromium.build.annotations.NullMarked;
+
 // TODO(crbug.com/40883889): See if we still need this class.
 /**
  * A subclass of AppCompatImageButton to add workarounds for bugs in Android Framework and Support
  * Library.
  */
+@NullMarked
 public class ChromeImageButton extends AppCompatImageButton {
     public ChromeImageButton(Context context) {
         super(context);
diff --git a/ui/android/java/src/org/chromium/ui/widget/ChromeImageView.java b/ui/android/java/src/org/chromium/ui/widget/ChromeImageView.java
index 6aa4316..b12ee20 100644
--- a/ui/android/java/src/org/chromium/ui/widget/ChromeImageView.java
+++ b/ui/android/java/src/org/chromium/ui/widget/ChromeImageView.java
@@ -11,16 +11,18 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 
-import androidx.annotation.Nullable;
 import androidx.appcompat.widget.AppCompatImageView;
 
 import org.chromium.base.Log;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 // TODO(crbug.com/40883889): This class has no use now, so we can get rid of it.
 /**
  * A subclass of AppCompatImageView to add workarounds for bugs in Android Framework and Support
  * Library.
  */
+@NullMarked
 public class ChromeImageView extends AppCompatImageView {
     private static final String TAG = "CIV";
 
diff --git a/ui/android/java/src/org/chromium/ui/widget/LoadingView.java b/ui/android/java/src/org/chromium/ui/widget/LoadingView.java
index 5eaff096..6aa41fb5 100644
--- a/ui/android/java/src/org/chromium/ui/widget/LoadingView.java
+++ b/ui/android/java/src/org/chromium/ui/widget/LoadingView.java
@@ -13,12 +13,14 @@
 import android.widget.ProgressBar;
 
 import org.chromium.base.ResettersForTesting;
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.interpolators.Interpolators;
 
 import java.util.ArrayList;
 import java.util.List;
 
 /** A {@link ProgressBar} that understands the hiding/showing policy defined in Material Design. */
+@NullMarked
 public class LoadingView extends ProgressBar {
     private static final int LOADING_ANIMATION_DELAY_MS = 500;
     private static final int MINIMUM_ANIMATION_SHOW_TIME_MS = 500;
diff --git a/ui/android/java/src/org/chromium/ui/widget/OptimizedFrameLayout.java b/ui/android/java/src/org/chromium/ui/widget/OptimizedFrameLayout.java
index 6b402e1..82d3abb7 100644
--- a/ui/android/java/src/org/chromium/ui/widget/OptimizedFrameLayout.java
+++ b/ui/android/java/src/org/chromium/ui/widget/OptimizedFrameLayout.java
@@ -11,6 +11,8 @@
 import android.view.View;
 import android.widget.FrameLayout;
 
+import org.chromium.build.annotations.NullMarked;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -18,6 +20,7 @@
  * This class overrides {@link FrameLayout#onMeasure} so that it does not call onMeasure on its
  * children multiple times during the same {@link FrameLayout#onMeasure} call.
  */
+@NullMarked
 public class OptimizedFrameLayout extends FrameLayout {
     private static class MeasurementState {
         final View mView;
diff --git a/ui/android/java/src/org/chromium/ui/widget/RectProvider.java b/ui/android/java/src/org/chromium/ui/widget/RectProvider.java
index aecc016..5b787685 100644
--- a/ui/android/java/src/org/chromium/ui/widget/RectProvider.java
+++ b/ui/android/java/src/org/chromium/ui/widget/RectProvider.java
@@ -6,7 +6,11 @@
 
 import android.graphics.Rect;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
 /** Provides a {@link Rect} object that represents a position in screen space. */
+@NullMarked
 public class RectProvider {
     /** An observer to be notified of changes to the {@Rect} position. */
     public interface Observer {
@@ -26,7 +30,7 @@
      */
     protected final Rect mRect = new Rect();
 
-    private Observer mObserver;
+    private @Nullable Observer mObserver;
 
     /** Creates an instance of a {@link RectProvider}. */
     public RectProvider() {}
diff --git a/ui/android/java/src/org/chromium/ui/widget/RippleBackgroundHelper.java b/ui/android/java/src/org/chromium/ui/widget/RippleBackgroundHelper.java
index b10ff90..76c1a364 100644
--- a/ui/android/java/src/org/chromium/ui/widget/RippleBackgroundHelper.java
+++ b/ui/android/java/src/org/chromium/ui/widget/RippleBackgroundHelper.java
@@ -17,17 +17,19 @@
 import androidx.annotation.ColorInt;
 import androidx.annotation.ColorRes;
 import androidx.annotation.DimenRes;
-import androidx.annotation.Nullable;
 import androidx.annotation.Px;
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.core.graphics.ColorUtils;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.R;
 
 /**
  * A helper class to create and maintain a background drawable with customized background color,
  * ripple color, and corner radius.
  */
+@NullMarked
 public class RippleBackgroundHelper {
     private static final int[] STATE_SET_PRESSED = {android.R.attr.state_pressed};
     private static final int[] STATE_SET_SELECTED = {android.R.attr.state_selected};
@@ -40,9 +42,13 @@
     private @Nullable ColorStateList mBackgroundColorList;
     private @Nullable ColorStateList mStateLayerColorList;
 
+    @SuppressWarnings("NullAway.Init")
     private GradientDrawable mBackgroundGradient;
+
+    @SuppressWarnings("NullAway.Init")
     private GradientDrawable mStateLayerGradient;
-    private LayerDrawable mBackgroundLayerDrawable;
+
+    private @Nullable LayerDrawable mBackgroundLayerDrawable;
 
     /**
      * @param view The {@link View} on which background will be applied.
diff --git a/ui/android/java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java b/ui/android/java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java
index e6f6acaa..1898cbe 100644
--- a/ui/android/java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java
+++ b/ui/android/java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java
@@ -20,6 +20,9 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.accessibility.AccessibilityState;
 
 /**
@@ -28,9 +31,10 @@
  * do nothing if it's a touch event directly on a ClickableSpan. Otherwise if there's only one
  * ClickableSpan, we activate it. If there's more than one, we pop up a PopupMenu to disambiguate.
  */
+@NullMarked
 public class TextViewWithClickableSpans extends TextViewWithLeading
         implements View.OnLongClickListener {
-    private PopupMenu mDisambiguationMenu;
+    private @Nullable PopupMenu mDisambiguationMenu;
 
     public TextViewWithClickableSpans(Context context) {
         super(context);
@@ -63,14 +67,14 @@
     }
 
     @Override
-    public final void setOnLongClickListener(View.OnLongClickListener listener) {
+    public final void setOnLongClickListener(View.@Nullable OnLongClickListener listener) {
         // Ensure that no one changes the long click listener to anything but this view.
         assert listener == this || listener == null;
         super.setOnLongClickListener(listener);
     }
 
     @Override
-    public boolean performAccessibilityAction(int action, Bundle arguments) {
+    public boolean performAccessibilityAction(int action, @Nullable Bundle arguments) {
         // BrailleBack will generate an accessibility click event directly
         // on this view, make sure we handle that correctly.
         if (action == AccessibilityNodeInfo.ACTION_CLICK) {
@@ -102,6 +106,7 @@
      * @param event The motion event to compare the spans against.
      * @return Whether the motion event intersected any clickable spans.
      */
+    @NullUnmarked
     protected boolean touchIntersectsAnyClickableSpans(MotionEvent event) {
         // This logic is borrowed from android.text.method.LinkMovementMethod.
         //
@@ -132,7 +137,7 @@
 
     /** Returns the ClickableSpans in this TextView's text. */
     @VisibleForTesting
-    public ClickableSpan[] getClickableSpans() {
+    public ClickableSpan @Nullable [] getClickableSpans() {
         CharSequence text = getText();
         if (!(text instanceof SpannableString)) return null;
 
diff --git a/ui/android/java/src/org/chromium/ui/widget/TextViewWithLeading.java b/ui/android/java/src/org/chromium/ui/widget/TextViewWithLeading.java
index a42c3717..79c321c 100644
--- a/ui/android/java/src/org/chromium/ui/widget/TextViewWithLeading.java
+++ b/ui/android/java/src/org/chromium/ui/widget/TextViewWithLeading.java
@@ -9,11 +9,12 @@
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
 
-import androidx.annotation.Nullable;
 import androidx.annotation.StyleRes;
 import androidx.annotation.StyleableRes;
 import androidx.appcompat.widget.AppCompatTextView;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.R;
 import org.chromium.ui.base.UiAndroidFeatureList;
 
@@ -23,6 +24,7 @@
  * calculation to set up leading correctly and allows it to be set in XML. It overwrites
  * android:lineSpacingExtra and android:lineSpacingMultiplier.
  */
+@NullMarked
 public class TextViewWithLeading extends AppCompatTextView {
     /**
      * Constructing TextViewWithLeading programmatically without an {@link AttributeSet} will render
diff --git a/ui/android/java/src/org/chromium/ui/widget/TextViewWithTightWrap.java b/ui/android/java/src/org/chromium/ui/widget/TextViewWithTightWrap.java
index 9df6522a..e7a87525 100644
--- a/ui/android/java/src/org/chromium/ui/widget/TextViewWithTightWrap.java
+++ b/ui/android/java/src/org/chromium/ui/widget/TextViewWithTightWrap.java
@@ -9,11 +9,14 @@
 import android.util.AttributeSet;
 import android.widget.TextView;
 
+import org.chromium.build.annotations.NullMarked;
+
 /**
  * A TextView with an accurate width calculation support for multilines.
  * This is used when we want no extra padding on a multiline TextView. The class perform the width
  * calculation in the overwritten OnMeasure() method.
  */
+@NullMarked
 public class TextViewWithTightWrap extends TextView {
     /** Constructing TextViewWithTightWrap programmatically is similar to a normal TextView. */
     public TextViewWithTightWrap(Context context) {
diff --git a/ui/android/java/src/org/chromium/ui/widget/Toast.java b/ui/android/java/src/org/chromium/ui/widget/Toast.java
index c51b445..7bbb347 100644
--- a/ui/android/java/src/org/chromium/ui/widget/Toast.java
+++ b/ui/android/java/src/org/chromium/ui/widget/Toast.java
@@ -23,6 +23,8 @@
 import androidx.annotation.StyleRes;
 
 import org.chromium.base.SysUtils;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.ui.R;
 import org.chromium.ui.display.DisplayAndroid;
 
@@ -39,6 +41,7 @@
  * that the toast be shown sooner than those of priority {@code NORMAL} queued for their turn.
  * See {@link ToastManager} for more details.
  */
+@NullMarked
 public class Toast {
 
     public static final int LENGTH_SHORT = android.widget.Toast.LENGTH_SHORT;
@@ -55,9 +58,9 @@
     }
 
     private android.widget.Toast mToast;
-    private ViewGroup mSWLayout;
+    private @Nullable ViewGroup mSWLayout;
     private @ToastPriority int mPriority;
-    private CharSequence mText;
+    private @Nullable CharSequence mText;
 
     public Toast(Context context, View toastView) {
         if (SysUtils.isLowEndDevice()) {
@@ -110,7 +113,7 @@
         }
     }
 
-    public View getView() {
+    public @Nullable View getView() {
         if (mToast.getView() == null) {
             return null;
         }
@@ -138,10 +141,11 @@
         return mPriority;
     }
 
-    void setText(CharSequence text) {
+    void setText(@Nullable CharSequence text) {
         mText = text;
     }
 
+    @Nullable
     CharSequence getText() {
         return mText;
     }
@@ -259,10 +263,10 @@
     /** Builder pattern class to construct {@link Toast} with various arguments. */
     public static class Builder {
         private final Context mContext;
-        private CharSequence mText;
-        private View mAnchoredView;
-        private Integer mBackgroundColor;
-        private Integer mTextAppearance;
+        private @Nullable CharSequence mText;
+        private @Nullable View mAnchoredView;
+        private @Nullable Integer mBackgroundColor;
+        private @Nullable Integer mTextAppearance;
         private int mDuration = LENGTH_SHORT;
         private @ToastPriority int mPriority = ToastPriority.NORMAL;
 
diff --git a/ui/android/java/src/org/chromium/ui/widget/ToastManager.java b/ui/android/java/src/org/chromium/ui/widget/ToastManager.java
index 203b397..44b001d 100644
--- a/ui/android/java/src/org/chromium/ui/widget/ToastManager.java
+++ b/ui/android/java/src/org/chromium/ui/widget/ToastManager.java
@@ -14,6 +14,10 @@
 
 import org.jni_zero.JNINamespace;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.NullUnmarked;
+import org.chromium.build.annotations.Nullable;
+
 import java.util.Iterator;
 import java.util.PriorityQueue;
 
@@ -28,11 +32,12 @@
  * </ul>
  */
 @JNINamespace("ui")
+@NullMarked
 public class ToastManager {
     private static final int DURATION_SHORT_MS = 2000;
     private static final int DURATION_LONG_MS = 3500;
     private static final long DURATION_BETWEEN_TOASTS_MS = 500;
-    private static ToastManager sInstance;
+    private static @Nullable ToastManager sInstance;
 
     // A queue for toasts waiting to be shown.
     private final PriorityQueue<Toast> mToastQueue =
@@ -50,7 +55,7 @@
     private final ToastEvent mToastEvent;
 
     // Toast currently showing. {@code null} if none is showing.
-    private Toast mToast;
+    private @Nullable Toast mToast;
 
     static ToastManager getInstance() {
         if (sInstance == null) sInstance = new ToastManager();
@@ -99,6 +104,7 @@
     }
 
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    @Nullable
     Toast getCurrentToast() {
         return mToast;
     }
@@ -148,6 +154,7 @@
             mPostToastRunnable = finishRunnable;
         }
 
+        @NullUnmarked
         @Override
         public void onShow(Toast toast) {
             int durationMs =
diff --git a/ui/android/java/src/org/chromium/ui/widget/UiWidgetFactory.java b/ui/android/java/src/org/chromium/ui/widget/UiWidgetFactory.java
index 76dad61..b2af8eb 100644
--- a/ui/android/java/src/org/chromium/ui/widget/UiWidgetFactory.java
+++ b/ui/android/java/src/org/chromium/ui/widget/UiWidgetFactory.java
@@ -9,12 +9,16 @@
 import android.content.Context;
 import android.widget.PopupWindow;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
 /**
  * The factory that creates UI widgets. Instead of direct creation of Android popups
  * we should ask this factory to create the object for us.
  */
+@NullMarked
 public class UiWidgetFactory {
-    private static UiWidgetFactory sFactory;
+    private static @Nullable UiWidgetFactory sFactory;
 
     protected UiWidgetFactory() {}
 
diff --git a/ui/android/java/src/org/chromium/ui/widget/ViewLookupCachingFrameLayout.java b/ui/android/java/src/org/chromium/ui/widget/ViewLookupCachingFrameLayout.java
index a649b38..f16f7fbc 100644
--- a/ui/android/java/src/org/chromium/ui/widget/ViewLookupCachingFrameLayout.java
+++ b/ui/android/java/src/org/chromium/ui/widget/ViewLookupCachingFrameLayout.java
@@ -11,10 +11,11 @@
 import android.view.ViewGroup;
 
 import androidx.annotation.IdRes;
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.build.BuildConfig;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 import java.lang.ref.WeakReference;
 
@@ -35,6 +36,7 @@
  *     Use the same way that you would use a normal {@link android.widget.FrameLayout}, but instead
  *     of using {@link #findViewById(int)} to access views, use {@link #fastFindViewById(int)}.
  */
+@NullMarked
 public class ViewLookupCachingFrameLayout extends OptimizedFrameLayout {
     /** A map containing views that have had lookup performed on them for quicker access. */
     private final SparseArray<WeakReference<View>> mCachedViews = new SparseArray<>();
@@ -73,7 +75,8 @@
      * @param view The root of the tree to attach listeners to.
      * @param listener The listener to attach (null to unset).
      */
-    private void setHierarchyListenerOnTree(View view, OnHierarchyChangeListener listener) {
+    private void setHierarchyListenerOnTree(
+            View view, @Nullable OnHierarchyChangeListener listener) {
         if (!(view instanceof ViewGroup)) return;
 
         ViewGroup group = (ViewGroup) view;
@@ -90,8 +93,7 @@
      * @param id The ID of the view to lookup.
      * @return The view if it exists.
      */
-    @Nullable
-    public View fastFindViewById(@IdRes int id) {
+    public @Nullable View fastFindViewById(@IdRes int id) {
         WeakReference<View> ref = mCachedViews.get(id);
         View view = null;
         if (ref != null) view = ref.get();
diff --git a/ui/android/java/src/org/chromium/ui/widget/ViewRectProvider.java b/ui/android/java/src/org/chromium/ui/widget/ViewRectProvider.java
index d1d7ea1..3ae4a0e 100644
--- a/ui/android/java/src/org/chromium/ui/widget/ViewRectProvider.java
+++ b/ui/android/java/src/org/chromium/ui/widget/ViewRectProvider.java
@@ -10,11 +10,15 @@
 
 import androidx.core.view.ViewCompat;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
 /**
  * Provides a {@link Rect} for the location of a {@link View} in its window, see {@link
  * View#getLocationOnScreen(int[])}. When view bound changes, {@link RectProvider.Observer} will be
  * notified.
  */
+@NullMarked
 public class ViewRectProvider extends RectProvider
         implements ViewTreeObserver.OnGlobalLayoutListener,
                 View.OnAttachStateChangeListener,
@@ -28,7 +32,7 @@
     private int mCachedViewHeight;
 
     /** If not {@code null}, the {@link ViewTreeObserver} that we are registered to. */
-    private ViewTreeObserver mViewTreeObserver;
+    private @Nullable ViewTreeObserver mViewTreeObserver;
 
     private boolean mIncludePadding;
 
diff --git a/ui/android/javatests/src/org/chromium/ui/test/util/UiRestriction.java b/ui/android/javatests/src/org/chromium/ui/test/util/UiRestriction.java
index 1d8f96c..d1f9a41 100644
--- a/ui/android/javatests/src/org/chromium/ui/test/util/UiRestriction.java
+++ b/ui/android/javatests/src/org/chromium/ui/test/util/UiRestriction.java
@@ -18,8 +18,16 @@
  * </code>
  */
 public final class UiRestriction {
+    private static Boolean sIsDesktop;
     private static Boolean sIsTablet;
 
+    private static boolean isDesktop() {
+      if (sIsDesktop == null) {
+        sIsDesktop = DeviceFormFactor.isDesktop();
+      }
+      return sIsDesktop;
+    }
+
     private static boolean isTablet() {
         if (sIsTablet == null) {
             sIsTablet =
@@ -33,6 +41,7 @@
     }
 
     public static void registerChecks(RestrictionSkipCheck check) {
+        check.addHandler(DeviceFormFactor.DESKTOP, () -> isDesktop());
         check.addHandler(DeviceFormFactor.PHONE, () -> isTablet());
         check.addHandler(DeviceFormFactor.TABLET, () -> !isTablet());
     }
diff --git a/ui/base/models/combobox_model.cc b/ui/base/models/combobox_model.cc
index 2bd9e83e..d1dd4f4 100644
--- a/ui/base/models/combobox_model.cc
+++ b/ui/base/models/combobox_model.cc
@@ -32,6 +32,10 @@
   return false;
 }
 
+bool ComboboxModel::IsItemTitleAt(size_t index) const {
+  return false;
+}
+
 std::optional<size_t> ComboboxModel::GetDefaultIndex() const {
   return size_t{0};
 }
diff --git a/ui/base/models/combobox_model.h b/ui/base/models/combobox_model.h
index 299571c..cc52b94 100644
--- a/ui/base/models/combobox_model.h
+++ b/ui/base/models/combobox_model.h
@@ -45,6 +45,10 @@
   // item.
   virtual bool IsItemSeparatorAt(size_t index) const;
 
+  // TODO(pbos): Consider replacing this (and IsItemSeparatorAt) with something
+  // that either returns or maps well to MenuModel::ItemType.
+  virtual bool IsItemTitleAt(size_t index) const;
+
   // The index of the item that is selected by default (before user
   // interaction).
   virtual std::optional<size_t> GetDefaultIndex() const;
diff --git a/ui/ozone/platform/wayland/host/wayland_shm_buffer.cc b/ui/ozone/platform/wayland/host/wayland_shm_buffer.cc
index 6ed0893..d1d36e7 100644
--- a/ui/ozone/platform/wayland/host/wayland_shm_buffer.cc
+++ b/ui/ozone/platform/wayland/host/wayland_shm_buffer.cc
@@ -57,7 +57,7 @@
   stride_ = stride;
 }
 
-uint8_t* WaylandShmBuffer::GetMemory() const {
+uint8_t* WaylandShmBuffer::GetMemory() {
   if (!IsValid() || !shared_memory_mapping_.IsValid())
     return nullptr;
   return shared_memory_mapping_.GetMemoryAs<uint8_t>();
diff --git a/ui/ozone/platform/wayland/host/wayland_shm_buffer.h b/ui/ozone/platform/wayland/host/wayland_shm_buffer.h
index 6a38389..93284cfc 100644
--- a/ui/ozone/platform/wayland/host/wayland_shm_buffer.h
+++ b/ui/ozone/platform/wayland/host/wayland_shm_buffer.h
@@ -39,7 +39,7 @@
 
   // Returns the underlying raw memory buffer, if it's currently mapped into
   // local address space, otherwise return nullptr
-  uint8_t* GetMemory() const;
+  uint8_t* GetMemory();
 
   // Returns the underlying wl_buffer pointer
   wl_buffer* get() const { return buffer_.get(); }
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index 0d4a2d80..55fe914 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -214,6 +214,7 @@
     "controls/textfield/textfield.h",
     "controls/textfield/textfield_controller.h",
     "controls/textfield/textfield_model.h",
+    "controls/theme_tracking_animated_image_view.h",
     "controls/theme_tracking_image_view.h",
     "controls/throbber.h",
     "controls/tree/tree_view.h",
@@ -446,6 +447,7 @@
     "controls/textfield/textfield.cc",
     "controls/textfield/textfield_controller.cc",
     "controls/textfield/textfield_model.cc",
+    "controls/theme_tracking_animated_image_view.cc",
     "controls/theme_tracking_image_view.cc",
     "controls/throbber.cc",
     "controls/tree/tree_view.cc",
diff --git a/ui/views/controls/combobox/combobox.h b/ui/views/controls/combobox/combobox.h
index a836092d..8463d2c 100644
--- a/ui/views/controls/combobox/combobox.h
+++ b/ui/views/controls/combobox/combobox.h
@@ -72,10 +72,8 @@
     callback_ = std::move(callback);
   }
 
-  // Set menu model.
-  void SetMenuModel(std::unique_ptr<ui::MenuModel> menu_model) {
-    menu_model_ = std::move(menu_model);
-  }
+  // Gets the matching menu-model adapter for testing.
+  ui::MenuModel* menu_model_for_testing() const { return menu_model_.get(); }
 
   // Gets/Sets the selected index.
   std::optional<size_t> GetSelectedIndex() const { return selected_index_; }
diff --git a/ui/views/controls/combobox/combobox_menu_model.cc b/ui/views/controls/combobox/combobox_menu_model.cc
index 32e2cdad..5e0bcacb 100644
--- a/ui/views/controls/combobox/combobox_menu_model.cc
+++ b/ui/views/controls/combobox/combobox_menu_model.cc
@@ -24,8 +24,12 @@
 }
 
 ui::MenuModel::ItemType ComboboxMenuModel::GetTypeAt(size_t index) const {
-  if (model_->IsItemSeparatorAt(index))
+  if (model_->IsItemSeparatorAt(index)) {
     return TYPE_SEPARATOR;
+  }
+  if (model_->IsItemTitleAt(index)) {
+    return TYPE_TITLE;
+  }
   return UseCheckmarks() ? TYPE_CHECK : TYPE_COMMAND;
 }
 
diff --git a/ui/views/controls/theme_tracking_animated_image_view.cc b/ui/views/controls/theme_tracking_animated_image_view.cc
new file mode 100644
index 0000000..3c7f9b3
--- /dev/null
+++ b/ui/views/controls/theme_tracking_animated_image_view.cc
@@ -0,0 +1,54 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/theme_tracking_animated_image_view.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <optional>
+#include <utility>
+#include <vector>
+
+#include "base/functional/callback.h"
+#include "cc/paint/skottie_wrapper.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/color_utils.h"
+
+namespace views {
+
+ThemeTrackingAnimatedImageView::ThemeTrackingAnimatedImageView(
+    int light_animation_lottie_id,
+    int dark_animation_lottie_id,
+    base::RepeatingCallback<SkColor()> get_background_color_callback)
+    : light_animation_lottie_id_(light_animation_lottie_id),
+      dark_animation_lottie_id_(dark_animation_lottie_id),
+      get_background_color_callback_(std::move(get_background_color_callback)) {
+}
+
+ThemeTrackingAnimatedImageView::~ThemeTrackingAnimatedImageView() = default;
+
+void ThemeTrackingAnimatedImageView::OnThemeChanged() {
+  AnimatedImageView::OnThemeChanged();
+  const bool is_dark =
+      color_utils::IsDark(get_background_color_callback_.Run());
+  UpdateAnimatedImage(is_dark ? dark_animation_lottie_id_
+                              : light_animation_lottie_id_);
+}
+
+void ThemeTrackingAnimatedImageView::UpdateAnimatedImage(int lottie_id) {
+  std::optional<std::vector<uint8_t>> lottie_bytes =
+      ui::ResourceBundle::GetSharedInstance().GetLottieData(lottie_id);
+  scoped_refptr<cc::SkottieWrapper> skottie =
+      cc::SkottieWrapper::UnsafeCreateSerializable(std::move(*lottie_bytes));
+  SetAnimatedImage(std::make_unique<lottie::Animation>(skottie));
+  SizeToPreferredSize();
+  Play();
+}
+
+BEGIN_METADATA(ThemeTrackingAnimatedImageView)
+END_METADATA
+
+}  // namespace views
diff --git a/ui/views/controls/theme_tracking_animated_image_view.h b/ui/views/controls/theme_tracking_animated_image_view.h
new file mode 100644
index 0000000..0cf257f
--- /dev/null
+++ b/ui/views/controls/theme_tracking_animated_image_view.h
@@ -0,0 +1,49 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_THEME_TRACKING_ANIMATED_IMAGE_VIEW_H_
+#define UI_VIEWS_CONTROLS_THEME_TRACKING_ANIMATED_IMAGE_VIEW_H_
+
+#include "base/functional/callback_forward.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/views/controls/animated_image_view.h"
+
+namespace views {
+
+// An AnimatedImageView that displays either `light_animation_lottie_id` or
+// `dark_animation_lottie_id` based on the current background color returned by
+// `get_background_color_callback`. Tracks theme changes so the image is always
+// the correct version.
+class VIEWS_EXPORT ThemeTrackingAnimatedImageView : public AnimatedImageView {
+  METADATA_HEADER(ThemeTrackingAnimatedImageView, AnimatedImageView)
+
+ public:
+  ThemeTrackingAnimatedImageView(
+      int light_animation_lottie_id,
+      int dark_animation_lottie_id,
+      base::RepeatingCallback<SkColor()> get_background_color_callback);
+
+  ThemeTrackingAnimatedImageView(const ThemeTrackingAnimatedImageView&) =
+      delete;
+  ThemeTrackingAnimatedImageView& operator=(
+      const ThemeTrackingAnimatedImageView&) = delete;
+  ~ThemeTrackingAnimatedImageView() override;
+
+  // AnimatedImageView:
+  void OnThemeChanged() override;
+
+ private:
+  void UpdateAnimatedImage(int lottie_id);
+
+  // The underlying light and dark mode animated images' Lottie IDs.
+  int light_animation_lottie_id_;
+  int dark_animation_lottie_id_;
+
+  base::RepeatingCallback<SkColor()> get_background_color_callback_;
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_THEME_TRACKING_ANIMATED_IMAGE_VIEW_H_
diff --git a/v8 b/v8
index 27d5ca8..99d615b 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit 27d5ca8ed62889fc9974afc2fd89c078582d5dd4
+Subproject commit 99d615b4cef42ad9a32639547e8ac4bd7db462e5