diff --git a/DEPS b/DEPS
index 40b7c35a..d7e0ef7 100644
--- a/DEPS
+++ b/DEPS
@@ -288,7 +288,7 @@
   'sysroots_json_path': 'build/linux/sysroot_scripts/sysroots.json',
 
   # siso CIPD package version.
-  'siso_version': 'git_revision:437716714a744e272fabdf1377b8878ccac26b43',
+  'siso_version': 'git_revision:44d2b8f5b840adf521bb4912ccac31848f6d1448',
 
   # download libaom test data
   'download_libaom_testdata': False,
@@ -312,7 +312,7 @@
   # 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': '98dbba281a8443156105ecdb5aeece0b7fd0345f',
+  'skia_revision': 'e335a0a11aa08b3926d179e84e26eae229a2e779',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -320,7 +320,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '97cb3eb8a79dcf752a99d0895719fde9f6bb3392',
+  'angle_revision': 'e92b8e8d97d86ed49e27d8aca38a7c4d76d432a3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -383,11 +383,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '704b0216566e888ea8c3c1680d21bbf2e721faae',
+  'catapult_revision': '13025491e512e6e7b4c7fca376267fb82acad09b',
   # 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': '1b58345810cd9c9a284efbe6312e1fa7305acd71',
+  'chromium_variations_revision': '2c423221c10e3c749e2ff9d952424544e8919d7d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
@@ -427,7 +427,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'ba00f41c0e3365e638fee70983ca10ddfbe2a2ee',
+  'dawn_revision': 'b4d05dec16507b5a6fc832dfb56a9e6489a13302',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -459,7 +459,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling nearby
   # and whatever else without interference from each other.
-  'nearby_revision': 'f788b891908dd93274918e5b919e09136f3f1efd',
+  'nearby_revision': '35a8289ef40bf67c6f4586a21f9325e7ad9b1c43',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling securemessage
   # and whatever else without interference from each other.
@@ -827,12 +827,12 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '8b5df658aa105d15f72f53d23d0cc4420075ceb8',
+    'fbc5a9e586cb0f8b580be2091f80cf84529ef8ee',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + '192b4c1fca9c092343459067d75ba65fbc6ea856',
+    'url': Var('chromium_git') + '/website.git' + '@' + '15de42c1a6ab2c80ad289fb8e61aea8ced48a4b9',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -982,7 +982,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': '2HIaQOZfz6KolPkB-gdaGP_O9DtLVSQnecjAeXlqG7AC',
+          'version': '-9mkWhwjTp6c-JwBWGcq4oAql_VoA9lykHUCzsAZgEEC',
       },
     ],
     'condition': 'checkout_android',
@@ -1192,7 +1192,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '05d20bc699768f6185938cbc426876986cc68a69',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '332c4eb546eccaa4fa1a524d89c9c82194b8b998',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1811,7 +1811,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@8dc5cb57074c42295aa647ea407e1adb85f6ec93',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@1517f06f64fc0b4181a15a188c8e851ba067dfb9',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '56300b29fbfcc693ee6609ddad3fdd5b7a449a21',
@@ -1848,10 +1848,10 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'bc3c8bad295ae0ba7f0ddb18848df70f92a820c0',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'f648fd6de71e4888b05e247087e77273eb4871da',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'a75ea0e849f517c52b993f0b69f75f1b7c286a49',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'de7e4ad1b1cb9b6d15cac281820399a613d6d971',
+    Var('webrtc_git') + '/src.git' + '@' + '655c89088f563cd553595ec707b312c62a6efc02',
 
   # 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.
@@ -1901,7 +1901,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/linux-amd64',
-          'version': 'ZpyLtfuztdYI-RCkvm6kXlmx8ec1wYyrwXNI-lQEJKwC',
+          'version': 'SQswrvGi674ASEtZKS6NGrcxzcOAx9fdEvxSUwNCVkIC',
         },
       ],
       'dep_type': 'cipd',
@@ -1922,7 +1922,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/mac-amd64',
-          'version': 'FpwpXsMPl8Mets8uet3zfFw8nNBpl69xJoTYESLUjl8C',
+          'version': 'vuB-Klm2s3uWsshi6g4r4l4fZox0RrWCgtSRKTxev3QC',
         },
       ],
       'dep_type': 'cipd',
@@ -1933,7 +1933,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/mac-arm64',
-          'version': 'GuJOsvx5V5z8DvAM_HOVy6eBydQ0sO7dVso_p_L7KTgC',
+          'version': 'sqWmO8LOK7GgLCYuZo_PWkn6BcuBSgv16TPYoV44QUsC',
         },
       ],
       'dep_type': 'cipd',
@@ -4065,7 +4065,7 @@
 
   'src/components/optimization_guide/internal': {
       'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' +
-        '5779125122f438c5f18b78f9d554a71da25b902f',
+        'bf065aaf550359d584f16cb19becfbf5b6cda492',
       'condition': 'checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index 639a114..3c307bdd 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -856,6 +856,7 @@
                   'chromeos/ash/components/network/|'\
                   'chromeos/ash/components/wifi_p2p/|'\
                   'chromeos/ash/services/network_config/|'\
+                  'chromeos/ash/services/wifi_direct/|'\
                   'chromeos/services/network_config/|'\
                   'components/onc/|'\
                   'extensions/browser/api/networking_private/',
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 0de6d53d..2e35f8af 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -2204,6 +2204,11 @@
              "OrcaOnlyInEnglishLocales",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Enables or disables Orca resizing support.
+BASE_FEATURE(kOrcaResizingSupport,
+             "OrcaResizingSupport",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 // Enables or disables Orca on Demo mode.
 BASE_FEATURE(kOrcaSupportDemoMode,
              "OrcaSupportDemoMode",
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index ac8da9c..ea3b6ea 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -663,6 +663,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kOrcaOnlyInEnglishLocales);
 COMPONENT_EXPORT(ASH_CONSTANTS)
+BASE_DECLARE_FEATURE(kOrcaResizingSupport);
+COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kOrcaUseAccountCapabilities);
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsOsFeedbackDialogEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS)
diff --git a/ash/webui/print_management/BUILD.gn b/ash/webui/print_management/BUILD.gn
index 7af1524..825287d5 100644
--- a/ash/webui/print_management/BUILD.gn
+++ b/ash/webui/print_management/BUILD.gn
@@ -10,10 +10,10 @@
   sources = [
     "print_management_ui.cc",
     "print_management_ui.h",
-    "url_constants.cc",
-    "url_constants.h",
   ]
 
+  public_deps = [ ":url_constants" ]
+
   deps = [
     "//ash/constants:constants",
     "//ash/webui/common:chrome_os_webui_config",
@@ -29,3 +29,12 @@
     "//ui/webui",
   ]
 }
+
+# Url constants pulled out to enable depending on production url constants in
+# browser tests.
+source_set("url_constants") {
+  sources = [
+    "url_constants.cc",
+    "url_constants.h",
+  ]
+}
diff --git a/ash/webui/print_preview_cros/resources/js/data/print_ticket_manager.ts b/ash/webui/print_preview_cros/resources/js/data/print_ticket_manager.ts
index 64f38aa..208af476 100644
--- a/ash/webui/print_preview_cros/resources/js/data/print_ticket_manager.ts
+++ b/ash/webui/print_preview_cros/resources/js/data/print_ticket_manager.ts
@@ -6,7 +6,7 @@
 
 import {createCustomEvent} from '../utils/event_utils.js';
 import {getPrintPreviewPageHandler} from '../utils/mojo_data_providers.js';
-import {type PrintPreviewPageHandler, SessionContext} from '../utils/print_preview_cros_app_types.js';
+import {type PrintPreviewPageHandler, PrintTicket, SessionContext} from '../utils/print_preview_cros_app_types.js';
 
 /**
  * @fileoverview
@@ -39,6 +39,7 @@
   // Non-static properties:
   private printPreviewPageHandler: PrintPreviewPageHandler|null;
   private printRequestInProgress = false;
+  private printTicket: PrintTicket|null = null;
   private sessionContext: SessionContext;
 
   // Prevent additional initialization.
@@ -57,6 +58,10 @@
     this.sessionContext = sessionContext;
     // TODO(b/323421684): Uses session context to configure ticket properties
     // and validating ticket matches policy requirements.
+    this.printTicket = {
+      printPreviewId: this.sessionContext.printPreviewId,
+    } as PrintTicket;
+
     this.dispatchEvent(
         createCustomEvent(PRINT_TICKET_MANAGER_SESSION_INITIALIZED));
   }
@@ -68,6 +73,11 @@
   sendPrintRequest(): void {
     assert(this.printPreviewPageHandler);
 
+    if (this.printTicket === null) {
+      // Print Ticket is not ready to be sent.
+      return;
+    }
+
     if (this.printRequestInProgress) {
       // Print is already in progress, wait for request to resolve before
       // allowing a second attempt.
@@ -79,7 +89,7 @@
 
     // TODO(b/323421684): Handle result from page handler and update UI if error
     // occurred.
-    this.printPreviewPageHandler!.print().finally(() => {
+    this.printPreviewPageHandler!.print(this.printTicket).finally(() => {
       this.printRequestInProgress = false;
       this.dispatchEvent(createCustomEvent(PRINT_REQUEST_FINISHED_EVENT));
     });
@@ -100,6 +110,10 @@
   isSessionInitialized(): boolean {
     return !!this.sessionContext;
   }
+
+  getPrintTicketForTesting(): PrintTicket|null {
+    return this.printTicket;
+  }
 }
 
 declare global {
diff --git a/ash/webui/print_preview_cros/resources/js/utils/print_preview_cros_app_types.ts b/ash/webui/print_preview_cros/resources/js/utils/print_preview_cros_app_types.ts
index de24bc54..5204060 100644
--- a/ash/webui/print_preview_cros/resources/js/utils/print_preview_cros_app_types.ts
+++ b/ash/webui/print_preview_cros/resources/js/utils/print_preview_cros_app_types.ts
@@ -25,6 +25,16 @@
   error?: string;
 }
 
+// PrintTicket represents the data required to start print job. Ticket will be
+// used to create a settings dictionary with fields matching the existing Chrome
+// preview print settings for reusability.
+// TODO(b/323421684): Add missing required settings to start print job.
+export interface PrintTicket {
+  // ID used to map a CrOS preview session to the responsible PrintViewManager
+  // and related web contents.
+  printPreviewId: UnguessableToken;
+}
+
 // Immutable session configuration details for the current CrOS preview request.
 export interface SessionContext {
   // ID used to map a CrOS preview session to the responsible PrintViewManager
@@ -39,9 +49,10 @@
   // a SessionContext.
   startSession(): Promise<SessionContext>;
 
-  // Start the print job and close the window. Needs to wait for result to
-  // display error messaging if starting the print job fails.
-  print(): Promise<PrintRequestOutcome>;
+  // Start the print job and close the window. Requires a print ticket to detail
+  // how print job should be configured.Needs to wait for result to display
+  // error messaging if starting the print job fails.
+  print(ticket: PrintTicket): Promise<PrintRequestOutcome>;
 
   // Cancel the print preview and close the window.
   cancel(): void;
diff --git a/ash/wm/snap_group/snap_group_unittest.cc b/ash/wm/snap_group/snap_group_unittest.cc
index 3a670efa..21670031 100644
--- a/ash/wm/snap_group/snap_group_unittest.cc
+++ b/ash/wm/snap_group/snap_group_unittest.cc
@@ -4089,7 +4089,14 @@
 
 // Tests that pressing the 'Close All' button closes both windows in a Snap
 // Group.
-TEST_F(SnapGroupDesksTest, CloseAll) {
+// TODO(crbug.com/335001236): Re-enable this test
+#if defined(MEMORY_SANITIZER) || defined(ADDRESS_SANITIZER) || \
+    defined(LEAK_SANITIZER)
+#define MAYBE_CloseAll DISABLED_CloseAll
+#else
+#define MAYBE_CloseAll CloseAll
+#endif
+TEST_F(SnapGroupDesksTest, MAYBE_CloseAll) {
   auto* desks_controller = DesksController::Get();
   desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
   ASSERT_EQ(2u, desks_controller->desks().size());
diff --git a/ash/wm/splitview/split_view_divider.cc b/ash/wm/splitview/split_view_divider.cc
index ab194dc..ea91593 100644
--- a/ash/wm/splitview/split_view_divider.cc
+++ b/ash/wm/splitview/split_view_divider.cc
@@ -601,8 +601,8 @@
     // widget.
     divider_view_->SetCanProcessEventsWithinSubtree(false);
     divider_window->SetEventTargetingPolicy(aura::EventTargetingPolicy::kNone);
-    divider_view_ = nullptr;
     divider_widget_->Close();
+    divider_view_ = nullptr;
     divider_widget_ = nullptr;
   }
 }
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/apple/foundation_util.h b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/apple/foundation_util.h
index 3a4a921..663863de 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/apple/foundation_util.h
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/apple/foundation_util.h
@@ -11,14 +11,12 @@
 
 namespace partition_alloc::internal::base::apple {
 
-// CFCast<>() and CFCastStrict<>() cast a basic CFTypeRef to a more
-// specific CoreFoundation type. The compatibility of the passed
-// object is found by comparing its opaque type against the
-// requested type identifier. If the supplied object is not
-// compatible with the requested return type, CFCast<>() returns
-// NULL and CFCastStrict<>() will DCHECK. Providing a NULL pointer
-// to either variant results in NULL being returned without
-// triggering any DCHECK.
+// CFCast<>() and CFCastStrict<>() cast a basic CFTypeRef to a more specific
+// CoreFoundation type. The compatibility of the passed object is found by
+// comparing its opaque type against the requested type identifier. If the
+// supplied object is not compatible with the requested return type, CFCast<>()
+// returns null and CFCastStrict<>() will CHECK. Providing a null pointer to
+// either variant results in null being returned without triggering any CHECK.
 //
 // Example usage:
 // CFNumberRef some_number = base::mac::CFCast<CFNumberRef>(
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/apple/foundation_util.mm b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/apple/foundation_util.mm
index 7bcafc3..4cf23dde 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/apple/foundation_util.mm
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/apple/foundation_util.mm
@@ -11,19 +11,19 @@
 #define PA_CF_CAST_DEFN(TypeCF)                                    \
   template <>                                                      \
   TypeCF##Ref CFCast<TypeCF##Ref>(const CFTypeRef& cf_val) {       \
-    if (cf_val == NULL) {                                          \
-      return NULL;                                                 \
+    if (cf_val == nullptr) {                                       \
+      return nullptr;                                              \
     }                                                              \
     if (CFGetTypeID(cf_val) == TypeCF##GetTypeID()) {              \
       return (TypeCF##Ref)(cf_val);                                \
     }                                                              \
-    return NULL;                                                   \
+    return nullptr;                                                \
   }                                                                \
                                                                    \
   template <>                                                      \
   TypeCF##Ref CFCastStrict<TypeCF##Ref>(const CFTypeRef& cf_val) { \
     TypeCF##Ref rv = CFCast<TypeCF##Ref>(cf_val);                  \
-    PA_BASE_DCHECK(cf_val == NULL || rv);                          \
+    PA_BASE_CHECK(cf_val == nullptr || rv);                        \
     return rv;                                                     \
   }
 
diff --git a/base/apple/foundation_util.h b/base/apple/foundation_util.h
index d1d8e05..26a01569 100644
--- a/base/apple/foundation_util.h
+++ b/base/apple/foundation_util.h
@@ -140,14 +140,12 @@
 // make its own copy of new_base_bundle_id.
 BASE_EXPORT void SetBaseBundleID(const char* new_base_bundle_id);
 
-// CFCast<>() and CFCastStrict<>() cast a basic CFTypeRef to a more
-// specific CoreFoundation type. The compatibility of the passed
-// object is found by comparing its opaque type against the
-// requested type identifier. If the supplied object is not
-// compatible with the requested return type, CFCast<>() returns
-// NULL and CFCastStrict<>() will DCHECK. Providing a NULL pointer
-// to either variant results in NULL being returned without
-// triggering any DCHECK.
+// CFCast<>() and CFCastStrict<>() cast a basic CFTypeRef to a more specific
+// CoreFoundation type. The compatibility of the passed object is found by
+// comparing its opaque type against the requested type identifier. If the
+// supplied object is not compatible with the requested return type, CFCast<>()
+// returns null and CFCastStrict<>() will CHECK. Providing a null pointer to
+// either variant results in null being returned without triggering any CHECK.
 //
 // Example usage:
 // CFNumberRef some_number = base::apple::CFCast<CFNumberRef>(
@@ -197,28 +195,27 @@
 
 #if defined(__OBJC__)
 
-// ObjCCast<>() and ObjCCastStrict<>() cast a basic id to a more
-// specific (NSObject-derived) type. The compatibility of the passed
-// object is found by checking if it's a kind of the requested type
-// identifier. If the supplied object is not compatible with the
-// requested return type, ObjCCast<>() returns nil and
-// ObjCCastStrict<>() will DCHECK. Providing a nil pointer to either
-// variant results in nil being returned without triggering any DCHECK.
+// ObjCCast<>() and ObjCCastStrict<>() cast a basic id to a more specific
+// (NSObject-derived) type. The compatibility of the passed object is found by
+// checking if it's a kind of the requested type identifier. If the supplied
+// object is not compatible with the requested return type, ObjCCast<>() returns
+// nil and ObjCCastStrict<>() will CHECK. Providing a nil pointer to either
+// variant results in nil being returned without triggering any CHECK.
 //
-// The strict variant is useful when retrieving a value from a
-// collection which only has values of a specific type, e.g. an
-// NSArray of NSStrings. The non-strict variant is useful when
-// retrieving values from data that you can't fully control. For
-// example, a plist read from disk may be beyond your exclusive
-// control, so you'd only want to check that the values you retrieve
+// The strict variant is useful when retrieving a value from a collection which
+// only has values of a specific type, e.g. an NSArray of NSStrings. The
+// non-strict variant is useful when retrieving values from data that you can't
+// fully control. For example, a plist read from disk may be beyond your
+// exclusive control, so you'd only want to check that the values you retrieve
 // from it are of the expected types, but not crash if they're not.
 //
 // Example usage:
-// NSString* version = base::apple::ObjCCast<NSString>(
-//     [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]);
+//   NSString* version = base::apple::ObjCCast<NSString>(
+//       [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]);
 //
-// NSString* str = base::apple::ObjCCastStrict<NSString>(
-//     [ns_arr_of_ns_strs objectAtIndex:0]);
+//   // (If it's not possible to use an NSArray<NSString>.)
+//   NSString* str = base::apple::ObjCCastStrict<NSString>(
+//       [ns_arr_of_ns_strs objectAtIndex:0]);
 template <typename T>
 T* ObjCCast(id objc_val) {
   if ([objc_val isKindOfClass:[T class]]) {
@@ -230,7 +227,7 @@
 template <typename T>
 T* ObjCCastStrict(id objc_val) {
   T* rv = ObjCCast<T>(objc_val);
-  DCHECK(objc_val == nil || rv);
+  CHECK(objc_val == nil || rv);
   return rv;
 }
 
diff --git a/base/apple/foundation_util.mm b/base/apple/foundation_util.mm
index cd637a1b..d0f6af8e 100644
--- a/base/apple/foundation_util.mm
+++ b/base/apple/foundation_util.mm
@@ -309,19 +309,19 @@
 #define CF_CAST_DEFN(TypeCF)                                       \
   template <>                                                      \
   TypeCF##Ref CFCast<TypeCF##Ref>(const CFTypeRef& cf_val) {       \
-    if (cf_val == NULL) {                                          \
-      return NULL;                                                 \
+    if (cf_val == nullptr) {                                       \
+      return nullptr;                                              \
     }                                                              \
     if (CFGetTypeID(cf_val) == TypeCF##GetTypeID()) {              \
       return (TypeCF##Ref)(cf_val);                                \
     }                                                              \
-    return NULL;                                                   \
+    return nullptr;                                                \
   }                                                                \
                                                                    \
   template <>                                                      \
   TypeCF##Ref CFCastStrict<TypeCF##Ref>(const CFTypeRef& cf_val) { \
     TypeCF##Ref rv = CFCast<TypeCF##Ref>(cf_val);                  \
-    DCHECK(cf_val == NULL || rv);                                  \
+    CHECK(cf_val == nullptr || rv);                                \
     return rv;                                                     \
   }
 
diff --git a/base/memory/platform_shared_memory_mapper_apple.cc b/base/memory/platform_shared_memory_mapper_apple.cc
index 39dafe6..1400d07 100644
--- a/base/memory/platform_shared_memory_mapper_apple.cc
+++ b/base/memory/platform_shared_memory_mapper_apple.cc
@@ -4,10 +4,11 @@
 
 #include "base/memory/platform_shared_memory_mapper.h"
 
-#include "base/logging.h"
-
 #include <mach/vm_map.h>
+
 #include "base/apple/mach_logging.h"
+#include "base/containers/span.h"
+#include "base/logging.h"
 
 namespace base {
 
@@ -32,7 +33,10 @@
     return std::nullopt;
   }
 
-  return make_span(reinterpret_cast<uint8_t*>(address), size);
+  // SAFETY: vm_map() maps a memory segment of `size` bytes. Since
+  // `VM_FLAGS_ANYWHERE` is used, the address will be chosen by vm_map() and
+  // returned in `address`.
+  return UNSAFE_BUFFERS(base::span(reinterpret_cast<uint8_t*>(address), size));
 }
 
 void PlatformSharedMemoryMapper::Unmap(span<uint8_t> mapping) {
diff --git a/base/message_loop/message_pump_win.cc b/base/message_loop/message_pump_win.cc
index b136708..82cbb425 100644
--- a/base/message_loop/message_pump_win.cc
+++ b/base/message_loop/message_pump_win.cc
@@ -105,7 +105,7 @@
   // |bound_thread_|.
 
   if (g_ui_pump_improvements_win &&
-      nested_state_ != NestedState::kNestedNativeLoopAnnounced) {
+      !in_nested_native_loop_with_application_tasks_) {
     // The pump is running using `event_` as its chrome-side synchronization
     // variable. In this case, no deduplication is done, since the event has its
     // own state.
@@ -160,7 +160,7 @@
   // See MessageLoopTest.PostDelayedTaskFromSystemPump for an example.
   // TODO(gab): This could potentially be replaced by a ForegroundIdleProc hook
   // if Windows ends up being the only platform requiring ScheduleDelayedWork().
-  if (nested_state_ == NestedState::kNestedNativeLoopAnnounced &&
+  if (in_nested_native_loop_with_application_tasks_ &&
       !native_msg_scheduled_.load(std::memory_order_relaxed)) {
     ScheduleNativeTimer(next_work_info);
   }
@@ -168,16 +168,13 @@
 
 bool MessagePumpForUI::HandleNestedNativeLoopWithApplicationTasks(
     bool application_tasks_desired) {
+  // It is here assumed that we will be in a native loop until either
+  // DoRunLoop() gets control back, or this is called with `false`, and thus the
+  // Windows event queue is to be used for synchronization. This is to prevent
+  // being unable to wake up for application tasks in the case of a nested loop.
+  in_nested_native_loop_with_application_tasks_ = application_tasks_desired;
   if (application_tasks_desired) {
-    // It is here assumed that we will be in a native loop until either
-    // DoRunLoop() gets control back, or this is called with `false`, and thus
-    // must `use_windows_event_queue_for_synchronization_`. This is to prevent
-    // being unable to wake up for application tasks in the case of a nested
-    // loop.
-    nested_state_ = NestedState::kNestedNativeLoopAnnounced;
     ScheduleWork();
-  } else {
-    nested_state_ = NestedState::kNone;
   }
   return true;
 }
@@ -237,7 +234,7 @@
     // work, then it is a good time to consider sleeping (waiting) for more
     // work.
 
-    nested_state_ = NestedState::kNone;
+    in_nested_native_loop_with_application_tasks_ = false;
     bool more_work_is_plausible = false;
 
     if (!g_ui_pump_improvements_win ||
@@ -246,14 +243,16 @@
       // We can end up in native loops which allow application tasks outside of
       // DoWork() when Windows calls back a Win32 message window owned by some
       // Chromium code.
-      nested_state_ = NestedState::kNone;
+      in_nested_native_loop_with_application_tasks_ = false;
       if (run_state_->should_quit) {
         break;
       }
     }
 
     Delegate::NextWorkInfo next_work_info = run_state_->delegate->DoWork();
-    nested_state_ = NestedState::kNone;
+    // Since nested native loops with application tasks are initiated by a
+    // scoper, they should always be cleared before exiting DoWork().
+    DCHECK(!in_nested_native_loop_with_application_tasks_);
     wakeup_state_ = WakeupState::kRunning;
     more_work_is_plausible |= next_work_info.is_immediate();
 
@@ -276,7 +275,7 @@
     // DoIdleWork() shouldn't end up in native nested loops, nor should it
     // permit native nested loops, and thus shouldn't have any chance of
     // reinstalling a native timer.
-    DCHECK_EQ(nested_state_, NestedState::kNone);
+    DCHECK(!in_nested_native_loop_with_application_tasks_);
     DCHECK(!installed_native_timer_);
     if (run_state_->should_quit) {
       break;
@@ -388,12 +387,6 @@
 void MessagePumpForUI::HandleWorkMessage() {
   DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
 
-  if (nested_state_ != NestedState::kNestedNativeLoopAnnounced) {
-    // The kMsgHaveWork message was consumed by a native loop, we must assume
-    // we're in one until DoRunLoop() gets control back.
-    nested_state_ = NestedState::kNestedNativeLoopDetected;
-  }
-
   // If we are being called outside of the context of Run, then don't try to do
   // any work.  This could correspond to a MessageBox call or something of that
   // sort.
@@ -452,8 +445,10 @@
 void MessagePumpForUI::ScheduleNativeTimer(
     Delegate::NextWorkInfo next_work_info) {
   DCHECK(!next_work_info.is_immediate());
-  // Ensure we are nested in some way.
-  DCHECK_NE(nested_state_, NestedState::kNone);
+  // We should only ScheduleNativeTimer() under the new pump implementation
+  // while nested with application tasks.
+  DCHECK(!g_ui_pump_improvements_win ||
+         in_nested_native_loop_with_application_tasks_);
 
   // Do not redundantly set the same native timer again if it was already set.
   // This can happen when a nested native loop goes idle with pending delayed
diff --git a/base/message_loop/message_pump_win.h b/base/message_loop/message_pump_win.h
index 3607f768..b5d1faf 100644
--- a/base/message_loop/message_pump_win.h
+++ b/base/message_loop/message_pump_win.h
@@ -183,26 +183,19 @@
   // is enabled.
   WaitableEvent event_{WaitableEvent::ResetPolicy::AUTOMATIC};
 
-  enum class NestedState {
-    // There are no nested message loops running.
-    kNone,
-    // kMsgHaveWork was pumped from a native queue. The state will return to
-    // `kNormal` whenever DoRunLoop() regains control.
-    //
-    // It is reset to `kNone` when DoRunLoop() gets control back after
-    // ProcessNextWindowsMessage() or DoWork().
-    kNestedNativeLoopDetected,
-    // HandleNestedNativeLoopWithApplicationTasks(true) was called (when a
-    // `ScopedAllowApplicationTasksInNativeNestedLoop` is instantiated). When
-    // running with `event_`, switches to pumping `kMsgHaveWork` MSGs when there
-    // are application tasks to be done during native runloops. In this state,
-    // ScheduleDelayedWork() will start a native timer.
-    //
-    // It is reset to `kNone` when:
-    //   - DoRunLoop() gets control back after ProcessNextWindowsMessage().
-    //   - HandleNestedNativeLoopWithApplicationTasks(false) is called.
-    kNestedNativeLoopAnnounced
-  } nested_state_ = NestedState::kNone;
+  // This is set when HandleNestedNativeLoopWithApplicationTasks(true) was
+  // called (when a `ScopedAllowApplicationTasksInNativeNestedLoop` is
+  // instantiated).
+  //
+  // When running with `event_`, switches to pumping
+  // `kMsgHaveWork` MSGs when there are application tasks to be done during
+  // native runloops. In this state, ScheduleDelayedWork() will start a native
+  // timer.
+  //
+  // It is reset when:
+  //   - DoRunLoop() gets control back after ProcessNextWindowsMessage().
+  //   - HandleNestedNativeLoopWithApplicationTasks(false) is called.
+  bool in_nested_native_loop_with_application_tasks_ = false;
 
   enum class WakeupState {
     kApplicationTask,
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/BatchedPublicTransitRule.java b/base/test/android/javatests/src/org/chromium/base/test/transit/BatchedPublicTransitRule.java
index 71186093..294fc28 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/transit/BatchedPublicTransitRule.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/transit/BatchedPublicTransitRule.java
@@ -20,12 +20,16 @@
  */
 public class BatchedPublicTransitRule<T extends TransitStation> implements TestRule {
     private final Class<T> mHomeStationType;
+    private final boolean mExpectResetByTest;
 
     /**
      * @param homeStationType Class of the home station
+     * @param expectResetByTest Whether the tests are responsible for resetting state before they
+     *     finish. If false, state should be reset at the start of each test.
      */
-    public BatchedPublicTransitRule(Class<T> homeStationType) {
+    public BatchedPublicTransitRule(Class<T> homeStationType, boolean expectResetByTest) {
         mHomeStationType = homeStationType;
+        mExpectResetByTest = expectResetByTest;
     }
 
     @Override
@@ -41,7 +45,10 @@
                     TransitAsserts.assertCurrentStationType(
                             mHomeStationType, "beginning of test", true);
                     base.evaluate();
-                    TransitAsserts.assertCurrentStationType(mHomeStationType, "end of test", false);
+                    if (mExpectResetByTest) {
+                        TransitAsserts.assertCurrentStationType(
+                                mHomeStationType, "end of test", false);
+                    }
                 } finally {
                     if (testName != null) {
                         TrafficControl.onTestFinished(testName);
diff --git a/base/threading/platform_thread_fuchsia.cc b/base/threading/platform_thread_fuchsia.cc
index 6c66178..3413446 100644
--- a/base/threading/platform_thread_fuchsia.cc
+++ b/base/threading/platform_thread_fuchsia.cc
@@ -4,15 +4,15 @@
 
 #include "base/threading/platform_thread.h"
 
+#include <fidl/fuchsia.media/cpp/fidl.h>
+#include <lib/fdio/directory.h>
+#include <lib/sys/cpp/component_context.h>
 #include <pthread.h>
 #include <sched.h>
 #include <zircon/syscalls.h>
 
 #include <mutex>
-
-#include <fidl/fuchsia.media/cpp/fidl.h>
-#include <lib/fdio/directory.h>
-#include <lib/sys/cpp/component_context.h>
+#include <string_view>
 
 #include "base/fuchsia/fuchsia_component_connect.h"
 #include "base/fuchsia/fuchsia_logging.h"
@@ -41,7 +41,7 @@
 // that period.
 // TODO(crbug.com/1365682): Migrate to the new fuchsia.scheduler.ProfileProvider
 // API when available.
-void SetThreadRole(StringPiece role_name,
+void SetThreadRole(std::string_view role_name,
                    TimeDelta period = {},
                    float capacity = 0.0f) {
   DCHECK_GE(capacity, 0.0);
diff --git a/base/threading/sequence_bound_unittest.cc b/base/threading/sequence_bound_unittest.cc
index 5d9a718..6b4d360b 100644
--- a/base/threading/sequence_bound_unittest.cc
+++ b/base/threading/sequence_bound_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <functional>
 #include <memory>
+#include <string_view>
 #include <utility>
 
 #include "base/memory/raw_ptr.h"
@@ -30,7 +31,7 @@
  public:
   EventLogger() = default;
 
-  void AddEvent(StringPiece event) {
+  void AddEvent(std::string_view event) {
     AutoLock guard(lock_);
     events_.push_back(std::string(event));
   }
@@ -249,7 +250,7 @@
   }
 
  private:
-  void AddEventIfNeeded(StringPiece event) const {
+  void AddEventIfNeeded(std::string_view event) const {
     if (logger_) {
       logger_->AddEvent(event);
     }
diff --git a/base/threading/thread_checker.cc b/base/threading/thread_checker.cc
index 4baec82..eb3bd1fb 100644
--- a/base/threading/thread_checker.cc
+++ b/base/threading/thread_checker.cc
@@ -7,6 +7,7 @@
 #if DCHECK_IS_ON()
 #include <memory>
 #include <ostream>
+#include <string_view>
 
 #include "base/check.h"
 #include "base/debug/stack_trace.h"
@@ -25,7 +26,7 @@
 
 ScopedValidateThreadChecker::ScopedValidateThreadChecker(
     const ThreadChecker& checker,
-    const StringPiece& msg) {
+    std::string_view msg) {
   std::unique_ptr<debug::StackTrace> bound_at;
   DCHECK(checker.CalledOnValidThread(&bound_at))
       << msg
diff --git a/base/threading/thread_checker.h b/base/threading/thread_checker.h
index e809f04d..650d6b6 100644
--- a/base/threading/thread_checker.h
+++ b/base/threading/thread_checker.h
@@ -5,10 +5,11 @@
 #ifndef BASE_THREADING_THREAD_CHECKER_H_
 #define BASE_THREADING_THREAD_CHECKER_H_
 
+#include <string_view>
+
 #include "base/base_export.h"
 #include "base/dcheck_is_on.h"
 #include "base/macros/uniquify.h"
-#include "base/strings/string_piece.h"
 #include "base/thread_annotations.h"
 #include "base/threading/thread_checker_impl.h"
 
@@ -136,7 +137,7 @@
   explicit ScopedValidateThreadChecker(const ThreadChecker& checker)
       EXCLUSIVE_LOCK_FUNCTION(checker);
   ScopedValidateThreadChecker(const ThreadChecker& checker,
-                              const StringPiece& msg)
+                              std::string_view msg)
       EXCLUSIVE_LOCK_FUNCTION(checker);
 
   ScopedValidateThreadChecker(const ScopedValidateThreadChecker&) = delete;
diff --git a/build/check_gn_headers_whitelist.txt b/build/check_gn_headers_whitelist.txt
index 7ef998d..94990a0 100644
--- a/build/check_gn_headers_whitelist.txt
+++ b/build/check_gn_headers_whitelist.txt
@@ -109,8 +109,6 @@
 ipc/ipc_channel_proxy_unittest_messages.h
 ipc/ipc_message_null_macros.h
 media/audio/audio_logging.h
-media/base/routing_token_callback.h
-media/base/video_renderer_sink.h
 media/cast/common/mod_util.h
 media/cast/net/rtcp/rtcp_session.h
 media/filters/ffmpeg_aac_bitstream_converter.h
diff --git a/build/config/siso/main.star b/build/config/siso/main.star
index 7e07066..d92f789 100644
--- a/build/config/siso/main.star
+++ b/build/config/siso/main.star
@@ -255,21 +255,12 @@
         # symbol_level = 2
         # use_siso = true
         "./obj/content/browser/browser/storage_partition_impl.o",
+        "./obj/third_party/blink/renderer/core/core/local_frame_view.o",
+        "./obj/third_party/blink/renderer/core/core_hot/document.o",
     ]
     if runtime.os == "windows":
         exit137_list = [obj.removesuffix(".o") + ".obj" for obj in exit137_list if obj.startswith("./obj/")]
 
-        # Fallback happens with the following args.gn
-        # (win-build-perf-developer)
-        # is_component_build = true
-        # is_debug = true
-        # symbol_level = 2
-        # use_siso = true
-        exit137_list.extend([
-            "./obj/third_party/blink/renderer/core/core/local_frame_view.obj",
-            "./obj/third_party/blink/renderer/core/core_hot/document.obj",
-        ])
-
     new_rules = []
     for rule in step_config["rules"]:
         if not rule["name"].endswith("/cxx"):
diff --git a/cc/animation/animation_host_unittest.cc b/cc/animation/animation_host_unittest.cc
index 096144a..0defa62 100644
--- a/cc/animation/animation_host_unittest.cc
+++ b/cc/animation/animation_host_unittest.cc
@@ -295,7 +295,6 @@
       transform_node_id, element_id);
 
   ScrollNode scroll_node;
-  scroll_node.scrollable = true;
   // Setup scroll dimention to be 100x100.
   scroll_node.bounds = gfx::Size(200, 200);
   scroll_node.container_bounds = gfx::Size(100, 100);
diff --git a/cc/animation/scroll_timeline_unittest.cc b/cc/animation/scroll_timeline_unittest.cc
index 271c70f..6bd1fe0 100644
--- a/cc/animation/scroll_timeline_unittest.cc
+++ b/cc/animation/scroll_timeline_unittest.cc
@@ -57,7 +57,6 @@
   // Add the scrolling node for the scrolling and link it to the above transform
   // node.
   ScrollNode scroll_node;
-  scroll_node.scrollable = true;
   scroll_node.bounds = content_size;
   scroll_node.container_bounds = container_size;
   scroll_node.element_id = scroller_id;
diff --git a/cc/input/input_handler.cc b/cc/input/input_handler.cc
index 97c17a59..bef3ede 100644
--- a/cc/input/input_handler.cc
+++ b/cc/input/input_handler.cc
@@ -1326,6 +1326,12 @@
 }
 
 ScrollNode* InputHandler::GetNodeToScroll(ScrollNode* node) const {
+  // The root and the secondary root are sentinel nodes and don't contribute to
+  // scrolling.
+  if (node->id <= kSecondaryRootPropertyNodeId) {
+    return nullptr;
+  }
+
   // Blink has a notion of a "root scroller", which is the scroller in a page
   // that is considered to host the main content. Typically this will be the
   // document/LayoutView contents; however, in some situations Blink may choose
@@ -1375,22 +1381,9 @@
     return true;
   }
 
-  ScrollNode* closest_scroll_node = nullptr;
   auto& scroll_tree = GetScrollTree();
-  ScrollNode* scroll_node = scroll_tree.Node(layer_impl->scroll_tree_index());
-  for (; scroll_tree.parent(scroll_node);
-       scroll_node = scroll_tree.parent(scroll_node)) {
-    // TODO(crbug.com/1413877): This is inconsistent with the condition in
-    // LayerTreeImpl::FindLayersUpToFirstScrollableOrOpaqueToHitTest(), and
-    // may be a reason for kFailedHitTest main thread scrolling. Can we change
-    // FindLayersUpToFirstScrollableOrOpaqueToHitTest() not to return
-    // a non-scrollable scroller, or not to check scrollable here? We may also
-    // need to consider overscroll behavior of a non-scrollable scroller.
-    if (scroll_node->scrollable) {
-      closest_scroll_node = GetNodeToScroll(scroll_node);
-      break;
-    }
-  }
+  ScrollNode* closest_scroll_node =
+      GetNodeToScroll(scroll_tree.Node(layer_impl->scroll_tree_index()));
 
   // If there's a scrolling layer, we should also have a closest scroll node,
   // and vice versa. Otherwise, the hit test is not reliable.
@@ -1766,8 +1759,10 @@
       break;
     }
 
-    if (!cur_node->scrollable)
+    if (!cur_node->user_scrollable_horizontal &&
+        !cur_node->user_scrollable_vertical) {
       continue;
+    }
 
     if (!first_scrollable_node) {
       first_scrollable_node = cur_node;
@@ -2024,7 +2019,8 @@
 // Return true if scrollable node for 'ancestor' is the same as 'child' or an
 // ancestor along the scroll tree.
 bool InputHandler::IsScrolledBy(LayerImpl* child, ScrollNode* ancestor) {
-  DCHECK(ancestor && ancestor->scrollable);
+  DCHECK(ancestor && (ancestor->user_scrollable_horizontal ||
+                      ancestor->user_scrollable_vertical));
   if (!child)
     return false;
   DCHECK_EQ(child->layer_tree_impl(), &ActiveTree());
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index f7c54fa..059af99 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -1114,42 +1114,6 @@
   return false;
 }
 
-void Layer::SetUserScrollable(bool horizontal, bool vertical) {
-  DCHECK(IsPropertyChangeAllowed());
-  auto& inputs = EnsureLayerTreeInputs();
-  if (inputs.user_scrollable_horizontal == horizontal &&
-      inputs.user_scrollable_vertical == vertical)
-    return;
-  inputs.user_scrollable_horizontal = horizontal;
-  inputs.user_scrollable_vertical = vertical;
-  if (!IsAttached())
-    return;
-
-  if (scrollable()) {
-    auto& scroll_tree =
-        layer_tree_host()->property_trees()->scroll_tree_mutable();
-    if (auto* scroll_node = scroll_tree.Node(scroll_tree_index_.Read(*this))) {
-      scroll_node->user_scrollable_horizontal = horizontal;
-      scroll_node->user_scrollable_vertical = vertical;
-    } else {
-      SetPropertyTreesNeedRebuild();
-    }
-  }
-
-  SetNeedsCommit();
-}
-
-bool Layer::GetUserScrollableHorizontal() const {
-  // user_scrollable_horizontal is true by default.
-  return !layer_tree_inputs() ||
-         layer_tree_inputs()->user_scrollable_horizontal;
-}
-
-bool Layer::GetUserScrollableVertical() const {
-  // user_scrollable_vertical is true by default.
-  return !layer_tree_inputs() || layer_tree_inputs()->user_scrollable_vertical;
-}
-
 void Layer::SetNonFastScrollableRegion(const Region& region) {
   DCHECK(IsPropertyChangeAllowed());
   const auto& rare_inputs = inputs_.Read(*this).rare_inputs;
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 786e347..b4fbf1cb 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -473,20 +473,7 @@
 
   virtual bool IsScrollbarLayerForTesting() const;
 
-  // For layer tree mode only.
-  // Set or get if this layer is able to be scrolled along each axis. These are
-  // independent of the scrollable state, or size of the scrollable area
-  // specified in SetScrollable(), as these may be enabled or disabled
-  // dynamically, while SetScrollable() defines what would be possible if these
-  // are enabled.
-  // When disabled, overscroll elasticity will not be used if the scroll offset
-  // ends up past the maximum range. And when enabled, with overlay scrollbars,
-  // the scrollbars will be shown when the scroll offset changes if these are
-  // set to true.
-  void SetUserScrollable(bool horizontal, bool vertical);
-  bool GetUserScrollableHorizontal() const;
-  bool GetUserScrollableVertical() const;
-
+  // For layer list mode only.
   // Set or get an area of this layer within which initiating a scroll can not
   // be done from the compositor thread. Within this area, if the user attempts
   // to start a scroll, the events must be sent to the main thread and processed
@@ -1044,9 +1031,6 @@
     // surface on itself if possible.
     bool is_fast_rounded_corner : 1 = false;
 
-    bool user_scrollable_horizontal : 1 = true;
-    bool user_scrollable_vertical : 1 = true;
-
     bool trilinear_filtering : 1 = false;
 
     bool hide_layer_and_subtree : 1 = false;
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 36de9e2b..f5d9d5ed 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -300,7 +300,8 @@
 
   const auto* scroll_node = GetScrollTree().FindNodeFromElementId(element_id());
   bool was_scrollable = scrollable_;
-  scrollable_ = scroll_node && scroll_node->scrollable;
+  scrollable_ = scroll_node && (scroll_node->user_scrollable_horizontal ||
+                                scroll_node->user_scrollable_vertical);
   if (was_scrollable == scrollable_) {
     if (!scrollable_)
       return;
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index a181ad31..ee95b28 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -1118,8 +1118,6 @@
   EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(
       test_layer->SetScrollable(gfx::Size(1, 1)));
   EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(
-      test_layer->SetUserScrollable(true, false));
-  EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(
       test_layer->SetScrollOffset(gfx::PointF(10, 10)));
   EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(
       test_layer->SetNonFastScrollableRegion(Region(gfx::Rect(1, 1, 2, 2))));
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index a51ff5a0..895d5f5 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -465,20 +465,23 @@
 
 TEST_F(ScrollbarLayerTest, UpdatePropertiesOfScrollBarWhenThumbRemoved) {
   scoped_refptr<Layer> root_layer = Layer::Create();
+  scoped_refptr<Layer> scroll_layer = Layer::Create();
   scoped_refptr<Layer> content_layer = Layer::Create();
   scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
-      FakePaintedScrollbarLayer::Create(false, true, root_layer->element_id());
+      FakePaintedScrollbarLayer::Create(false, true,
+                                        scroll_layer->element_id());
 
   // Give the root layer a size that will result in MaxScrollOffset = (80, 0).
-  root_layer->SetScrollable(gfx::Size(20, 50));
-  root_layer->SetBounds(gfx::Size(100, 50));
+  scroll_layer->SetScrollable(gfx::Size(20, 50));
+  scroll_layer->SetBounds(gfx::Size(100, 50));
   content_layer->SetBounds(gfx::Size(100, 50));
 
   layer_tree_host_->SetRootLayer(root_layer);
-  root_layer->AddChild(content_layer);
-  root_layer->AddChild(scrollbar_layer);
+  root_layer->AddChild(scroll_layer);
+  scroll_layer->AddChild(content_layer);
+  scroll_layer->AddChild(scrollbar_layer);
 
-  root_layer->SetScrollOffset(gfx::PointF(0, 0));
+  scroll_layer->SetScrollOffset(gfx::PointF(0, 0));
   scrollbar_layer->SetBounds(gfx::Size(70, 10));
 
   // The track_rect should be relative to the scrollbar's origin.
@@ -502,21 +505,24 @@
 
 TEST_F(ScrollbarLayerTest, ThumbRect) {
   scoped_refptr<Layer> root_layer = Layer::Create();
-  root_layer->SetElementId(LayerIdToElementIdForTesting(root_layer->id()));
+  scoped_refptr<Layer> scroll_layer = Layer::Create();
+  scroll_layer->SetElementId(LayerIdToElementIdForTesting(scroll_layer->id()));
   scoped_refptr<Layer> content_layer = Layer::Create();
   scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
-      FakePaintedScrollbarLayer::Create(false, true, root_layer->element_id());
+      FakePaintedScrollbarLayer::Create(false, true,
+                                        scroll_layer->element_id());
 
-  // Give the root layer a size that will result in MaxScrollOffset = (80, 0).
-  root_layer->SetScrollable(gfx::Size(20, 50));
-  root_layer->SetBounds(gfx::Size(100, 50));
+  // Give the scroll layer a size that will result in MaxScrollOffset = (80, 0).
+  scroll_layer->SetScrollable(gfx::Size(20, 50));
+  scroll_layer->SetBounds(gfx::Size(100, 50));
   content_layer->SetBounds(gfx::Size(100, 50));
 
   layer_tree_host_->SetRootLayer(root_layer);
-  root_layer->AddChild(content_layer);
-  root_layer->AddChild(scrollbar_layer);
+  root_layer->AddChild(scroll_layer);
+  scroll_layer->AddChild(content_layer);
+  scroll_layer->AddChild(scrollbar_layer);
 
-  root_layer->SetScrollOffset(gfx::PointF(0, 0));
+  scroll_layer->SetScrollOffset(gfx::PointF(0, 0));
   scrollbar_layer->SetBounds(gfx::Size(70, 10));
 
   // The track_rect should be relative to the scrollbar's origin.
@@ -535,14 +541,14 @@
             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
 
   // Under-scroll (thumb position should clamp and be unchanged).
-  root_layer->SetScrollOffset(gfx::PointF(-5, 0));
+  scroll_layer->SetScrollOffset(gfx::PointF(-5, 0));
 
   UPDATE_AND_EXTRACT_LAYER_POINTERS();
   EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
 
   // Over-scroll (thumb position should clamp on the far side).
-  root_layer->SetScrollOffset(gfx::PointF(85, 0));
+  scroll_layer->SetScrollOffset(gfx::PointF(85, 0));
   layer_tree_host_->UpdateLayers();
 
   UPDATE_AND_EXTRACT_LAYER_POINTERS();
@@ -576,18 +582,20 @@
 
 TEST_F(ScrollbarLayerTest, ThumbRectForOverlayLeftSideVerticalScrollbar) {
   scoped_refptr<Layer> root_layer = Layer::Create();
+  scoped_refptr<Layer> scroll_layer = Layer::Create();
   // Create an overlay left side vertical scrollbar.
   scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
       FakePaintedScrollbarLayer::Create(false, true,
                                         ScrollbarOrientation::kVertical, true,
-                                        true, root_layer->element_id());
-  root_layer->SetScrollable(gfx::Size(20, 50));
-  root_layer->SetBounds(gfx::Size(50, 100));
+                                        true, scroll_layer->element_id());
+  scroll_layer->SetScrollable(gfx::Size(20, 50));
+  scroll_layer->SetBounds(gfx::Size(50, 100));
 
   layer_tree_host_->SetRootLayer(root_layer);
-  root_layer->AddChild(scrollbar_layer);
+  root_layer->AddChild(scroll_layer);
+  scroll_layer->AddChild(scrollbar_layer);
 
-  root_layer->SetScrollOffset(gfx::PointF(0, 0));
+  scroll_layer->SetScrollOffset(gfx::PointF(0, 0));
   scrollbar_layer->SetBounds(gfx::Size(10, 20));
   scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 10, 20));
   scrollbar_layer->fake_scrollbar()->set_thumb_size(gfx::Size(10, 4));
@@ -913,7 +921,8 @@
   SetupViewport(impl.root_layer(), gfx::Size(), gfx::Size(900, 900));
 
   auto* scroll_layer = impl.OuterViewportScrollLayer();
-  EXPECT_FALSE(GetScrollNode(scroll_layer)->scrollable);
+  EXPECT_FALSE(GetScrollNode(scroll_layer)->user_scrollable_horizontal);
+  EXPECT_FALSE(GetScrollNode(scroll_layer)->user_scrollable_vertical);
 
   const int kTrackStart = 0;
   const int kThumbThickness = 10;
@@ -929,14 +938,15 @@
   GetScrollNode(scroll_layer)->container_bounds = gfx::Size(900, 900);
   scroll_layer->SetBounds(gfx::Size(900, 900));
   scroll_layer->UpdateScrollable();
-  EXPECT_FALSE(GetScrollNode(scroll_layer)->scrollable);
+  EXPECT_FALSE(GetScrollNode(scroll_layer)->user_scrollable_horizontal);
+  EXPECT_FALSE(GetScrollNode(scroll_layer)->user_scrollable_vertical);
   // If the scroll layer is not scrollable, the bounds and the container bounds
   // do not affect scrollbar geometries.
   EXPECT_FALSE(
       impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate());
 
   // Changing scrollable to true should require an update.
-  GetScrollNode(scroll_layer)->scrollable = true;
+  GetScrollNode(scroll_layer)->user_scrollable_horizontal = true;
   scroll_layer->UpdateScrollable();
   EXPECT_TRUE(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate());
   impl.host_impl()->active_tree()->UpdateScrollbarGeometries();
@@ -961,7 +971,7 @@
       impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate());
 
   // Changing scrollable to false should require an update.
-  GetScrollNode(scroll_layer)->scrollable = false;
+  GetScrollNode(scroll_layer)->user_scrollable_horizontal = false;
   scroll_layer->UpdateScrollable();
   EXPECT_TRUE(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate());
   impl.host_impl()->active_tree()->UpdateScrollbarGeometries();
diff --git a/cc/test/property_tree_test_utils.cc b/cc/test/property_tree_test_utils.cc
index 674ebce..159d5714 100644
--- a/cc/test/property_tree_test_utils.cc
+++ b/cc/test/property_tree_test_utils.cc
@@ -153,9 +153,8 @@
   }
   node->bounds = layer->bounds();
   node->container_bounds = scroll_container_bounds;
-  node->scrollable = !scroll_container_bounds.IsEmpty();
-  node->user_scrollable_horizontal = true;
-  node->user_scrollable_vertical = true;
+  node->user_scrollable_horizontal = node->user_scrollable_vertical =
+      !scroll_container_bounds.IsEmpty();
   node->is_composited = true;
 
   DCHECK(layer->has_transform_node());
@@ -347,9 +346,8 @@
 
   node->bounds = bounds;
   node->container_bounds = scroll_container_bounds;
-  node->scrollable = !scroll_container_bounds.IsEmpty();
-  node->user_scrollable_horizontal = true;
-  node->user_scrollable_vertical = true;
+  node->user_scrollable_horizontal = node->user_scrollable_vertical =
+      !scroll_container_bounds.IsEmpty();
   node->is_composited = false;
 
   // Create a matching transform node.
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index b142eeb..7cea6a0 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -1176,13 +1176,12 @@
     switch (layer_tree_host()->SourceFrameNumber()) {
       case 1:
         child_->SetForceRenderSurfaceForTesting(true);
-        // Add a non-fast region to ensure a scroll node is created.
-        child_->SetNonFastScrollableRegion(Region(gfx::Rect(50, 50, 50, 50)));
+        child_->SetScrollable(gfx::Size(100, 100));
         break;
       case 2:
-        child_->SetForceRenderSurfaceForTesting(false);
-        // Remove the non-fast region to ensure a scroll node is removed.
-        child_->SetNonFastScrollableRegion(Region());
+        child_->RemoveFromParent();
+        child_ = Layer::Create();
+        root_->AddChild(child_);
         break;
     }
   }
@@ -3386,7 +3385,6 @@
 
     scroll_layer_->SetBounds(gfx::Size(2 * root_layer->bounds().width(),
                                        2 * root_layer->bounds().height()));
-    scroll_layer_->SetScrollOffset(gfx::PointF());
 
     SetupViewport(root_layer, scroll_layer_, root_layer->bounds());
 
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index 388284d..2bb81a4 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -1539,8 +1539,9 @@
   const ScrollNode* scroll_node = Node(scroll_node_id);
   gfx::SizeF scroll_bounds = this->scroll_bounds(scroll_node_id);
 
-  if (!scroll_node->scrollable || scroll_bounds.IsEmpty())
+  if (scroll_bounds.IsEmpty()) {
     return gfx::PointF();
+  }
 
   const TransformTree& transform_tree = property_trees()->transform_tree();
   float scale_factor = 1.f;
@@ -1630,18 +1631,8 @@
 }
 
 gfx::Transform ScrollTree::ScreenSpaceTransform(int scroll_node_id) const {
-  const ScrollNode* scroll_node = Node(scroll_node_id);
-  const TransformTree& transform_tree = property_trees()->transform_tree();
-  const TransformNode* transform_node =
-      transform_tree.Node(scroll_node->transform_id);
-  gfx::Transform screen_space_transform = gfx::Transform::MakeTranslation(
-      scroll_node->offset_to_transform_parent.x(),
-      scroll_node->offset_to_transform_parent.y());
-  screen_space_transform.PostConcat(
-      transform_tree.ToScreen(transform_node->id));
-  if (scroll_node->should_flatten)
-    screen_space_transform.Flatten();
-  return screen_space_transform;
+  return property_trees()->transform_tree().ToScreen(
+      Node(scroll_node_id)->transform_id);
 }
 
 SyncedScrollOffset* ScrollTree::GetSyncedScrollOffset(ElementId id) {
@@ -1991,7 +1982,6 @@
     adjusted_scroll.set_x(0);
   if (!scroll_node.user_scrollable_vertical)
     adjusted_scroll.set_y(0);
-  DCHECK(scroll_node.scrollable);
   gfx::PointF old_offset = current_scroll_offset(scroll_node.element_id);
   gfx::PointF new_offset =
       ClampScrollOffsetToLimits(old_offset + adjusted_scroll, scroll_node);
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index ce25705a..a466302 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -717,24 +717,21 @@
 
   bool is_root = !layer->parent();
   bool scrollable = layer->scrollable();
-  bool contains_non_fast_scrollable_region =
-      !layer->non_fast_scrollable_region().IsEmpty();
-
-  bool requires_node =
-      is_root || scrollable || contains_non_fast_scrollable_region;
+  CHECK(layer->non_fast_scrollable_region().IsEmpty());
+  bool requires_node = is_root || scrollable;
 
   int node_id;
   if (!requires_node) {
     node_id = parent_id;
     data_for_children->scroll_tree_parent = node_id;
   } else {
+    CHECK(!is_root || !scrollable);
+    CHECK(!is_root || layer->offset_to_transform_parent().IsZero());
     ScrollNode node;
-    node.scrollable = scrollable;
     node.bounds = layer->bounds();
     node.container_bounds = layer->scroll_container_bounds();
-    node.offset_to_transform_parent = layer->offset_to_transform_parent();
-    node.user_scrollable_horizontal = layer->GetUserScrollableHorizontal();
-    node.user_scrollable_vertical = layer->GetUserScrollableVertical();
+    node.user_scrollable_horizontal = node.user_scrollable_vertical =
+        scrollable;
     node.element_id = layer->element_id();
     node.transform_id = data_for_children->transform_tree_parent;
     node.is_composited = true;
@@ -748,10 +745,8 @@
       scroll_tree_->SetElementIdForNodeId(node_id, layer->element_id());
     }
 
-    if (node.scrollable) {
-      scroll_tree_->SetBaseScrollOffset(layer->element_id(),
-                                        layer->scroll_offset());
-    }
+    scroll_tree_->SetBaseScrollOffset(layer->element_id(),
+                                      layer->scroll_offset());
   }
 
   layer->SetScrollTreeIndex(node_id);
diff --git a/cc/trees/scroll_node.cc b/cc/trees/scroll_node.cc
index 5588ab5c..ef2ab20 100644
--- a/cc/trees/scroll_node.cc
+++ b/cc/trees/scroll_node.cc
@@ -24,12 +24,8 @@
 void ScrollNode::AsValueInto(base::trace_event::TracedValue* value) const {
   value->SetInteger("id", id);
   value->SetInteger("parent_id", parent_id);
-  value->SetBoolean("scrollable", scrollable);
   MathUtil::AddToTracedValue("container_bounds", container_bounds, value);
   MathUtil::AddToTracedValue("bounds", bounds, value);
-  MathUtil::AddToTracedValue("offset_to_transform_parent",
-                             offset_to_transform_parent, value);
-  value->SetBoolean("should_flatten", should_flatten);
   value->SetBoolean("user_scrollable_horizontal", user_scrollable_horizontal);
   value->SetBoolean("user_scrollable_vertical", user_scrollable_vertical);
 
diff --git a/cc/trees/scroll_node.h b/cc/trees/scroll_node.h
index 40d07cce..31011b1 100644
--- a/cc/trees/scroll_node.h
+++ b/cc/trees/scroll_node.h
@@ -48,23 +48,14 @@
   // Size of the content that is scrolled within the container bounds.
   gfx::Size bounds;
 
-  // This is used for subtrees that should not be scrolled independently. For
-  // example, when there is a layer that is not scrollable itself but is inside
-  // a scrolling layer.
-  bool scrollable : 1 = false;
   bool max_scroll_offset_affected_by_page_scale : 1 = false;
   bool scrolls_inner_viewport : 1 = false;
   bool scrolls_outer_viewport : 1 = false;
   bool prevent_viewport_scrolling_from_inner : 1 = false;
-  bool should_flatten : 1 = false;
   bool user_scrollable_horizontal : 1 = false;
   bool user_scrollable_vertical : 1 = false;
   bool is_composited : 1 = false;
 
-  // This offset is used when |scrollable| is false and there isn't a transform
-  // node already present that covers this offset. For layer tree mode only.
-  gfx::Vector2dF offset_to_transform_parent;
-
   ElementId element_id;
   int transform_id = kRootPropertyNodeId;
 
diff --git a/chrome/android/baseline_profiles/profile.txt b/chrome/android/baseline_profiles/profile.txt
index 13e4eb87..d524aba 100644
--- a/chrome/android/baseline_profiles/profile.txt
+++ b/chrome/android/baseline_profiles/profile.txt
@@ -3167,7 +3167,6 @@
 HSPLorg/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel;->getBarHeight()F
 HSPLorg/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel;->onActivityStateChange(Landroid/app/Activity;I)V
 HSPLorg/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel;->setManagementDelegate(Lorg/chromium/chrome/browser/contextualsearch/ContextualSearchManager;)V
-Lorg/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelInterface;
 Lorg/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelMetrics;
 HSPLorg/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelMetrics;-><init>()V
 Lorg/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator;
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index fcffa30..dde4653 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -337,12 +337,9 @@
   "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchContextControl.java",
   "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchImageControl.java",
   "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java",
-  "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelCoordinator.java",
-  "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelInterface.java",
   "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelMetrics.java",
   "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPromoControl.java",
   "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchQuickActionControl.java",
-  "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchSheetContent.java",
   "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchTermControl.java",
   "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/NoSystemGestureFrameLayout.java",
   "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/RelatedSearchesControl.java",
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
index ff5bb421..5e721122 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
@@ -1049,9 +1049,7 @@
             if (mIsNativeInitialized) mLogoCoordinator.initWithNative();
         }
         if (mLogoCoordinator != null) {
-            boolean isShowingHomepage = isHomepageShown();
-            mLogoCoordinator.updateVisibilityAndMaybeCleanUp(
-                    isShowingHomepage && isVisible, !isShowingHomepage, false);
+            mLogoCoordinator.updateVisibility(false);
         }
     }
 
@@ -1201,14 +1199,7 @@
         }
 
         mLogoCoordinator =
-                new LogoCoordinator(
-                        mContext,
-                        logoClickedCallback,
-                        logoView,
-                        true,
-                        null,
-                        isHomepageShown(),
-                        this);
+                new LogoCoordinator(mContext, logoClickedCallback, logoView, true, null, this);
         return mLogoCoordinator;
     }
 
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java
index 70ad14e..cc39286a7 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java
@@ -142,8 +142,7 @@
     private ImageView mShadowImageView;
     private int mShadowTopOffset;
     private TabListOnScrollListener mScrollListener;
-    // It is null when gts-tab animation is disabled or switching from Start surface to GTS.
-    @Nullable private RecyclerView.ItemAnimator mOriginalAnimator;
+    private RecyclerView.ItemAnimator mOriginalAnimator;
     // Null unless item animations are disabled.
     @Nullable private RecyclerView.ItemAnimator mDisabledAnimatorHolder;
     // Null if there is no runnable to execute on the next layout.
@@ -300,12 +299,7 @@
                         mSuppressCapture = true;
                         mListener.finishedShowing();
                         // Restore the original value.
-                        // TODO(crbug.com/1315676): Remove the null check after decoupling Start
-                        // surface layout and grid tab switcher layout.
-                        if (mOriginalAnimator != null) {
-                            setItemAnimator(mOriginalAnimator);
-                            mOriginalAnimator = null;
-                        }
+                        setItemAnimator(mOriginalAnimator);
                         setShadowVisibility(computeVerticalScrollOffset() > 0);
                         if (mDynamicView != null) {
                             unregisterDynamicView();
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPanePublicTransitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPanePublicTransitTest.java
index cb596cd..8b1cb93 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPanePublicTransitTest.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPanePublicTransitTest.java
@@ -53,7 +53,7 @@
 public class TabSwitcherPanePublicTransitTest {
     @Rule
     public BatchedPublicTransitRule<PageStation> mBatchedRule =
-            new BatchedPublicTransitRule<>(PageStation.class);
+            new BatchedPublicTransitRule<>(PageStation.class, /* expectResetByTest= */ true);
 
     @ClassRule
     public static ChromeTabbedActivityTestRule sActivityTestRule =
diff --git a/chrome/android/java/res/values/values.xml b/chrome/android/java/res/values/values.xml
index e6246c04..ad588b4 100644
--- a/chrome/android/java/res/values/values.xml
+++ b/chrome/android/java/res/values/values.xml
@@ -26,9 +26,6 @@
     <integer name="download_infobar_bar_fill_in_delay">400</integer>
     <integer name="download_infobar_bar_fill_out_delay">200</integer>
 
-    <!-- Contextual Search -->
-    <item name="contextual_search_sheet_full_height_fraction" format="float" type="dimen">0.95</item>
-
     <!-- Revamped Incognito NTP -->
     <integer name="descriptions_weight">1</integer>
 </resources>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
index f66e725..9458440 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
@@ -6,7 +6,6 @@
 
 import android.app.Activity;
 import android.content.Context;
-import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.ColorDrawable;
 import android.view.ViewGroup;
@@ -49,10 +48,10 @@
 import java.util.List;
 
 /**
- * Controls the Contextual Search Panel, primarily the Bar - the
- * {@link ContextualSearchBarControl} - and the content area that shows the Search Result.
+ * Controls the Contextual Search Panel, primarily the Bar - the {@link ContextualSearchBarControl}
+ * - and the content area that shows the Search Result.
  */
-public class ContextualSearchPanel extends OverlayPanel implements ContextualSearchPanelInterface {
+public class ContextualSearchPanel extends OverlayPanel {
     /** Allows controls that appear in this panel to call back with requests or notifications. */
     interface ContextualSearchPanelSectionHost {
         /** Returns the current Y position of the panel section. */
@@ -223,9 +222,9 @@
 
     /**
      * Sets the {@code ContextualSearchManagementDelegate} associated with this panel.
+     *
      * @param delegate The {@code ContextualSearchManagementDelegate}.
      */
-    @Override
     public void setManagementDelegate(ContextualSearchManagementDelegate delegate) {
         if (mManagementDelegate != delegate) {
             mManagementDelegate = delegate;
@@ -237,9 +236,9 @@
 
     /**
      * Notifies that the preference state has changed.
+     *
      * @param isEnabled Whether the feature is enabled.
      */
-    @Override
     public void onContextualSearchPrefChanged(boolean isEnabled) {
         if (!isShowing()) return;
 
@@ -521,7 +520,6 @@
     // ============================================================================================
 
     /** Notify the panel that the content was seen. */
-    @Override
     public void setWasSearchContentViewSeen() {
         mPanelMetrics.setWasSearchContentViewSeen();
     }
@@ -529,7 +527,6 @@
     /**
      * @param isActive Whether the promo is active.
      */
-    @Override
     public void setIsPromoActive(boolean isActive) {
         if (isActive) {
             getPromoControl().show();
@@ -540,7 +537,6 @@
         mPanelMetrics.setIsPromoActive(isActive);
     }
 
-    @Override
     public void clearRelatedSearches() {
         getRelatedSearchesInBarControl().hide();
     }
@@ -557,9 +553,9 @@
 
     /**
      * Maximizes the Contextual Search Panel, then promotes it to a regular Tab.
+     *
      * @param reason The {@code StateChangeReason} behind the maximization and promotion to tab.
      */
-    @Override
     public void maximizePanelThenPromoteToTab(@StateChangeReason int reason) {
         mShouldPromoteToTabAfterMaximizing = true;
         super.maximizePanel(reason);
@@ -610,28 +606,27 @@
     }
 
     /** Gets whether a touch on the content view has been done yet or not. */
-    @Override
     public boolean didTouchContent() {
         return mHasContentBeenTouched;
     }
 
     /**
-     * Sets the search term to display in the SearchBar.
-     * This should be called when the search term is set without search term resolution.
+     * Sets the search term to display in the SearchBar. This should be called when the search term
+     * is set without search term resolution.
+     *
      * @param searchTerm The string that represents the search term.
      */
-    @Override
     public void setSearchTerm(String searchTerm) {
         setSearchTerm(searchTerm, null);
     }
 
     /**
-     * Sets the search term to display in the SearchBar.
-     * This should be called when the search term is set after search term resolution completed.
+     * Sets the search term to display in the SearchBar. This should be called when the search term
+     * is set after search term resolution completed.
+     *
      * @param searchTerm The string that represents the search term.
      * @param pronunciation A string for the pronunciation when a Definition is shown.
      */
-    @Override
     public void setSearchTerm(String searchTerm, @Nullable String pronunciation) {
         getImageControl().hideCustomImage(true);
         getSearchBarControl().setSearchTerm(searchTerm, pronunciation);
@@ -642,10 +637,10 @@
 
     /**
      * Sets the search context details to display in the SearchBar.
+     *
      * @param selection The portion of the context that represents the user's selection.
      * @param end The portion of the context from the selection to its end.
      */
-    @Override
     public void setContextDetails(String selection, String end) {
         getImageControl().hideCustomImage(true);
         getSearchBarControl().setContextDetails(selection, end);
@@ -655,17 +650,16 @@
     }
 
     /**
-     * Sets the caption to display in the SearchBar.
-     * When the caption is displayed, the Search Term is pushed up and the caption shows below.
+     * Sets the caption to display in the SearchBar. When the caption is displayed, the Search Term
+     * is pushed up and the caption shows below.
+     *
      * @param caption The string to show in as the caption.
      */
-    @Override
     public void setCaption(String caption) {
         getSearchBarControl().setCaption(caption);
     }
 
     /** Ensures that we have a Caption to display in the SearchBar. */
-    @Override
     public void ensureCaption() {
         if (getSearchBarControl().hasCaption()) return;
         getSearchBarControl()
@@ -675,23 +669,22 @@
     }
 
     /** Hides the caption. */
-    @Override
     public void hideCaption() {
         getSearchBarControl().hideCaption();
     }
 
     /**
      * Handles showing the resolved search term in the SearchBar.
+     *
      * @param searchTerm The string that represents the search term.
      * @param thumbnailUrl The URL of the thumbnail to display.
      * @param quickActionUri The URI for the intent associated with the quick action.
      * @param quickActionCategory The {@code QuickActionCategory} for the quick action.
-     * @param cardTagEnum The {@link CardTag} that the server returned if there was a card,
-     *        or {@code 0}.
+     * @param cardTagEnum The {@link CardTag} that the server returned if there was a card, or
+     *     {@code 0}.
      * @param relatedSearchesInBar Related Searches suggestions to be displayed in the Bar.
      */
     @VisibleForTesting
-    @Override
     public void onSearchTermResolved(
             String searchTerm,
             String thumbnailUrl,
@@ -711,16 +704,16 @@
 
     /**
      * Handles showing the resolved search term in the SearchBar.
+     *
      * @param searchTerm The string that represents the search term.
      * @param pronunciation A string for the pronunciation when a Definition is shown.
      * @param thumbnailUrl The URL of the thumbnail to display.
      * @param quickActionUri The URI for the intent associated with the quick action.
      * @param quickActionCategory The {@code QuickActionCategory} for the quick action.
-     * @param cardTagEnum The {@link CardTag} that the server returned if there was a card,
-     *        or {@code 0}.
+     * @param cardTagEnum The {@link CardTag} that the server returned if there was a card, or
+     *     {@code 0}.
      * @param relatedSearchesInBar Related Searches suggestions to be displayed in the Bar.
      */
-    @Override
     public void onSearchTermResolved(
             String searchTerm,
             @Nullable String pronunciation,
@@ -753,28 +746,8 @@
     }
 
     /**
-     * Calculates the position of the Contextual Search panel on the screen.
-     * @return A {@link Rect} object that represents the Contextual Search panel's position in
-     *         the screen, in pixels.
+     * @return The padding used for each side of the button in the Bar.
      */
-    @Override
-    public Rect getPanelRect() {
-        int[] contentLocationInWindow = new int[2];
-        mActivity.findViewById(android.R.id.content).getLocationInWindow(contentLocationInWindow);
-        int leftPadding = contentLocationInWindow[0];
-        int topPadding = contentLocationInWindow[1];
-
-        // getOffsetX() and getOffsetY() return the position of the panel relative to the activity,
-        // therefore leftPadding and topPadding are added to get the position in the screen.
-        int left = (int) (getOffsetX() / mPxToDp) + leftPadding;
-        int top = (int) (getOffsetY() / mPxToDp) + topPadding;
-        int bottom = top + (int) (getBarHeight() / mPxToDp);
-        int right = left + (int) (getWidth() / mPxToDp);
-
-        return new Rect(left, top, right, bottom);
-    }
-
-    /** @return The padding used for each side of the button in the Bar. */
     public float getButtonPaddingDps() {
         return mButtonPaddingDps;
     }
@@ -788,13 +761,11 @@
     /**
      * @return The {@link ContextualSearchPanelMetrics}.
      */
-    @Override
     public ContextualSearchPanelMetrics getPanelMetrics() {
         return mPanelMetrics;
     }
 
     /** Sets that the contextual search involved the promo. */
-    @Override
     public void setDidSearchInvolvePromo() {
         mPanelMetrics.setDidSearchInvolvePromo();
     }
@@ -933,9 +904,9 @@
 
     /**
      * Updates the coordinate of the existing selection.
+     *
      * @param y The y coordinate of the selection in pixels.
      */
-    @Override
     public void updateBasePageSelectionYPx(float y) {
         mBasePageSelectionYPx = y;
     }
@@ -965,7 +936,6 @@
      * Creates the ContextualSearchBarControl, if needed. The Views are set to INVISIBLE, because
      * they won't actually be displayed on the screen (their snapshots will be displayed instead).
      */
-    @Override
     public ContextualSearchBarControl getSearchBarControl() {
         // When Edge To Edge is enabled and drawing to the bottom edge, pass in the bottom inset
         // to pad the search bar (specifically, the caption's bottom padding). Use 0 otherwise.
@@ -1029,14 +999,6 @@
     private ContextualSearchPromoHost mPromoHost;
 
     /**
-     * @return Whether the Promo reached a state in which it could be interacted.
-     */
-    @Override
-    public boolean wasPromoInteractive() {
-        return getPromoControl().wasInteractive();
-    }
-
-    /**
      * @return Height of the promo in pixels.
      */
     private float getPromoHeightPx() {
@@ -1208,11 +1170,9 @@
     }
 
     /**
-     * Destroy the current content in the panel.
-     * NOTE(mdjones): This should not be exposed. The only use is in ContextualSearchManager for a
-     * bug related to loading new panel content.
+     * Destroy the current content in the panel. NOTE(mdjones): This should not be exposed. The only
+     * use is in ContextualSearchManager for a bug related to loading new panel content.
      */
-    @Override
     public void destroyContent() {
         super.destroyOverlayPanelContent();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelCoordinator.java
deleted file mode 100644
index e29cd1b2c..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelCoordinator.java
+++ /dev/null
@@ -1,367 +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.
-
-package org.chromium.chrome.browser.compositor.bottombar.contextualsearch;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-import androidx.core.content.res.ResourcesCompat;
-
-import org.chromium.base.supplier.Supplier;
-import org.chromium.base.version_info.VersionInfo;
-import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.PanelState;
-import org.chromium.chrome.browser.content.ContentUtils;
-import org.chromium.chrome.browser.content.WebContentsFactory;
-import org.chromium.chrome.browser.contextualsearch.ContextualSearchManagementDelegate;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.profiles.ProfileManager;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver;
-import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver;
-import org.chromium.components.embedder_support.view.ContentView;
-import org.chromium.components.thinwebview.ThinWebView;
-import org.chromium.components.thinwebview.ThinWebViewConstraints;
-import org.chromium.components.thinwebview.ThinWebViewFactory;
-import org.chromium.content_public.browser.LoadUrlParams;
-import org.chromium.content_public.browser.WebContents;
-import org.chromium.ui.base.IntentRequestTracker;
-import org.chromium.ui.base.ViewAndroidDelegate;
-import org.chromium.ui.base.WindowAndroid;
-
-import java.util.List;
-
-/**
- * Coordinator for the {@link BottomSheet} and {@link ThinWebView} based Contextual Search panel.
- */
-public class ContextualSearchPanelCoordinator implements ContextualSearchPanelInterface {
-    private final Context mContext;
-    private final WindowAndroid mWindowAndroid;
-    private final BottomSheetController mBottomSheetController;
-    private final Supplier<Integer> mTabHeightSupplier;
-    private final int mToolbarHeightPx;
-    private final float mFullHeightFraction;
-
-    private final ContextualSearchPanelMetrics mPanelMetrics;
-    private final IntentRequestTracker mIntentRequestTracker;
-
-    private ContextualSearchSheetContent mSheetContent;
-    private ViewGroup mSheetContentView;
-    private ThinWebView mThinWebView;
-    private WebContents mWebContents;
-    private ContentView mWebContentView;
-    private BottomSheetObserver mBottomSheetObserver;
-
-    private ContextualSearchManagementDelegate mManagementDelegate;
-
-    private boolean mIsActive;
-
-    /**
-     * Construct a {@link ContextualSearchPanelCoordinator}.
-     * @param context The Android {@link Context}.
-     * @param windowAndroid The associated {@link WindowAndroid}.
-     * @param bottomSheetController The {@link BottomSheetController} that will manage the sheet.
-     * @param tabHeightSupplier The {@link Supplier} for the tab height.
-     * @param intentRequestTracker The {@link IntentRequestTracker} of the current activity.
-     */
-    public ContextualSearchPanelCoordinator(
-            Context context,
-            WindowAndroid windowAndroid,
-            BottomSheetController bottomSheetController,
-            Supplier<Integer> tabHeightSupplier,
-            IntentRequestTracker intentRequestTracker) {
-        mContext = context;
-        mWindowAndroid = windowAndroid;
-        mPanelMetrics = new ContextualSearchPanelMetrics();
-        mBottomSheetController = bottomSheetController;
-        mTabHeightSupplier = tabHeightSupplier;
-
-        final Resources resources = mContext.getResources();
-        mToolbarHeightPx =
-                resources.getDimensionPixelSize(
-                        org.chromium.chrome.R.dimen.sheet_tab_toolbar_height);
-        mFullHeightFraction =
-                ResourcesCompat.getFloat(
-                        resources,
-                        org.chromium.chrome.R.dimen.contextual_search_sheet_full_height_fraction);
-        mIntentRequestTracker = intentRequestTracker;
-    }
-
-    private void createWebContents() {
-        final Profile profile = ProfileManager.getLastUsedRegularProfile();
-        mWebContents = WebContentsFactory.createWebContents(profile, false, false);
-        mWebContentView = ContentView.createContentView(mContext, null, mWebContents);
-        final ViewAndroidDelegate delegate =
-                ViewAndroidDelegate.createBasicDelegate(mWebContentView);
-        mWebContents.initialize(
-                VersionInfo.getProductVersion(),
-                delegate,
-                mWebContentView,
-                mWindowAndroid,
-                WebContents.createDefaultInternalsHolder());
-        ContentUtils.setUserAgentOverride(mWebContents, /* overrideInNewTabs= */ false);
-    }
-
-    private void destroyWebContents() {
-        mSheetContent = null;
-
-        if (mWebContents != null) {
-            mWebContents.destroy();
-            mWebContents = null;
-            mWebContentView = null;
-        }
-
-        mBottomSheetController.removeObserver(mBottomSheetObserver);
-    }
-
-    private void createSheetContent() {
-        assert mWebContentView != null;
-        if (mWebContentView.getParent() != null) {
-            ((ViewGroup) mWebContentView.getParent()).removeView(mWebContentView);
-        }
-
-        final int maxHeight = (int) (mTabHeightSupplier.get() * mFullHeightFraction);
-        mThinWebView =
-                ThinWebViewFactory.create(
-                        mContext, new ThinWebViewConstraints(), mIntentRequestTracker);
-        mThinWebView
-                .getView()
-                .setLayoutParams(
-                        new FrameLayout.LayoutParams(
-                                ViewGroup.LayoutParams.MATCH_PARENT, maxHeight - mToolbarHeightPx));
-        mThinWebView.attachWebContents(mWebContents, mWebContentView, null);
-
-        mSheetContentView = new FrameLayout(mContext);
-        mSheetContentView.addView(mThinWebView.getView());
-        mSheetContentView.setPadding(0, mToolbarHeightPx, 0, 0);
-        mSheetContent = new ContextualSearchSheetContent(mSheetContentView, mFullHeightFraction);
-    }
-
-    // region ContextualSearchPanelInterface implementation
-    // ---------------------------------------------------------------------------------------------
-
-    @Override
-    public void destroy() {}
-
-    @Override
-    public boolean didTouchContent() {
-        return false;
-    }
-
-    @Override
-    public void setIsPromoActive(boolean show) {}
-
-    @Override
-    public boolean wasPromoInteractive() {
-        return false;
-    }
-
-    @Override
-    public void destroyContent() {}
-
-    @Override
-    public void setSearchTerm(String searchTerm) {}
-
-    @Override
-    public void setSearchTerm(String searchTerm, @Nullable String pronunciation) {}
-
-    @Override
-    public void setDidSearchInvolvePromo() {}
-
-    @VisibleForTesting
-    @Override
-    public void onSearchTermResolved(
-            String searchTerm,
-            String thumbnailUrl,
-            String quickActionUri,
-            int quickActionCategory,
-            int cardTagEnum,
-            @Nullable List<String> inBarRelatedSearches) {}
-
-    @Override
-    public void onSearchTermResolved(
-            String searchTerm,
-            @Nullable String pronunciation,
-            String thumbnailUrl,
-            String quickActionUri,
-            int quickActionCategory,
-            int cardTagEnum,
-            @Nullable List<String> inBarRelatedSearches) {}
-
-    @Override
-    public void setCaption(String caption) {}
-
-    @Override
-    public void ensureCaption() {}
-
-    @Override
-    public void hideCaption() {}
-
-    @Override
-    public void setManagementDelegate(ContextualSearchManagementDelegate delegate) {
-        mManagementDelegate = delegate;
-    }
-
-    @Override
-    public void onContextualSearchPrefChanged(boolean isEnabled) {}
-
-    @Override
-    public void setWasSearchContentViewSeen() {}
-
-    @Override
-    public void maximizePanelThenPromoteToTab(int reason) {}
-
-    @Override
-    public void updateBasePageSelectionYPx(float y) {}
-
-    @Override
-    public void setContextDetails(String selection, String end) {}
-
-    @Override
-    public ContextualSearchBarControl getSearchBarControl() {
-        return null;
-    }
-
-    @Override
-    public ContextualSearchPanelMetrics getPanelMetrics() {
-        return mPanelMetrics;
-    }
-
-    @Override
-    public Rect getPanelRect() {
-        return null;
-    }
-
-    @Override
-    public void clearRelatedSearches() {}
-
-    @Override
-    public void requestPanelShow(int reason) {
-        if (mWebContents == null) {
-            createWebContents();
-            createSheetContent();
-            mBottomSheetObserver =
-                    new EmptyBottomSheetObserver() {
-                        @Override
-                        public void onSheetOpened(int reason) {
-                            mManagementDelegate
-                                    .getOverlayContentDelegate()
-                                    .onVisibilityChanged(true);
-                        }
-
-                        @Override
-                        public void onSheetStateChanged(int newState, int reason) {
-                            if (newState == SheetState.HIDDEN) {
-                                mIsActive = false;
-                                destroyWebContents();
-                            }
-                        }
-                    };
-            // TODO(sinansahin): It's not guaranteed that we'll be observing the BottomSheet with
-            // the contents we provide. We should probably use the return value from
-            // BottomSheetController#requestShowContent to decide whether we want to observe the
-            // BottomSheet.
-            mBottomSheetController.addObserver(mBottomSheetObserver);
-        }
-
-        mIsActive = true;
-        mBottomSheetController.requestShowContent(mSheetContent, true);
-    }
-
-    @Override
-    public void loadUrlInPanel(String url) {
-        mWebContents.getNavigationController().loadUrl(new LoadUrlParams(url));
-    }
-
-    @Override
-    public void updateBrowserControlsState() {}
-
-    @Override
-    public void updateBrowserControlsState(int current, boolean animate) {}
-
-    @Override
-    public void removeLastHistoryEntry(String historyUrl, long urlTimeMs) {}
-
-    @Override
-    public void onLoadUrlFailed() {}
-
-    @Override
-    public boolean isActive() {
-        return mIsActive;
-    }
-
-    @Override
-    public boolean isContentShowing() {
-        // TODO(sinansahin): Replace with real impl. True for the other methods.
-        return true;
-    }
-
-    @Override
-    public boolean isProcessingPendingNavigation() {
-        return false;
-    }
-
-    @Override
-    public boolean isPeeking() {
-        return mBottomSheetController.getSheetState() == SheetState.PEEK;
-    }
-
-    @Override
-    public WebContents getWebContents() {
-        return mWebContents;
-    }
-
-    @Override
-    public ViewGroup getContainerView() {
-        return null;
-    }
-
-    @Override
-    public void setCanHideAndroidBrowserControls(boolean canHideAndroidBrowserControls) {}
-
-    @Override
-    public boolean isPanelOpened() {
-        return mBottomSheetController.isSheetOpen();
-    }
-
-    @Override
-    public boolean isShowing() {
-        return mBottomSheetController.getCurrentOffset() > 0;
-    }
-
-    @Override
-    public void closePanel(int reason, boolean animate) {}
-
-    @Override
-    public void peekPanel(int reason) {}
-
-    @Override
-    public void expandPanel(int reason) {}
-
-    @Override
-    public void maximizePanel(int reason) {}
-
-    @Override
-    public void showPanel(int reason) {}
-
-    @Override
-    public @PanelState int getPanelState() {
-        return PanelState.UNDEFINED;
-    }
-
-    @Override
-    @VisibleForTesting
-    public boolean getCanHideAndroidBrowserControls() {
-        return false;
-    }
-
-    // ---------------------------------------------------------------------------------------------
-    // endregion
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelInterface.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelInterface.java
deleted file mode 100644
index e7a7a5b..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelInterface.java
+++ /dev/null
@@ -1,135 +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.
-
-package org.chromium.chrome.browser.compositor.bottombar.contextualsearch;
-
-import android.graphics.Rect;
-import android.view.ViewGroup;
-
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-
-import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.PanelState;
-import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason;
-import org.chromium.chrome.browser.contextualsearch.ContextualSearchManagementDelegate;
-import org.chromium.chrome.browser.contextualsearch.ResolvedSearchTerm.CardTag;
-import org.chromium.content_public.browser.WebContents;
-
-import java.util.List;
-
-/**
- * An interface that encapsulates all the methods that {@link ContextualSearchManager} needs to
- * communicate with the {@link ContextualSearchPanel} to make it easier to swap out the
- * {@link OverlayPanel} based implementation.
- */
-public interface ContextualSearchPanelInterface {
-    void destroy();
-
-    /** {@link ContextualSearchPanel} methods */
-    boolean didTouchContent();
-
-    void setIsPromoActive(boolean show);
-
-    boolean wasPromoInteractive();
-
-    void destroyContent();
-
-    void setSearchTerm(String searchTerm);
-
-    void setSearchTerm(String searchTerm, @Nullable String pronunciation);
-
-    void setDidSearchInvolvePromo();
-
-    @VisibleForTesting
-    void onSearchTermResolved(
-            String searchTerm,
-            String thumbnailUrl,
-            String quickActionUri,
-            int quickActionCategory,
-            @CardTag int cardTagEnum,
-            @Nullable List<String> inBarRelatedSearches);
-
-    void onSearchTermResolved(
-            String searchTerm,
-            @Nullable String pronunciation,
-            String thumbnailUrl,
-            String quickActionUri,
-            int quickActionCategory,
-            @CardTag int cardTagEnum,
-            @Nullable List<String> inBarRelatedSearches);
-
-    void setCaption(String caption);
-
-    void ensureCaption();
-
-    void hideCaption();
-
-    void onContextualSearchPrefChanged(boolean isEnabled);
-
-    void setManagementDelegate(ContextualSearchManagementDelegate delegate);
-
-    void setWasSearchContentViewSeen();
-
-    void maximizePanelThenPromoteToTab(@StateChangeReason int reason);
-
-    void updateBasePageSelectionYPx(float y);
-
-    void setContextDetails(String selection, String end);
-
-    ContextualSearchBarControl getSearchBarControl();
-
-    ContextualSearchPanelMetrics getPanelMetrics();
-
-    Rect getPanelRect();
-
-    void clearRelatedSearches();
-
-    /** {@link OverlayPanel} methods */
-    void requestPanelShow(@StateChangeReason int reason);
-
-    void loadUrlInPanel(String url);
-
-    void updateBrowserControlsState();
-
-    void updateBrowserControlsState(int current, boolean animate);
-
-    void removeLastHistoryEntry(String historyUrl, long urlTimeMs);
-
-    void onLoadUrlFailed();
-
-    boolean isActive();
-
-    boolean isContentShowing();
-
-    boolean isProcessingPendingNavigation();
-
-    boolean isPeeking();
-
-    WebContents getWebContents();
-
-    ViewGroup getContainerView();
-
-    void setCanHideAndroidBrowserControls(boolean canHideAndroidBrowserControls);
-
-    /** {@link OverlayPanelBase} methods */
-    boolean isPanelOpened();
-
-    boolean isShowing();
-
-    void closePanel(@StateChangeReason int reason, boolean animate);
-
-    void peekPanel(@StateChangeReason int reason);
-
-    void expandPanel(@StateChangeReason int reason);
-
-    void maximizePanel(@StateChangeReason int reason);
-
-    void showPanel(@StateChangeReason int reason);
-
-    @PanelState
-    int getPanelState();
-
-    @VisibleForTesting
-    boolean getCanHideAndroidBrowserControls();
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchSheetContent.java
deleted file mode 100644
index 5351864..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchSheetContent.java
+++ /dev/null
@@ -1,86 +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.
-
-package org.chromium.chrome.browser.compositor.bottombar.contextualsearch;
-
-import android.view.View;
-
-import org.chromium.chrome.R;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
-
-class ContextualSearchSheetContent implements BottomSheetContent {
-    private final View mView;
-    private final float mFullHeightFraction;
-
-    /**
-     * Construct the coordinator.
-     * @param view The view for the bottom sheet.
-     * @param fullHeightFraction The fraction for the height the content when fully expanded.
-     */
-    public ContextualSearchSheetContent(View view, float fullHeightFraction) {
-        mView = view;
-        mFullHeightFraction = fullHeightFraction;
-    }
-
-    // region BottomSheetContent implementation
-    // ---------------------------------------------------------------------------------------------
-
-    @Override
-    public View getContentView() {
-        return mView;
-    }
-
-    @Override
-    public View getToolbarView() {
-        return null;
-    }
-
-    @Override
-    public int getVerticalScrollOffset() {
-        return 0;
-    }
-
-    @Override
-    public void destroy() {}
-
-    @Override
-    public int getPriority() {
-        return ContentPriority.HIGH;
-    }
-
-    @Override
-    public boolean swipeToDismissEnabled() {
-        return true;
-    }
-
-    @Override
-    public float getFullHeightRatio() {
-        return mFullHeightFraction;
-    }
-
-    // TODO(sinansahin): These are the temporary strings borrowed from the Preview Tab to avoid a
-    // Resources$NotFoundException. We can replace them once the real strings are ready.
-    @Override
-    public int getSheetContentDescriptionStringId() {
-        return R.string.ephemeral_tab_sheet_description;
-    }
-
-    @Override
-    public int getSheetHalfHeightAccessibilityStringId() {
-        return R.string.ephemeral_tab_sheet_opened_half;
-    }
-
-    @Override
-    public int getSheetFullHeightAccessibilityStringId() {
-        return R.string.ephemeral_tab_sheet_opened_full;
-    }
-
-    @Override
-    public int getSheetClosedAccessibilityStringId() {
-        return R.string.ephemeral_tab_sheet_closed;
-    }
-
-    // ---------------------------------------------------------------------------------------------
-    // endregion
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagementDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagementDelegate.java
index 733062bc..22e0826 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagementDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagementDelegate.java
@@ -9,7 +9,6 @@
 import org.chromium.chrome.browser.compositor.bottombar.OverlayContentDelegate;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason;
 import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel;
-import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanelInterface;
 import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
 
 /**
@@ -29,13 +28,15 @@
 
     /**
      * Sets the handle to the ContextualSearchPanel.
+     *
      * @param panel The ContextualSearchPanel.
      */
-    void setContextualSearchPanel(ContextualSearchPanelInterface panel);
+    void setContextualSearchPanel(ContextualSearchPanel panel);
 
     /**
-     * Gets whether the device is running in compatibility mode for Contextual Search.
-     * If so, a new tab showing search results should be opened instead of showing the panel.
+     * Gets whether the device is running in compatibility mode for Contextual Search. If so, a new
+     * tab showing search results should be opened instead of showing the panel.
+     *
      * @return whether the device is running in compatibility mode.
      */
     boolean isRunningInCompatibilityMode();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index 95836e1..7c6591c2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -35,8 +35,6 @@
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.PanelState;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason;
 import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel;
-import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanelCoordinator;
-import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanelInterface;
 import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.RelatedSearchesControl;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerImpl;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchInternalStateController.InternalState;
@@ -171,7 +169,7 @@
     private ContextualSearchInternalStateController mInternalStateController;
 
     // The panel.
-    private ContextualSearchPanelInterface mSearchPanel;
+    private ContextualSearchPanel mSearchPanel;
 
     // The native manager associated with this object.
     private long mNativeContextualSearchManagerPtr;
@@ -365,39 +363,24 @@
 
         mLayoutManager = layoutManager;
 
-        ContextualSearchPanelInterface panel;
-        if (ChromeFeatureList.isEnabled(
-                ChromeFeatureList.CONTEXTUAL_SEARCH_THIN_WEB_VIEW_IMPLEMENTATION)) {
-            panel =
-                    new ContextualSearchPanelCoordinator(
-                            mActivity,
-                            mWindowAndroid,
-                            bottomSheetController,
-                            this::getBasePageHeight,
-                            intentRequestTracker);
-        } else {
-            panel =
-                    new ContextualSearchPanel(
-                            mActivity,
-                            mLayoutManager,
-                            mLayoutManager.getOverlayPanelManager(),
-                            mBrowserControlsStateProvider,
-                            mWindowAndroid,
-                            mProfile,
-                            compositorViewHolder,
-                            toolbarHeightDp,
-                            toolbarManager,
-                            activityType,
-                            mTabSupplier,
-                            mEdgeToEdgeControllerSupplier);
-        }
-
+        ContextualSearchPanel panel =
+                new ContextualSearchPanel(
+                        mActivity,
+                        mLayoutManager,
+                        mLayoutManager.getOverlayPanelManager(),
+                        mBrowserControlsStateProvider,
+                        mWindowAndroid,
+                        mProfile,
+                        compositorViewHolder,
+                        toolbarHeightDp,
+                        toolbarManager,
+                        activityType,
+                        mTabSupplier,
+                        mEdgeToEdgeControllerSupplier);
         panel.setManagementDelegate(this);
-        setContextualSearchPanel(panel);
 
-        if (panel instanceof SceneOverlay) {
-            mLayoutManager.addSceneOverlay((SceneOverlay) panel);
-        }
+        setContextualSearchPanel(panel);
+        mLayoutManager.addSceneOverlay((SceneOverlay) panel);
 
         mRedirectHandler = RedirectHandler.create();
 
@@ -433,7 +416,7 @@
     }
 
     @Override
-    public void setContextualSearchPanel(ContextualSearchPanelInterface panel) {
+    public void setContextualSearchPanel(ContextualSearchPanel panel) {
         assert panel != null;
         mSearchPanel = panel;
         mPolicy.setContextualSearchPanel(panel);
@@ -2054,9 +2037,11 @@
         mPolicy = policy;
     }
 
-    /** @return The {@link ContextualSearchPanelInterface}, for testing purposes only. */
+    /**
+     * @return The {@link ContextualSearchPanel}, for testing purposes only.
+     */
     @VisibleForTesting
-    ContextualSearchPanelInterface getContextualSearchPanel() {
+    ContextualSearchPanel getContextualSearchPanel() {
         return mSearchPanel;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
index 6ba24887..0497546 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
@@ -16,7 +16,7 @@
 import org.chromium.base.Log;
 import org.chromium.base.shared_preferences.SharedPreferencesManager;
 import org.chromium.base.version_info.VersionInfo;
-import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanelInterface;
+import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchInternalStateController.InternalState;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchSelectionController.SelectionType;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchUma.ContextualSearchPreference;
@@ -51,7 +51,7 @@
     private final ContextualSearchSelectionController mSelectionController;
     private final RelatedSearchesStamp mRelatedSearchesStamp;
     private ContextualSearchNetworkCommunicator mNetworkCommunicator;
-    private ContextualSearchPanelInterface mSearchPanel;
+    private ContextualSearchPanel mSearchPanel;
 
     // Members used only for testing purposes.
     private boolean mDidOverrideFullyEnabledForTesting;
@@ -75,9 +75,10 @@
 
     /**
      * Sets the handle to the ContextualSearchPanel.
+     *
      * @param panel The ContextualSearchPanel.
      */
-    public void setContextualSearchPanel(ContextualSearchPanelInterface panel) {
+    public void setContextualSearchPanel(ContextualSearchPanel panel) {
         mSearchPanel = panel;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryManager.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryManager.java
index 93355f2..ceafa01 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryManager.java
@@ -294,6 +294,7 @@
             String searchEmptyString = getSearchEmptyString();
             mSelectableListLayout.onStartSearch(searchEmptyString);
             mUmaRecorder.recordSearchHistory();
+            mIsSearching = true;
             return true;
         } else if (item.getItemId() == R.id.info_menu_id) {
             toggleInfoHeaderVisibility();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayoutPublicTransitTest.java b/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayoutPublicTransitTest.java
index 47a74c56..70a24472 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayoutPublicTransitTest.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayoutPublicTransitTest.java
@@ -20,7 +20,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import org.chromium.base.test.transit.BatchedPublicTransitRule;
 import org.chromium.base.test.transit.TransitStation;
 import org.chromium.base.test.transit.Trip;
 import org.chromium.base.test.util.Batch;
@@ -28,11 +27,10 @@
 import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.features.start_surface.StartSurfaceConfiguration;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
-import org.chromium.chrome.test.transit.ChromeTabbedActivityPublicTransitEntryPoints;
+import org.chromium.chrome.test.transit.BlankCTATabInitialStatePublicTransitRule;
 import org.chromium.chrome.test.transit.HubIncognitoTabSwitcherStation;
 import org.chromium.chrome.test.transit.HubTabSwitcherAppMenuFacility;
 import org.chromium.chrome.test.transit.HubTabSwitcherStation;
@@ -40,7 +38,6 @@
 import org.chromium.chrome.test.transit.PageAppMenuFacility;
 import org.chromium.chrome.test.transit.PageStation;
 import org.chromium.chrome.test.util.ChromeApplicationTestUtils;
-import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
 /** Public transit instrumentation/integration test of Hub. */
 @RunWith(ChromeJUnit4ClassRunner.class)
@@ -48,34 +45,30 @@
 @EnableFeatures({ANDROID_HUB})
 @Batch(Batch.PER_CLASS)
 public class HubLayoutPublicTransitTest {
-    @Rule
-    public BatchedPublicTransitRule<PageStation> mBatchedRule =
-            new BatchedPublicTransitRule<>(PageStation.class);
-
     @ClassRule
     public static ChromeTabbedActivityTestRule sActivityTestRule =
             new ChromeTabbedActivityTestRule();
 
-    private ChromeTabbedActivityPublicTransitEntryPoints mTransitEntryPoints =
-            new ChromeTabbedActivityPublicTransitEntryPoints(sActivityTestRule);
+    @Rule
+    public BlankCTATabInitialStatePublicTransitRule mInitialStateRule =
+            new BlankCTATabInitialStatePublicTransitRule(sActivityTestRule);
 
     @Test
     @LargeTest
     public void testEnterAndExitHub() {
-        PageStation page = mTransitEntryPoints.startOnBlankPageBatched(mBatchedRule);
+        PageStation page = mInitialStateRule.startOnBlankPageBatched();
 
         HubTabSwitcherStation tabSwitcher = page.openHub(HubTabSwitcherStation.class);
 
         PageStation previousTab = tabSwitcher.leaveHubToPreviousTabViaBack();
 
         assertFinalDestination(previousTab);
-        assertFinalTabModelState();
     }
 
     @Test
     @LargeTest
     public void testEnterHubAndLeaveViaAppMenuNewTab() {
-        PageStation page = mTransitEntryPoints.startOnBlankPageBatched(mBatchedRule);
+        PageStation page = mInitialStateRule.startOnBlankPageBatched();
 
         HubTabSwitcherStation tabSwitcher = page.openHub(HubTabSwitcherStation.class);
 
@@ -83,18 +76,13 @@
 
         NewTabPageStation newTab = appMenu.openNewTab();
 
-        // Reset to original state for batching.
-        tabSwitcher = newTab.openHub(HubTabSwitcherStation.class);
-        tabSwitcher = tabSwitcher.closeTabAtIndex(1, HubTabSwitcherStation.class);
-        PageStation blankTab = tabSwitcher.selectTabAtIndex(0);
-        assertFinalDestination(blankTab);
-        assertFinalTabModelState();
+        assertFinalDestination(newTab);
     }
 
     @Test
     @LargeTest
     public void testEnterHubAndLeaveViaAppMenuNewIncognitoTab() {
-        PageStation page = mTransitEntryPoints.startOnBlankPageBatched(mBatchedRule);
+        PageStation page = mInitialStateRule.startOnBlankPageBatched();
 
         HubTabSwitcherStation tabSwitcher = page.openHub(HubTabSwitcherStation.class);
 
@@ -102,19 +90,13 @@
 
         NewTabPageStation newIncognitoTab = appMenu.openNewIncognitoTab();
 
-        // Reset to original state for batching.
-        HubIncognitoTabSwitcherStation incognitoTabSwitcher =
-                newIncognitoTab.openHub(HubIncognitoTabSwitcherStation.class);
-        tabSwitcher = incognitoTabSwitcher.closeTabAtIndex(0, HubTabSwitcherStation.class);
-        PageStation blankTab = tabSwitcher.selectTabAtIndex(0);
-        assertFinalDestination(blankTab);
-        assertFinalTabModelState();
+        assertFinalDestination(newIncognitoTab);
     }
 
     @Test
     @LargeTest
     public void testChangeTabSwitcherPanes() {
-        PageStation page = mTransitEntryPoints.startOnBlankPageBatched(mBatchedRule);
+        PageStation page = mInitialStateRule.startOnBlankPageBatched();
 
         PageAppMenuFacility appMenu = page.openAppMenu();
         NewTabPageStation incognitoNewTabPage = appMenu.openNewIncognitoTab();
@@ -129,14 +111,9 @@
         HubTabSwitcherStation tabSwitcher =
                 incognitoTabSwitcher.selectPane(PaneId.TAB_SWITCHER, HubTabSwitcherStation.class);
 
-        // Reset to original state for batching.
-        incognitoTabSwitcher =
-                tabSwitcher.selectPane(
-                        PaneId.INCOGNITO_TAB_SWITCHER, HubIncognitoTabSwitcherStation.class);
-        tabSwitcher = incognitoTabSwitcher.closeTabAtIndex(0, HubTabSwitcherStation.class);
+        // Go back to a PageStation for BlankCTATabInitialStateRule to reset state.
         PageStation blankTab = tabSwitcher.selectTabAtIndex(0);
         assertFinalDestination(blankTab);
-        assertFinalTabModelState();
     }
 
     @Test
@@ -146,7 +123,7 @@
         StartSurfaceConfiguration.START_SURFACE_RETURN_TIME_SECONDS.setForTesting(0);
         StartSurfaceConfiguration.START_SURFACE_RETURN_TIME_ON_TABLET_SECONDS.setForTesting(0);
 
-        PageStation page = mTransitEntryPoints.startOnBlankPageBatched(mBatchedRule);
+        PageStation page = mInitialStateRule.startOnBlankPageBatched();
 
         PageAppMenuFacility appMenu = page.openAppMenu();
         NewTabPageStation newTabPage = appMenu.openNewTab();
@@ -157,12 +134,7 @@
         tabSwitcher = page.openHub(HubTabSwitcherStation.class);
         newTabPage = pauseAndResumeActivity(tabSwitcher);
 
-        // Reset to original state for batching.
-        tabSwitcher = newTabPage.openHub(HubTabSwitcherStation.class);
-        tabSwitcher = tabSwitcher.closeTabAtIndex(1, HubTabSwitcherStation.class);
-        page = tabSwitcher.selectTabAtIndex(0);
-        assertFinalDestination(page);
-        assertFinalTabModelState();
+        assertFinalDestination(newTabPage);
     }
 
     private NewTabPageStation pauseAndResumeActivity(TransitStation currentStation) {
@@ -199,14 +171,4 @@
 
         return destination;
     }
-
-    private void assertFinalTabModelState() {
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    TabModelSelector selector =
-                            sActivityTestRule.getActivity().getTabModelSelector();
-                    assertEquals(1, selector.getModel(false).getCount());
-                    assertEquals(0, selector.getModel(true).getCount());
-                });
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java
index 906dde4..2c4084c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java
@@ -17,6 +17,7 @@
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.base.supplier.Supplier;
+import org.chromium.chrome.R;
 import org.chromium.chrome.browser.app.download.home.DownloadPage;
 import org.chromium.chrome.browser.bookmarks.BookmarkPage;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsMarginSupplier;
@@ -398,7 +399,8 @@
                 tab.getProfile(),
                 activity,
                 url,
-                pdfInfo);
+                pdfInfo,
+                activity.getString(R.string.pdf_transient_tab_title));
     }
 
     /** Simple implementation of NativePageHost backed by a {@link Tab} */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
index 11ea925..0fd83173 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -495,7 +495,6 @@
                         mLogoView,
                         shouldFetchDoodle,
                         onLogoAvailableCallback,
-                        /* isParentSurfaceShown= */ true,
                         /* visibilityObserver= */ null);
         mLogoCoordinator.initWithNative();
         setSearchProviderInfo(searchProviderHasLogo, searchProviderIsGoogle);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
index 7460492..691d6ad 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
@@ -10,6 +10,7 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.text.TextUtils;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -22,6 +23,7 @@
 import org.chromium.base.IntentUtils;
 import org.chromium.base.Log;
 import org.chromium.base.ResettersForTesting;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
@@ -106,6 +108,10 @@
     /* package */ static final String USED_LENS_FROM_SHORTCUTS_WIDGET =
             "QuickActionSearchWidget.LensQuery";
 
+    @VisibleForTesting
+    /* package */ static final String HISTOGRAM_LAUNCHED_WITH_QUERY =
+            "Android.Omnibox.SearchActivity.LaunchedWithQuery";
+
     /** Notified about events happening inside a SearchActivity. */
     public static class SearchActivityDelegate {
         /**
@@ -541,6 +547,11 @@
     }
 
     private void beginQuery() {
+        var query = SearchActivityUtils.getIntentQuery(getIntent());
+
+        RecordHistogram.recordBooleanHistogram(
+                HISTOGRAM_LAUNCHED_WITH_QUERY, !TextUtils.isEmpty(query));
+
         mSearchBox.beginQuery(
                 mIntentOrigin,
                 mSearchType,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchHistogramTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchHistogramTest.java
index ea36a5a..23a4684 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchHistogramTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchHistogramTest.java
@@ -29,10 +29,7 @@
 /** Tests the Contextual Search histograms. */
 // NOTE: Disable online detection so we we'll default to online on test bots with no network.
 @RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({
-    ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
-    "disable-features=" + ChromeFeatureList.CONTEXTUAL_SEARCH_THIN_WEB_VIEW_IMPLEMENTATION
-})
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 @EnableFeatures(ChromeFeatureList.CONTEXTUAL_SEARCH_DISABLE_ONLINE_DETECTION)
 @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
 @Batch(Batch.PER_CLASS)
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInstrumentationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInstrumentationTest.java
index 40e14773f..eb9f539 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInstrumentationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInstrumentationTest.java
@@ -27,10 +27,7 @@
 /** Tests the Contextual Search Manager using instrumentation tests. */
 // NOTE: Disable online detection so we we'll default to online on test bots with no network.
 @RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({
-    ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
-    "disable-features=" + ChromeFeatureList.CONTEXTUAL_SEARCH_THIN_WEB_VIEW_IMPLEMENTATION
-})
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 @EnableFeatures(ChromeFeatureList.CONTEXTUAL_SEARCH_DISABLE_ONLINE_DETECTION)
 @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
 @Batch(Batch.PER_CLASS)
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
index 2d3d1d6..911a3d2 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -95,10 +95,7 @@
 /** Tests the Contextual Search Manager using instrumentation tests. */
 @RunWith(ChromeJUnit4ClassRunner.class)
 // NOTE: Disable online detection so we we'll default to online on test bots with no network.
-@CommandLineFlags.Add({
-    ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
-    "disable-features=" + ChromeFeatureList.CONTEXTUAL_SEARCH_THIN_WEB_VIEW_IMPLEMENTATION
-})
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 @EnableFeatures(ChromeFeatureList.CONTEXTUAL_SEARCH_DISABLE_ONLINE_DETECTION)
 @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
 @Batch(Batch.PER_CLASS)
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchObserverTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchObserverTest.java
index f5503f7f..1c1924bc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchObserverTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchObserverTest.java
@@ -30,10 +30,7 @@
 /** Tests system and application interaction with Contextual Search using instrumentation tests. */
 @RunWith(ChromeJUnit4ClassRunner.class)
 // NOTE: Disable online detection so we we'll default to online on test bots with no network.
-@CommandLineFlags.Add({
-    ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
-    "disable-features=" + ChromeFeatureList.CONTEXTUAL_SEARCH_THIN_WEB_VIEW_IMPLEMENTATION
-})
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 @EnableFeatures(ChromeFeatureList.CONTEXTUAL_SEARCH_DISABLE_ONLINE_DETECTION)
 @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
 @Batch(Batch.PER_CLASS)
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSystemTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSystemTest.java
index 02cfe05..5bc94471 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSystemTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSystemTest.java
@@ -40,10 +40,7 @@
 /** Tests system and application interaction with Contextual Search using instrumentation tests. */
 @RunWith(ChromeJUnit4ClassRunner.class)
 // NOTE: Disable online detection so we we'll default to online on test bots with no network.
-@CommandLineFlags.Add({
-    ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
-    "disable-features=" + ChromeFeatureList.CONTEXTUAL_SEARCH_THIN_WEB_VIEW_IMPLEMENTATION
-})
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 @EnableFeatures(ChromeFeatureList.CONTEXTUAL_SEARCH_DISABLE_ONLINE_DETECTION)
 @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
 @Batch(Batch.PER_CLASS)
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUnbatchedTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUnbatchedTest.java
index ec868de..6e32b78 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUnbatchedTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUnbatchedTest.java
@@ -25,10 +25,7 @@
 /** Tests the Contextual Search Manager using instrumentation tests. */
 // NOTE: Disable online detection so we we'll default to online on test bots with no network.
 @RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({
-    ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
-    "disable-features=" + ChromeFeatureList.CONTEXTUAL_SEARCH_THIN_WEB_VIEW_IMPLEMENTATION
-})
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 @EnableFeatures(ChromeFeatureList.CONTEXTUAL_SEARCH_DISABLE_ONLINE_DETECTION)
 @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
 @DoNotBatch(reason = "testTapWithLanguage is flaky if it is batched https://crbug.com/1105488")
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/FullscreenVideoPictureInPictureControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/FullscreenVideoPictureInPictureControllerTest.java
index fbb02c3..6879de6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/FullscreenVideoPictureInPictureControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/FullscreenVideoPictureInPictureControllerTest.java
@@ -85,6 +85,7 @@
     @Test
     @MediumTest
     @MinAndroidSdkLevel(Build.VERSION_CODES.O)
+    @DisabledTest(message = "https://crbug.com/335305496")
     public void testFullscreenVideoDetectedOnlyWhenPlaying() throws Throwable {
         enterFullscreen();
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuBatchedPTTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuBatchedPTTest.java
index b8b4075..e51ae5bb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuBatchedPTTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuBatchedPTTest.java
@@ -49,7 +49,7 @@
 
     @Rule
     public BatchedPublicTransitRule<PageStation> mBatchedRule =
-            new BatchedPublicTransitRule<>(PageStation.class);
+            new BatchedPublicTransitRule<>(PageStation.class, /* expectResetByTest= */ true);
 
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuWithHubBatchedPTTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuWithHubBatchedPTTest.java
index 9afedd8b..208adf9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuWithHubBatchedPTTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuWithHubBatchedPTTest.java
@@ -50,7 +50,7 @@
 
     @Rule
     public BatchedPublicTransitRule<PageStation> mBatchedRule =
-            new BatchedPublicTransitRule<>(PageStation.class);
+            new BatchedPublicTransitRule<>(PageStation.class, /* expectResetByTest= */ true);
 
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/OWNERS b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/OWNERS
index 2c1b0552..697ea17 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/OWNERS
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/OWNERS
@@ -1,3 +1,3 @@
 file://chrome/browser/ui/android/toolbar/OWNERS
 
-per-file StartSurfaceToolbarMediatorUnitTest.java=file://chrome/android/features/start_surface/OWNERS
+per-file .../StartSurfaceToolbarMediatorUnitTest.java=file://chrome/android/features/start_surface/OWNERS
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java
index 848c6e6..92a8647 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java
@@ -53,7 +53,6 @@
 import org.chromium.base.Callback;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Features;
-import org.chromium.base.test.util.Features.DisableFeatures;
 import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
@@ -523,41 +522,6 @@
     }
 
     @Test
-    @DisableFeatures(ChromeFeatureList.SURFACE_POLISH)
-    public void testLogoLoadOrDestroy() {
-        createMediator(false);
-        assertFalse(mMediator.isLogoVisibleForTesting());
-
-        mMediator.onStartSurfaceStateChanged(true, LayoutType.START_SURFACE);
-        assertTrue(mMediator.isLogoVisibleForTesting());
-
-        mMediator.onStartSurfaceStateChanged(true, LayoutType.TAB_SWITCHER);
-        assertFalse(mMediator.isLogoVisibleForTesting());
-        verify(mLogoBridge).destroy(eq(1L), any());
-
-        mMediator.onStartSurfaceStateChanged(true, LayoutType.START_SURFACE);
-        assertTrue(mMediator.isLogoVisibleForTesting());
-    }
-
-    @Test
-    @EnableFeatures(ChromeFeatureList.SURFACE_POLISH)
-    public void testLogoLoadOrDestroy_SurfacePolishMoveDownLogoDisabled() {
-        StartSurfaceConfiguration.SURFACE_POLISH_MOVE_DOWN_LOGO.setForTesting(false);
-        createMediator(false);
-        assertFalse(mMediator.isLogoVisibleForTesting());
-
-        mMediator.onStartSurfaceStateChanged(true, LayoutType.START_SURFACE);
-        assertTrue(mMediator.isLogoVisibleForTesting());
-
-        mMediator.onStartSurfaceStateChanged(true, LayoutType.TAB_SWITCHER);
-        assertFalse(mMediator.isLogoVisibleForTesting());
-        verify(mLogoBridge).destroy(eq(1L), any());
-
-        mMediator.onStartSurfaceStateChanged(true, LayoutType.START_SURFACE);
-        assertTrue(mMediator.isLogoVisibleForTesting());
-    }
-
-    @Test
     @EnableFeatures(ChromeFeatureList.SURFACE_POLISH)
     public void testNotShowLogo_SurfacePolishMoveDownLogoEnabled() {
         StartSurfaceConfiguration.SURFACE_POLISH_MOVE_DOWN_LOGO.setForTesting(true);
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index e0f407ed..797057c 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -7571,19 +7571,21 @@
       </message>
 
       <!-- About box strings -->
-      <if expr="is_win">
+      <if expr="is_win or is_macosx">
         <message name="IDS_ABOUT_BOX_ERROR_DURING_UPDATE_CHECK" desc="The error label for errors that occurred while checking for updates in the About box.">
           An error occurred while checking for updates: <ph name="ERROR">$1<ex>Unable to contact Google Update</ex></ph>
         </message>
+        <message name="IDS_ABOUT_BOX_GOOGLE_UPDATE_ERROR" desc="An error message from Google Update with details.">
+          <ph name="ERROR">$1<ex>An error message from Google Update.</ex></ph> (error code <ph name="ERROR_CODE">$2<ex>7: 0x80000005</ex></ph>).
+        </message>
+      </if>
+      <if expr="is_win">
         <message name="IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED" desc="The error message for the specific case when we cannot create the Google Update component">
           Update check failed to start (error code <ph name="ERROR">$1<ex>0x80000005</ex></ph>).
         </message>
         <message name="IDS_ABOUT_BOX_EXTERNAL_UPDATE_IS_RUNNING" desc="The external updater is running independently.">
           The updater is currently running. Refresh in a minute to check again.
         </message>
-        <message name="IDS_ABOUT_BOX_GOOGLE_UPDATE_ERROR" desc="An error message from Google Update with details.">
-          <ph name="ERROR">$1<ex>An error message from Google Update.</ex></ph> (error code <ph name="ERROR_CODE">$2<ex>7: 0x80000005</ex></ph>).
-        </message>
       </if>
 
       <!-- Omnibox -->
@@ -7822,9 +7824,6 @@
       <message name="IDS_NTP_CUSTOMIZE_NO_BACKGROUND_LABEL" desc="The label for the 'Default Chrome' tile in the customization menu on the New Tab Page">
         Default Chrome
       </message>
-      <message name="IDS_NTP_CUSTOMIZE_CHROME_COLORS_LABEL" desc="The label for the 'Chrome Colors' tile in the New Tab Page customize chrome side panel, which lists themes of colored default chrome.">
-        Chrome Colors
-      </message>
       <message name="IDS_NTP_CUSTOMIZE_CHROME_CHANGE_THEME_LABEL" desc="The label for the action button for changing Chrome theme in the New Tab Page customize chrome side panel.">
         Change theme
       </message>
@@ -8343,9 +8342,15 @@
         <ph name="BREAK">&lt;br&gt;</ph>
         You can manage settings from the card menu or see more options in Customize Chrome.
       </message>
+      <message name="IDS_NTP_MODULES_TODAY_CALENDAR_HEADER" desc="Header of the Calendar module when showing today's calendar on the NTP." meaning="Header of the calendar module to indicate that the events shown are for today." translateable="false">
+        Today's Calendar
+      </message>
       <message name="IDS_NTP_MODULES_GOOGLE_CALENDAR_TITLE" desc="Title of the Google Calendar module shown in various UIs for Customize Chrome and the NTP." meaning="Title of feature for showing a glimpse of a user's Google Calendar.">
         Google Calendar
       </message>
+      <message name="IDS_NTP_MODULES_OUTLOOK_CALENDAR_TITLE" desc="Title of the Google Calendar module shown in various UIs for Customize Chrome and the NTP." meaning="Title of feature for showing a glimpse of a user's Google Calendar.">
+        Outlook Calendar
+      </message>
       <message name="IDS_NTP_MODULES_PHOTOS_TITLE" desc="Title shown in the header of the photos module.">
         From your Google Photos
       </message>
@@ -11016,7 +11021,7 @@
         Sign in to let Chrome suggest tab groups
       </message>
       <message name="IDS_TAB_ORGANIZATION_IN_PROGRESS_TITLE" desc="The header text for the in progress state in the tab organization UI">
-        Organizing into a tab group…
+        Grouping your tabs…
       </message>
       <message name="IDS_TAB_ORGANIZATION_SUCCESS_TITLE" desc="The header text for the MVP success state in the tab organization UI">
         Tab group suggestion
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_CUSTOMIZE_CHROME_COLORS_LABEL.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_CUSTOMIZE_CHROME_COLORS_LABEL.png.sha1
deleted file mode 100644
index 9633eaf..0000000
--- a/chrome/app/generated_resources_grd/IDS_NTP_CUSTOMIZE_CHROME_COLORS_LABEL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-9cde707b52c6b2b47a020718e301e1092ef375c7
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_MODULES_OUTLOOK_CALENDAR_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_MODULES_OUTLOOK_CALENDAR_TITLE.png.sha1
new file mode 100644
index 0000000..7b01984
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_MODULES_OUTLOOK_CALENDAR_TITLE.png.sha1
@@ -0,0 +1 @@
+838bc3a07a85f153ba78df03f05cb11dbf08063b
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_TAB_ORGANIZATION_IN_PROGRESS_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_TAB_ORGANIZATION_IN_PROGRESS_TITLE.png.sha1
index b3133cb..8d99dfd 100644
--- a/chrome/app/generated_resources_grd/IDS_TAB_ORGANIZATION_IN_PROGRESS_TITLE.png.sha1
+++ b/chrome/app/generated_resources_grd/IDS_TAB_ORGANIZATION_IN_PROGRESS_TITLE.png.sha1
@@ -1 +1 @@
-48f6b91c6dc42f6e2b142baa880569dfe0902392
\ No newline at end of file
+02daf581efea121c5304a6e1c30e7475d6ed05f2
\ No newline at end of file
diff --git a/chrome/app_shim/DEPS b/chrome/app_shim/DEPS
index b5cb133..771ae5d 100644
--- a/chrome/app_shim/DEPS
+++ b/chrome/app_shim/DEPS
@@ -7,6 +7,7 @@
   "+chrome/installer/launcher_support",
   "+chrome/services/mac_notifications",
   "+components/crash/core/app",
+  "+components/metrics",
   "+components/remote_cocoa",
   "+content/public/browser",
   "+mojo/core/embedder",
diff --git a/chrome/app_shim/app_shim_controller.h b/chrome/app_shim/app_shim_controller.h
index fc00432..b873d21 100644
--- a/chrome/app_shim/app_shim_controller.h
+++ b/chrome/app_shim/app_shim_controller.h
@@ -185,6 +185,9 @@
           provider) override;
   void RequestNotificationPermission(
       RequestNotificationPermissionCallback callback) override;
+  void BindChildHistogramFetcherFactory(
+      mojo::PendingReceiver<metrics::mojom::ChildHistogramFetcherFactory>
+          receiver) override;
 
   // mac_notifications::mojom::MacNotificationProvider implementation.
   void BindNotificationService(
diff --git a/chrome/app_shim/app_shim_controller.mm b/chrome/app_shim/app_shim_controller.mm
index fd86d3a..9993e09b 100644
--- a/chrome/app_shim/app_shim_controller.mm
+++ b/chrome/app_shim/app_shim_controller.mm
@@ -22,6 +22,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/field_trial_param_associator.h"
+#include "base/metrics/histogram_macros_local.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
@@ -45,6 +46,7 @@
 #include "chrome/grit/generated_resources.h"
 #import "chrome/services/mac_notifications/mac_notification_service_ns.h"
 #import "chrome/services/mac_notifications/mac_notification_service_un.h"
+#include "components/metrics/child_histogram_fetcher_impl.h"
 #include "components/remote_cocoa/app_shim/application_bridge.h"
 #include "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h"
 #include "components/remote_cocoa/common/application.mojom.h"
@@ -923,5 +925,13 @@
 }
 
 void AppShimController::ApplicationWillTerminate() {
+  // Local histogram to let tests verify that histograms are emitted properly.
+  LOCAL_HISTOGRAM_BOOLEAN("AppShim.WillTerminate", true);
   host_->ApplicationWillTerminate();
 }
+
+void AppShimController::BindChildHistogramFetcherFactory(
+    mojo::PendingReceiver<metrics::mojom::ChildHistogramFetcherFactory>
+        receiver) {
+  metrics::ChildHistogramFetcherFactoryImpl::Create(std::move(receiver));
+}
diff --git a/chrome/app_shim/chrome_main_app_mode_mac.mm b/chrome/app_shim/chrome_main_app_mode_mac.mm
index b8230eab..057c534 100644
--- a/chrome/app_shim/chrome_main_app_mode_mac.mm
+++ b/chrome/app_shim/chrome_main_app_mode_mac.mm
@@ -27,6 +27,7 @@
 #include "base/mac/scoped_sending_event.h"
 #include "base/message_loop/message_pump_apple.h"
 #include "base/message_loop/message_pump_type.h"
+#include "base/metrics/histogram_macros_local.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/strings/sys_string_conversions.h"
@@ -219,6 +220,9 @@
     ChromeContentClient chrome_content_client;
     content::SetContentClient(&chrome_content_client);
 
+    // Local histogram to let tests verify that histograms are emitted properly.
+    LOCAL_HISTOGRAM_BOOLEAN("AppShim.Launched", true);
+
     // Launch the IO thread.
     base::Thread::Options io_thread_options;
     io_thread_options.message_pump_type = base::MessagePumpType::IO;
diff --git a/chrome/browser/apps/app_service/app_install/app_install_navigation_throttle.cc b/chrome/browser/apps/app_service/app_install/app_install_navigation_throttle.cc
index 9ab20afa..1985f287 100644
--- a/chrome/browser/apps/app_service/app_install/app_install_navigation_throttle.cc
+++ b/chrome/browser/apps/app_service/app_install/app_install_navigation_throttle.cc
@@ -67,6 +67,9 @@
   if (base::EqualsCaseInsensitiveASCII(source, "launcher")) {
     return AppInstallSurface::kAppInstallUriLauncher;
   }
+  if (base::EqualsCaseInsensitiveASCII(source, "peripherals")) {
+    return AppInstallSurface::kAppInstallUriPeripherals;
+  }
   return AppInstallSurface::kAppInstallUriUnknown;
 }
 
diff --git a/chrome/browser/apps/app_service/app_install/app_install_service_lacros.cc b/chrome/browser/apps/app_service/app_install/app_install_service_lacros.cc
index c1055db..011a954 100644
--- a/chrome/browser/apps/app_service/app_install/app_install_service_lacros.cc
+++ b/chrome/browser/apps/app_service/app_install/app_install_service_lacros.cc
@@ -38,6 +38,8 @@
         return Surface::kAppInstallUriGetit;
       case AppInstallSurface::kAppInstallUriLauncher:
         return Surface::kAppInstallUriLauncher;
+      case AppInstallSurface::kAppInstallUriPeripherals:
+        return Surface::kAppInstallUriPeripherals;
       case AppInstallSurface::kAppPreloadServiceOem:
       case AppInstallSurface::kAppPreloadServiceDefault:
         // Preloads should be installed from Ash, not Lacros.
diff --git a/chrome/browser/apps/app_service/app_install/app_install_types.cc b/chrome/browser/apps/app_service/app_install/app_install_types.cc
index 797d6a1..1dc49860 100644
--- a/chrome/browser/apps/app_service/app_install/app_install_types.cc
+++ b/chrome/browser/apps/app_service/app_install/app_install_types.cc
@@ -26,6 +26,8 @@
       return out << "AppInstallUriGetit";
     case AppInstallSurface::kAppInstallUriLauncher:
       return out << "AppInstallUriLauncher";
+    case AppInstallSurface::kAppInstallUriPeripherals:
+      return out << "AppInstallUriPeripherals";
   }
 }
 
diff --git a/chrome/browser/apps/app_service/app_install/app_install_types.h b/chrome/browser/apps/app_service/app_install/app_install_types.h
index 9e6b437..63937e9 100644
--- a/chrome/browser/apps/app_service/app_install/app_install_types.h
+++ b/chrome/browser/apps/app_service/app_install/app_install_types.h
@@ -30,6 +30,7 @@
   kAppInstallUriMall,
   kAppInstallUriGetit,
   kAppInstallUriLauncher,
+  kAppInstallUriPeripherals,
 };
 
 std::ostream& operator<<(std::ostream& out, AppInstallSurface surface);
diff --git a/chrome/browser/apps/app_service/app_install/web_app_installer.cc b/chrome/browser/apps/app_service/app_install/web_app_installer.cc
index cae22e4..d5648be 100644
--- a/chrome/browser/apps/app_service/app_install/web_app_installer.cc
+++ b/chrome/browser/apps/app_service/app_install/web_app_installer.cc
@@ -201,6 +201,7 @@
         case AppInstallSurface::kAppInstallUriMall:
         case AppInstallSurface::kAppInstallUriGetit:
         case AppInstallSurface::kAppInstallUriLauncher:
+        case AppInstallSurface::kAppInstallUriPeripherals:
           return crosapi::mojom::PreloadWebAppInstallSource::
               kAlmanacInstallAppUri;
         case AppInstallSurface::kAppPreloadServiceOem:
@@ -225,6 +226,7 @@
         case AppInstallSurface::kAppInstallUriMall:
         case AppInstallSurface::kAppInstallUriGetit:
         case AppInstallSurface::kAppInstallUriLauncher:
+        case AppInstallSurface::kAppInstallUriPeripherals:
           return webapps::WebappInstallSource::ALMANAC_INSTALL_APP_URI;
         case AppInstallSurface::kAppPreloadServiceOem:
           return webapps::WebappInstallSource::PRELOADED_OEM;
diff --git a/chrome/browser/apps/app_service/subscriber_crosapi.cc b/chrome/browser/apps/app_service/subscriber_crosapi.cc
index 7c39823..968cba15 100644
--- a/chrome/browser/apps/app_service/subscriber_crosapi.cc
+++ b/chrome/browser/apps/app_service/subscriber_crosapi.cc
@@ -52,6 +52,8 @@
       return AppInstallSurface::kAppInstallUriGetit;
     case Surface::kAppInstallUriLauncher:
       return AppInstallSurface::kAppInstallUriLauncher;
+    case Surface::kAppInstallUriPeripherals:
+      return AppInstallSurface::kAppInstallUriPeripherals;
   }
 }
 
diff --git a/chrome/browser/apps/app_shim/BUILD.gn b/chrome/browser/apps/app_shim/BUILD.gn
index 46dbc73..368668a6 100644
--- a/chrome/browser/apps/app_shim/BUILD.gn
+++ b/chrome/browser/apps/app_shim/BUILD.gn
@@ -16,8 +16,8 @@
     "app_shim_manager_mac.h",
     "app_shim_termination_manager.cc",
     "app_shim_termination_manager.h",
-    "code_signature_mac.h",
     "code_signature_mac.cc",
+    "code_signature_mac.h",
     "mach_bootstrap_acceptor.cc",
     "mach_bootstrap_acceptor.h",
     "web_app_shim_manager_delegate_mac.cc",
@@ -39,6 +39,7 @@
     "//chrome/common:mojo_bindings",
     "//chrome/common:non_code_constants",
     "//components/crx_file",
+    "//components/metrics:content",
     "//components/remote_cocoa/browser",
     "//components/version_info",
     "//components/webapps/common",
diff --git a/chrome/browser/apps/app_shim/app_shim_host_mac.cc b/chrome/browser/apps/app_shim/app_shim_host_mac.cc
index d2bafd9..977dbff 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_mac.cc
+++ b/chrome/browser/apps/app_shim/app_shim_host_mac.cc
@@ -7,16 +7,24 @@
 #include <utility>
 
 #include "base/apple/foundation_util.h"
+#include "base/check_is_test.h"
 #include "base/files/file_path.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_shared_memory.h"
+#include "base/metrics/persistent_histogram_allocator.h"
 #include "chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h"
 #include "chrome/browser/web_applications/os_integration/web_app_shortcut_mac.h"
 #include "chrome/common/chrome_features.h"
+#include "components/metrics/content/subprocess_metrics_provider.h"
+#include "components/metrics/histogram_controller.h"
+#include "components/metrics/public/mojom/histogram_fetcher.mojom.h"
 #include "components/remote_cocoa/browser/application_host.h"
 #include "components/remote_cocoa/common/application.mojom.h"
 #include "content/public/browser/browser_accessibility_state.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/child_process_host.h"
+#include "content/public/common/process_type.h"
 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
 
 AppShimHost::AppShimHost(AppShimHost::Client* client,
@@ -28,6 +36,8 @@
       app_id_(app_id),
       profile_path_(profile_path),
       uses_remote_views_(uses_remote_views),
+      child_process_host_id_(
+          content::ChildProcessHost::GenerateChildProcessUniqueId()),
       launch_weak_factory_(this) {
   // Create the interfaces used to host windows, so that browser windows may be
   // created before the host process finishes launching.
@@ -44,10 +54,23 @@
     app_shim_->CreateRemoteCocoaApplication(
         std::move(views_application_receiver));
   }
+
+  auto shared_memory = base::HistogramSharedMemory::Create(
+      child_process_host_id_,
+      {content::PROCESS_TYPE_UTILITY, "AppShimMetrics", 512 << 10});
+  if (shared_memory) {
+    histogram_allocator_ = std::move(shared_memory->allocator);
+  }
+  metrics::HistogramController::GetInstance()->SetHistogramMemory(
+      this,
+      shared_memory ? std::move(shared_memory->region)
+                    : base::UnsafeSharedMemoryRegion(),
+      metrics::HistogramController::ChildProcessMode::kGetHistogramData);
 }
 
 AppShimHost::~AppShimHost() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  metrics::HistogramController::GetInstance()->NotifyChildDied(this);
   // If this instance gets destructed while a test is still waiting for it to be
   // connected, we should unblock the test. The shim would have never connected,
   // but unblocking the test at least can cause the test to fail gracefully
@@ -62,6 +85,13 @@
   LOG(ERROR) << "Channel error custom_reason:" << custom_reason
              << " description: " << description;
 
+  if (auto* provider = metrics::SubprocessMetricsProvider::GetInstance()) {
+    provider->DeregisterSubprocessAllocator(child_process_host_id_);
+  } else {
+    // SubprocessMetricsProvider can be null in tests.
+    CHECK_IS_TEST();
+  }
+
   // OnShimProcessDisconnected will delete |this|.
   client_->OnShimProcessDisconnected(this);
 }
@@ -92,8 +122,18 @@
 
   // If the shim process was created, then await either an AppShimHostBootstrap
   // connecting or the process exiting.
-  if (shim_process.IsValid())
+  if (shim_process.IsValid()) {
+    auto* provider = metrics::SubprocessMetricsProvider::GetInstance();
+    if (!provider) {
+      CHECK_IS_TEST();
+    } else if (histogram_allocator_) {
+      provider->RegisterSubprocessAllocator(
+          child_process_host_id_,
+          std::make_unique<base::PersistentHistogramAllocator>(
+              std::move(histogram_allocator_)));
+    }
     return;
+  }
 
   // Shim launch failing is treated the same as the shim launching but
   // terminating before connecting.
@@ -105,6 +145,13 @@
     web_app::ShimLaunchMode launch_mode) {
   DCHECK(!bootstrap_);
 
+  if (auto* provider = metrics::SubprocessMetricsProvider::GetInstance()) {
+    provider->DeregisterSubprocessAllocator(child_process_host_id_);
+  } else {
+    // SubprocessMetricsProvider can be null in tests.
+    CHECK_IS_TEST();
+  }
+
   // If this was a launch without recreating shims, then the launch may have
   // failed because the shims were not present, or because they were out of
   // date. Try again, recreating the shims this time.
@@ -257,3 +304,9 @@
 chrome::mojom::AppShim* AppShimHost::GetAppShim() const {
   return app_shim_.get();
 }
+
+void AppShimHost::BindChildHistogramFetcherFactory(
+    mojo::PendingReceiver<metrics::mojom::ChildHistogramFetcherFactory>
+        factory) {
+  app_shim_->BindChildHistogramFetcherFactory(std::move(factory));
+}
diff --git a/chrome/browser/apps/app_shim/app_shim_host_mac.h b/chrome/browser/apps/app_shim/app_shim_host_mac.h
index e8bab19..f5ae541 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_mac.h
+++ b/chrome/browser/apps/app_shim/app_shim_host_mac.h
@@ -16,6 +16,7 @@
 #include "base/threading/thread_checker.h"
 #include "chrome/browser/web_applications/os_integration/web_app_shortcut_mac.h"
 #include "chrome/common/mac/app_shim.mojom.h"
+#include "components/metrics/histogram_child_process.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -34,7 +35,8 @@
 // This is the counterpart to AppShimController in
 // chrome/app/chrome_main_app_mode_mac.mm. The AppShimHost is owned by the
 // AppShimManager, which implements its client interface.
-class AppShimHost : public chrome::mojom::AppShimHost {
+class AppShimHost : public chrome::mojom::AppShimHost,
+                    public metrics::HistogramChildProcess {
  public:
   // The interface through which the AppShimHost interacts with
   // AppShimManager.
@@ -165,6 +167,11 @@
   void NotificationPermissionStatusChanged(
       mac_notifications::mojom::PermissionStatus status) override;
 
+  // content::HistogramChildProcess:
+  void BindChildHistogramFetcherFactory(
+      mojo::PendingReceiver<metrics::mojom::ChildHistogramFetcherFactory>
+          factory) override;
+
   // Weak, owns |this|.
   const raw_ptr<Client> client_;
 
@@ -186,6 +193,15 @@
   base::FilePath profile_path_;
   const bool uses_remote_views_;
 
+  // Not a system-level PID, rather an ID assigned by content::ChildProcessHost
+  // used to identify this process when registering with
+  // metrics::SubprocessMetricsProvider.
+  const int child_process_host_id_;
+
+  // This holds the histogram allocator to be used for this app shim before it
+  // gets passed to the remote host when it finished launching.
+  std::unique_ptr<base::PersistentMemoryAllocator> histogram_allocator_;
+
   // This class is only ever to be used on the UI thread.
   THREAD_CHECKER(thread_checker_);
 
diff --git a/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc b/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc
index e322a0d..4728909 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc
+++ b/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc
@@ -73,6 +73,9 @@
           provider) override {}
   void RequestNotificationPermission(
       RequestNotificationPermissionCallback callback) override {}
+  void BindChildHistogramFetcherFactory(
+      mojo::PendingReceiver<metrics::mojom::ChildHistogramFetcherFactory>
+          receiver) override {}
 
   bool received_launch_done_result_ = false;
   chrome::mojom::AppShimLaunchResult launch_done_result_ =
diff --git a/chrome/browser/apps/app_shim/app_shim_listener_browsertest.mm b/chrome/browser/apps/app_shim/app_shim_listener_browsertest.mm
index 1f592fa0..ceb76ac9 100644
--- a/chrome/browser/apps/app_shim/app_shim_listener_browsertest.mm
+++ b/chrome/browser/apps/app_shim/app_shim_listener_browsertest.mm
@@ -89,6 +89,9 @@
           provider) override {}
   void RequestNotificationPermission(
       RequestNotificationPermissionCallback callback) override {}
+  void BindChildHistogramFetcherFactory(
+      mojo::PendingReceiver<metrics::mojom::ChildHistogramFetcherFactory>
+          receiver) override {}
 
  private:
   void OnShimConnectedDone(
diff --git a/chrome/browser/apps/app_shim/app_shim_manager_mac_unittest.cc b/chrome/browser/apps/app_shim/app_shim_manager_mac_unittest.cc
index bbeae81..c523f8f 100644
--- a/chrome/browser/apps/app_shim/app_shim_manager_mac_unittest.cc
+++ b/chrome/browser/apps/app_shim/app_shim_manager_mac_unittest.cc
@@ -296,6 +296,9 @@
       RequestNotificationPermissionCallback callback) override {
     request_notification_permission_callback_.SetValue(std::move(callback));
   }
+  void BindChildHistogramFetcherFactory(
+      mojo::PendingReceiver<metrics::mojom::ChildHistogramFetcherFactory>
+          receiver) override {}
 
   // mac_notifications::mojom::MacNotificationProvider:
   void BindNotificationService(
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 46534d8..2568de2 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -143,8 +143,8 @@
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/input/web_mouse_event.h"
 #include "third_party/blink/public/common/switches.h"
-#include "ui/accessibility/ax_event_notification_details.h"
 #include "ui/accessibility/ax_mode.h"
+#include "ui/accessibility/ax_updates_and_events.h"
 #include "ui/display/display_switches.h"
 #include "ui/events/gesture_detection/gesture_configuration.h"
 #include "ui/gfx/geometry/point.h"
@@ -5133,7 +5133,7 @@
   }
 
   void AccessibilityEventReceived(
-      const ui::AXEventNotificationDetails& event_bundle) override {
+      const ui::AXUpdatesAndEvents& event_bundle) override {
     bool found = false;
     int event_node_id = 0;
     for (auto& event : event_bundle.events) {
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index 245bdf9d..45a3c31 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -3885,6 +3885,7 @@
     "//chromeos/ash/services/rollback_network_config/public/mojom",
     "//chromeos/ash/services/secure_channel/public/cpp/client",
     "//chromeos/ash/services/secure_channel/public/mojom",
+    "//chromeos/ash/services/wifi_direct/public/mojom",
     "//chromeos/components/firewall_hole",
     "//chromeos/components/mahi/public/cpp",
     "//chromeos/components/onc",
@@ -4293,6 +4294,7 @@
     "//chromeos/ash/services/quick_pair/public/mojom",
     "//chromeos/ash/services/secure_channel",
     "//chromeos/ash/services/secure_channel/public/cpp/shared",
+    "//chromeos/ash/services/wifi_direct",
     "//chromeos/components/cdm_factory_daemon:cdm_factory_daemon_browser",
     "//chromeos/components/cdm_factory_daemon/mojom",
     "//chromeos/components/certificate_provider",
diff --git a/chrome/browser/ash/PRESUBMIT.py b/chrome/browser/ash/PRESUBMIT.py
new file mode 100644
index 0000000..54ab747
--- /dev/null
+++ b/chrome/browser/ash/PRESUBMIT.py
@@ -0,0 +1,88 @@
+# 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.
+
+PRESUBMIT_VERSION = '2.0.0'
+USE_PYTHON3 = True
+
+def _CheckDepsFileProhibitingChromeExists(input_api, output_api):
+  """Enforce that each top-level directory in //chrome/browser/ash has DEPS file
+  which prohibits //chrome.
+
+  This ensures that any new //chrome dependencies added in this directory are
+  reviewed by a //chrome OWNER. There is an active effort to refactor
+  //chrome/browser/ash to break these dependencies; see b/332804822.
+  """
+  _CHROME_BROWSER_ASH = input_api.os_path.join('chrome', 'browser', 'ash')
+
+  missing_deps_files = set()
+  deps_files_not_prohibiting_chrome = set()
+
+  for f in input_api.AffectedFiles(False):
+    # Path relative to chrome/browser/ash.
+    # Example: For 'chrome/browser/ash/foo/bar/baz.h' => 'foo/bar/baz.h'.
+    relative_path = input_api.os_path.relpath(f.LocalPath(),
+                                              _CHROME_BROWSER_ASH)
+
+    # Split path for this relative path.
+    # Example: For 'foo/bar/baz.h' => ['foo' 'bar/baz.h'].
+    splitPath = relative_path.split(input_api.os_path.sep, 1)
+
+    # If the split path contains 1 or fewer elements, it is not in a
+    # subdirectory (e.g., len == 1 would be a file directly in
+    # //chrome/browser/ash).
+    if len(splitPath) <= 1:
+      continue
+
+    relative_deps_files_path = input_api.os_path.join(splitPath[0], 'DEPS')
+    deps_file_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
+                                            relative_deps_files_path)
+
+    if not input_api.os_path.exists(deps_file_path):
+      missing_deps_files.add(
+          input_api.os_path.join(_CHROME_BROWSER_ASH, relative_deps_files_path))
+      continue
+
+    # If the affected file is not a DEPS file, move onto the next file to check.
+    if f.LocalPath() != deps_file_path:
+      continue
+
+    # If the affected file *is* a DEPS file, confirm that it has a "-chrome"
+    # rule, prohibiting new //chrome dependencies.
+    prohibit_chrome_pattern = input_api.re.compile(r'\"\-chrome\"')
+    if not prohibit_chrome_pattern.search(input_api.ReadFile(deps_file_path)):
+      deps_files_not_prohibiting_chrome.add(
+          input_api.os_path.join(_CHROME_BROWSER_ASH, relative_deps_files_path))
+
+  results = []
+  if missing_deps_files:
+    dir_text = ''
+    for dir in missing_deps_files:
+      dir_text += dir + ', '
+    dir_text = dir_text[:-2]
+    results.append(output_api.PresubmitError(
+        "Subdirectories in //chrome/browser/ash require a DEPS file. Please "
+        "create DEPS files: [%s]. See b/332805865 and "
+        "//tools/chromeos/gen_deps.sh for details." % (dir_text)
+        ))
+
+  if deps_files_not_prohibiting_chrome:
+    deps_text = ''
+    for deps_file in deps_files_not_prohibiting_chrome:
+      deps_text += deps_file + ', '
+    deps_text = deps_text[:-2]
+    results.append(output_api.PresubmitError(
+        "DEPS files in subdirectories of in //chrome/browser/ash must prohibit "
+        "new //chrome dependencies. Please ensure a \"-chrome\" rule is added "
+        "in [%s]. See b/332805865 and //tools/chromeos/gen_deps.sh for "
+        " details." % (deps_text)
+        ))
+
+  return results
+
+def CheckChangeOnUpload(input_api, output_api):
+  return _CheckDepsFileProhibitingChromeExists(input_api, output_api)
+
+
+def CheckChangeOnCommit(input_api, output_api):
+  return _CheckDepsFileProhibitingChromeExists(input_api, output_api)
diff --git a/chrome/browser/ash/PRESUBMIT_test.py b/chrome/browser/ash/PRESUBMIT_test.py
new file mode 100755
index 0000000..df6ab0cd
--- /dev/null
+++ b/chrome/browser/ash/PRESUBMIT_test.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python3
+# 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 os.path
+import sys
+import unittest
+
+import PRESUBMIT
+
+# Switch to src/ directory to import test mocks.
+file_path = os.path.dirname(os.path.abspath(__file__))
+sys.path.insert(0, os.path.join(file_path, '..', '..', '..'))
+from PRESUBMIT_test_mocks import (MockInputApi, MockOutputApi, MockAffectedFile,
+    MockFile)
+
+_CHROME_BROWSER_ASH = os.path.join('chrome', 'browser', 'ash')
+
+class DepsFileProhibitingChromeExistsFileTest(unittest.TestCase):
+  def assertDepsFilesWithErrors(self, input_api, expected_missing_deps_files,
+      expected_deps_files_missing_chrome):
+    # Restore path that was changed to import test mocks above.
+    input_api.presubmit_local_path = _CHROME_BROWSER_ASH
+
+    # Create mock files for all affected files so that os_path.exists() works.
+    input_api.CreateMockFileInPath(
+        [x.LocalPath() for x in input_api.AffectedFiles(include_deletes=True)])
+
+    results = PRESUBMIT._CheckDepsFileProhibitingChromeExists(
+        input_api, MockOutputApi())
+    self.assertTrue(len(results) <= 2)
+
+    missing_deps_file_pattern = input_api.re.compile(
+        r'.*require a DEPS file.*\[(.*)\].*')
+    missing_chrome_rule_pattern = input_api.re.compile(
+        r'.*must prohibit new \/\/chrome dependencies.*\[(.*)\].*')
+
+    missing_deps_files = []
+    deps_files_missing_chrome = []
+
+    for r in results:
+      regex_results = missing_deps_file_pattern.search(r.message)
+      if regex_results:
+        missing_deps_files = regex_results.group(1).split(', ')
+
+      regex_results = missing_chrome_rule_pattern.search(r.message)
+      if missing_chrome_rule_pattern.search(r.message):
+        deps_files_missing_chrome = regex_results.group(1).split(', ')
+
+    self.assertEqual(set(missing_deps_files), set(expected_missing_deps_files))
+    self.assertEqual(set(deps_files_missing_chrome),
+                     set(expected_deps_files_missing_chrome))
+
+  # No files created; no errors expected.
+  def testNoFiles(self):
+    input_api = MockInputApi()
+    self.assertDepsFilesWithErrors(input_api, [], [])
+
+  # Create files in new subdirectories without DEPS files.
+  def testFileInDirectoryWithNoDeps(self):
+    input_api = MockInputApi()
+    input_api.files = [
+      MockAffectedFile(
+          input_api.os_path.join(_CHROME_BROWSER_ASH, 'foo', 'bar.h'), ''),
+      MockAffectedFile(
+          input_api.os_path.join(_CHROME_BROWSER_ASH, 'bar', 'baz.h'), ''),
+    ]
+    self.assertDepsFilesWithErrors(
+        input_api,
+        [
+          input_api.os_path.join(_CHROME_BROWSER_ASH, 'foo', 'DEPS'),
+          input_api.os_path.join(_CHROME_BROWSER_ASH, 'bar', 'DEPS'),
+        ], [])
+
+  # Create files in a new subdirectories with DEPS files not prohibiting
+  # //chrome.
+  def testFileInDirectoryNotProhibitingChrome(self):
+    DEPS_FILE_NOT_PROHIBITING_CHROME = ['include_rules = []']
+
+    input_api = MockInputApi()
+    input_api.files = [
+      MockAffectedFile(
+          input_api.os_path.join(_CHROME_BROWSER_ASH, 'foo', 'bar.h'), ''),
+      MockAffectedFile(
+          input_api.os_path.join(_CHROME_BROWSER_ASH, 'foo', 'DEPS'),
+          DEPS_FILE_NOT_PROHIBITING_CHROME),
+      MockAffectedFile(
+          input_api.os_path.join(_CHROME_BROWSER_ASH, 'bar', 'baz.h'), ''),
+      MockAffectedFile(
+          input_api.os_path.join(_CHROME_BROWSER_ASH, 'bar', 'DEPS'),
+          DEPS_FILE_NOT_PROHIBITING_CHROME),
+    ]
+    self.assertDepsFilesWithErrors(
+        input_api, [],
+        [
+          input_api.os_path.join(_CHROME_BROWSER_ASH, 'foo', 'DEPS'),
+          input_api.os_path.join(_CHROME_BROWSER_ASH, 'bar', 'DEPS'),
+        ])
+
+  # Create files in a new subdirectories with DEPS files prohibiting //chrome.
+  def testFilesWithDepsFilesProhibitingChrome(self):
+    DEPS_FILE_PROHIBITING_CHROME = ['include_rules = [ "-chrome", ]']
+
+    input_api = MockInputApi()
+    input_api.files = [
+      MockAffectedFile(
+          input_api.os_path.join(_CHROME_BROWSER_ASH, 'foo', 'bar.h'), ''),
+      MockAffectedFile(
+          input_api.os_path.join(_CHROME_BROWSER_ASH, 'foo', 'DEPS'),
+          DEPS_FILE_PROHIBITING_CHROME),
+      MockAffectedFile(
+          input_api.os_path.join(_CHROME_BROWSER_ASH, 'bar', 'baz.h'), ''),
+      MockAffectedFile(
+          input_api.os_path.join(_CHROME_BROWSER_ASH, 'bar', 'DEPS'),
+          DEPS_FILE_PROHIBITING_CHROME),
+    ]
+    self.assertDepsFilesWithErrors(input_api, [], [])
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/chrome/browser/ash/accessibility/service/automation_client_impl.cc b/chrome/browser/ash/accessibility/service/automation_client_impl.cc
index cd36466..cc11c9aa 100644
--- a/chrome/browser/ash/accessibility/service/automation_client_impl.cc
+++ b/chrome/browser/ash/accessibility/service/automation_client_impl.cc
@@ -55,7 +55,7 @@
 }
 
 void AutomationClientImpl::DispatchAccessibilityLocationChange(
-    const ui::AXLocationChangeNotificationDetails& details) {
+    const ui::AXLocationChanges& details) {
   ui::AXTreeID tree_id = details.ax_tree_id;
   if (tree_id == ui::AXTreeIDUnknown())
     return;
diff --git a/chrome/browser/ash/accessibility/service/automation_client_impl.h b/chrome/browser/ash/accessibility/service/automation_client_impl.h
index bd9f263..9672d51 100644
--- a/chrome/browser/ash/accessibility/service/automation_client_impl.h
+++ b/chrome/browser/ash/accessibility/service/automation_client_impl.h
@@ -50,7 +50,7 @@
                                    const gfx::Point& mouse_location,
                                    std::vector<ui::AXEvent> events) override;
   void DispatchAccessibilityLocationChange(
-      const ui::AXLocationChangeNotificationDetails& details) override;
+      const ui::AXLocationChanges& details) override;
   void DispatchTreeDestroyedEvent(ui::AXTreeID tree_id) override;
   void DispatchActionResult(const ui::AXActionData& data,
                             bool result,
diff --git a/chrome/browser/ash/app_restore/pine_browsertest.cc b/chrome/browser/ash/app_restore/pine_browsertest.cc
index 675d111..1a87e0a 100644
--- a/chrome/browser/ash/app_restore/pine_browsertest.cc
+++ b/chrome/browser/ash/app_restore/pine_browsertest.cc
@@ -398,30 +398,35 @@
   EXPECT_TRUE(BrowserList::GetInstance()->empty());
 }
 
-IN_PROC_BROWSER_TEST_F(PineBrowserTest, PRE_TabInfo) {
+IN_PROC_BROWSER_TEST_F(PineBrowserTest, PRE_TabInfoWithinLimit) {
   EXPECT_TRUE(BrowserList::GetInstance()->empty());
 
   Browser* browser = CreateBrowser(ProfileManager::GetActiveUserProfile());
   EXPECT_EQ(1u, BrowserList::GetInstance()->size());
 
-  // Create two more urls in addition to the default "about:blank" tab.
-  for (const GURL& url :
-       {GURL("https://www.youtube.com/"), GURL("https://www.google.com/")}) {
-    content::TestNavigationObserver navigation_observer(url);
+  // Create four more urls in addition to the default "about:blank" tab. That
+  // tab will be last in the tab strip.
+  std::vector<const GURL> urls{
+      GURL("https://www.youtube.com/"), GURL("https://www.google.com/"),
+      GURL("https://www.waymo.com/"), GURL("https://x.company/")};
+  for (int i = 0; i < static_cast<int>(urls.size()); ++i) {
+    content::TestNavigationObserver navigation_observer(urls[i]);
     navigation_observer.StartWatchingNewWebContents();
-    chrome::AddTabAt(browser, url, /*index=*/-1,
+    chrome::AddTabAt(browser, urls[i], /*index=*/i,
                      /*foreground=*/false);
     navigation_observer.Wait();
   }
 
+  // Activate the third tab (waymo.com) so it becomes the most recent tab.
+  browser->tab_strip_model()->ActivateTabAt(2);
+
   // Immediate save to full restore file to bypass the 2.5 second throttle.
   AppLaunchInfoSaveWaiter::Wait();
 }
 
-// TODO(http://b/329152636): Update or add to this test to check that the
-// windows and tabs are listed with proper activation order.
-// Verify that the tab info that is sent to ash shell is as expected.
-IN_PROC_BROWSER_TEST_F(PineBrowserTest, TabInfo) {
+// Verify that the tab info that is sent to ash shell is as expected, when the
+// most recent active tab is one of the first five tabs.
+IN_PROC_BROWSER_TEST_F(PineBrowserTest, TabInfoWithinLimit) {
   EXPECT_TRUE(BrowserList::GetInstance()->empty());
 
   // The pine dialog is built based on the values in this data structure.
@@ -430,11 +435,71 @@
   ASSERT_TRUE(pine_contents_data);
   const PineContentsData::AppsInfos& apps_infos =
       pine_contents_data->apps_infos;
+
   ASSERT_EQ(1u, apps_infos.size());
-  ASSERT_EQ(3u, apps_infos[0].tab_urls.size());
-  EXPECT_EQ(GURL(url::kAboutBlankURL), apps_infos[0].tab_urls[0]);
+  ASSERT_EQ(5u, apps_infos[0].tab_urls.size());
+
+  // As it was the most recently activated tab, waymo.com should appear first,
+  // with the other four tabs appearing afterwards in order.
+  EXPECT_EQ(GURL("https://www.waymo.com/"), apps_infos[0].tab_urls[0]);
   EXPECT_EQ(GURL("https://www.youtube.com/"), apps_infos[0].tab_urls[1]);
   EXPECT_EQ(GURL("https://www.google.com/"), apps_infos[0].tab_urls[2]);
+  EXPECT_EQ(GURL("https://x.company/"), apps_infos[0].tab_urls[3]);
+  EXPECT_EQ(GURL(url::kAboutBlankURL), apps_infos[0].tab_urls[4]);
+}
+
+IN_PROC_BROWSER_TEST_F(PineBrowserTest, PRE_TabInfoOutsideLimit) {
+  EXPECT_TRUE(BrowserList::GetInstance()->empty());
+
+  Browser* browser = CreateBrowser(ProfileManager::GetActiveUserProfile());
+  EXPECT_EQ(1u, BrowserList::GetInstance()->size());
+
+  // Create six more urls in addition to the default "about:blank" tab. That tab
+  // will be last in the tab strip.
+  std::vector<const GURL> urls{
+      GURL("https://www.youtube.com/"), GURL("https://www.google.com/"),
+      GURL("https://www.waymo.com/"),   GURL("https://x.company/"),
+      GURL("https://docs.google.com/"), GURL("https://www.chromium.org/")};
+  for (int i = 0; i < static_cast<int>(urls.size()); ++i) {
+    content::TestNavigationObserver navigation_observer(urls[i]);
+    navigation_observer.StartWatchingNewWebContents();
+    chrome::AddTabAt(browser, urls[i], /*index=*/i,
+                     /*foreground=*/false);
+    navigation_observer.Wait();
+  }
+
+  // Activate the sixth tab (chromium.org) so it becomes the most recent tab.
+  browser->tab_strip_model()->ActivateTabAt(5);
+
+  // Immediate save to full restore file to bypass the 2.5 second throttle.
+  AppLaunchInfoSaveWaiter::Wait();
+}
+
+// Verify that the tab info that is sent to ash shell is as expected, when the
+// most recent active tab is outside of the first five tabs.
+IN_PROC_BROWSER_TEST_F(PineBrowserTest, TabInfoOutsideLimit) {
+  EXPECT_TRUE(BrowserList::GetInstance()->empty());
+
+  // The pine dialog is built based on the values in this data structure.
+  const PineContentsData* pine_contents_data =
+      Shell::Get()->pine_controller()->pine_contents_data();
+  ASSERT_TRUE(pine_contents_data);
+  const PineContentsData::AppsInfos& apps_infos =
+      pine_contents_data->apps_infos;
+
+  // Even though there were seven tabs, we limit the number of tab URLs to five
+  // before `PineContentsData` is created.
+  ASSERT_EQ(1u, apps_infos.size());
+  ASSERT_EQ(5u, apps_infos[0].tab_urls.size());
+
+  // As it was the most recently activated tab, chromium.org should appear
+  // first, with the first four tabs in the tab strip appearing afterwards in
+  // order.
+  EXPECT_EQ(GURL("https://www.chromium.org/"), apps_infos[0].tab_urls[0]);
+  EXPECT_EQ(GURL("https://www.youtube.com/"), apps_infos[0].tab_urls[1]);
+  EXPECT_EQ(GURL("https://www.google.com/"), apps_infos[0].tab_urls[2]);
+  EXPECT_EQ(GURL("https://www.waymo.com/"), apps_infos[0].tab_urls[3]);
+  EXPECT_EQ(GURL("https://x.company/"), apps_infos[0].tab_urls[4]);
 }
 
 IN_PROC_BROWSER_TEST_F(PineBrowserTest, PRE_ReenterOverviewPineSession) {
diff --git a/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
index 1ebe9ed..757a26f0 100644
--- a/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
+++ b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
@@ -62,7 +62,7 @@
                                    std::vector<ui::AXEvent> events) override {}
 
   void DispatchAccessibilityLocationChange(
-      const ui::AXLocationChangeNotificationDetails& details) override {}
+      const ui::AXLocationChanges& details) override {}
 
   void DispatchTreeDestroyedEvent(ui::AXTreeID tree_id) override {}
 
diff --git a/chrome/browser/ash/crosapi/automation_ash.cc b/chrome/browser/ash/crosapi/automation_ash.cc
index ef3274d..add71aa1 100644
--- a/chrome/browser/ash/crosapi/automation_ash.cc
+++ b/chrome/browser/ash/crosapi/automation_ash.cc
@@ -62,7 +62,7 @@
     const base::UnguessableToken& tree_id,
     int32_t node_id,
     const ui::AXRelativeBounds& bounds) {
-  ui::AXLocationChangeNotificationDetails details;
+  ui::AXLocationChanges details;
   details.ax_tree_id = ui::AXTreeID::FromToken(tree_id);
   details.id = node_id;
   details.new_location = bounds;
diff --git a/chrome/browser/ash/file_manager/file_manager_jstest.cc b/chrome/browser/ash/file_manager/file_manager_jstest.cc
index 81aa10c..b39589d2 100644
--- a/chrome/browser/ash/file_manager/file_manager_jstest.cc
+++ b/chrome/browser/ash/file_manager/file_manager_jstest.cc
@@ -320,7 +320,8 @@
   RunTestURL("lib/selector_unittest.js");
 }
 
-IN_PROC_BROWSER_TEST_F(FileManagerJsTest, DucksAllEntries) {
+// TODO(crbug.com/335318101): re-enable this test.
+IN_PROC_BROWSER_TEST_F(FileManagerJsTest, DISABLED_DucksAllEntries) {
   RunTestURL("state/ducks/all_entries_unittest.js");
 }
 
diff --git a/chrome/browser/ash/nearby/presence/credential_storage/metrics/credential_storage_metrics.cc b/chrome/browser/ash/nearby/presence/credential_storage/metrics/credential_storage_metrics.cc
index 326e2ab..8369df84 100644
--- a/chrome/browser/ash/nearby/presence/credential_storage/metrics/credential_storage_metrics.cc
+++ b/chrome/browser/ash/nearby/presence/credential_storage/metrics/credential_storage_metrics.cc
@@ -26,12 +26,37 @@
       "RemotePublicDatabaseInitializationResult",
       success);
 }
+
 void RecordCredentialStoragePrivateInitializationResult(bool success) {
   base::UmaHistogramBoolean(
       "Nearby.Presence.Credentials.Storage.PrivateDatabaseInitializationResult",
       success);
 }
 
+void RecordCredentialStorageLocalPublicDatabaseInitializationDuration(
+    base::TimeDelta duration) {
+  base::UmaHistogramMicrosecondsTimes(
+      "Nearby.Presence.Credentials.Storage."
+      "LocalPublicDatabaseInitializationDuration",
+      duration);
+}
+
+void RecordCredentialStorageRemotePublicDatabaseInitializationDuration(
+    base::TimeDelta duration) {
+  base::UmaHistogramMicrosecondsTimes(
+      "Nearby.Presence.Credentials.Storage."
+      "RemotePublicDatabaseInitializationDuration",
+      duration);
+}
+
+void RecordCredentialStoragePrivateDatabaseInitializationDuration(
+    base::TimeDelta duration) {
+  base::UmaHistogramMicrosecondsTimes(
+      "Nearby.Presence.Credentials.Storage."
+      "PrivateDatabaseInitializationDuration",
+      duration);
+}
+
 void RecordCredentialStorageSaveLocalPublicCredentialsResult(bool success) {
   base::UmaHistogramBoolean(
       "Nearby.Presence.Credentials.Storage.SaveLocalPublicCredentials.Result",
@@ -50,4 +75,27 @@
       success);
 }
 
+void RecordCredentialStorageRetrieveLocalPublicCredentialsDuration(
+    base::TimeDelta duration) {
+  base::UmaHistogramMicrosecondsTimes(
+      "Nearby.Presence.Credentials.Storage."
+      "RetrieveLocalPublicCredentialsDuration",
+      duration);
+}
+
+void RecordCredentialStorageRetrieveRemotePublicCredentialsDuration(
+    base::TimeDelta duration) {
+  base::UmaHistogramMicrosecondsTimes(
+      "Nearby.Presence.Credentials.Storage."
+      "RetrieveRemotePublicCredentialsDuration",
+      duration);
+}
+
+void RecordCredentialStorageRetrievePrivateCredentialsDuration(
+    base::TimeDelta duration) {
+  base::UmaHistogramMicrosecondsTimes(
+      "Nearby.Presence.Credentials.Storage.RetrievePrivateCredentialsDuration",
+      duration);
+}
+
 }  // namespace ash::nearby::presence::metrics
diff --git a/chrome/browser/ash/nearby/presence/credential_storage/metrics/credential_storage_metrics.h b/chrome/browser/ash/nearby/presence/credential_storage/metrics/credential_storage_metrics.h
index af55318..753c31e 100644
--- a/chrome/browser/ash/nearby/presence/credential_storage/metrics/credential_storage_metrics.h
+++ b/chrome/browser/ash/nearby/presence/credential_storage/metrics/credential_storage_metrics.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_ASH_NEARBY_PRESENCE_CREDENTIAL_STORAGE_METRICS_CREDENTIAL_STORAGE_METRICS_H_
 #define CHROME_BROWSER_ASH_NEARBY_PRESENCE_CREDENTIAL_STORAGE_METRICS_CREDENTIAL_STORAGE_METRICS_H_
 
+#include "base/time/time.h"
+
 namespace ash::nearby::presence::metrics {
 
 void RecordCredentialStorageInitializationResult(bool success);
@@ -13,10 +15,24 @@
 void RecordCredentialStorageRemotePublicInitializationResult(bool success);
 void RecordCredentialStoragePrivateInitializationResult(bool success);
 
+void RecordCredentialStorageLocalPublicDatabaseInitializationDuration(
+    base::TimeDelta duration);
+void RecordCredentialStorageRemotePublicDatabaseInitializationDuration(
+    base::TimeDelta duration);
+void RecordCredentialStoragePrivateDatabaseInitializationDuration(
+    base::TimeDelta duration);
+
 void RecordCredentialStorageSaveLocalPublicCredentialsResult(bool success);
 void RecordCredentialStorageSaveRemotePublicCredentialsResult(bool success);
 void RecordCredentialStorageSavePrivateCredentialsResult(bool success);
 
+void RecordCredentialStorageRetrieveLocalPublicCredentialsDuration(
+    base::TimeDelta duration);
+void RecordCredentialStorageRetrieveRemotePublicCredentialsDuration(
+    base::TimeDelta duration);
+void RecordCredentialStorageRetrievePrivateCredentialsDuration(
+    base::TimeDelta duration);
+
 }  // namespace ash::nearby::presence::metrics
 
 #endif  // CHROME_BROWSER_ASH_NEARBY_PRESENCE_CREDENTIAL_STORAGE_METRICS_CREDENTIAL_STORAGE_METRICS_H_
diff --git a/chrome/browser/ash/nearby/presence/credential_storage/nearby_presence_credential_storage.cc b/chrome/browser/ash/nearby/presence/credential_storage/nearby_presence_credential_storage.cc
index a4dfe54..ceba002 100644
--- a/chrome/browser/ash/nearby/presence/credential_storage/nearby_presence_credential_storage.cc
+++ b/chrome/browser/ash/nearby/presence/credential_storage/nearby_presence_credential_storage.cc
@@ -102,7 +102,8 @@
   // true.
   private_db_->Init(base::BindOnce(
       &NearbyPresenceCredentialStorage::OnPrivateDatabaseInitialized,
-      weak_ptr_factory_.GetWeakPtr(), std::move(on_fully_initialized)));
+      weak_ptr_factory_.GetWeakPtr(), std::move(on_fully_initialized),
+      /*initialization_start_time=*/base::TimeTicks::Now()));
 }
 
 void NearbyPresenceCredentialStorage::SaveCredentials(
@@ -157,16 +158,19 @@
     GetPublicCredentialsCallback callback) {
   CHECK(callback);
 
+  auto on_credentials_received_callback = base::BindOnce(
+      &NearbyPresenceCredentialStorage::OnPublicCredentialsRetrieved,
+      weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+      /*retrieval_start_time=*/base::TimeTicks::Now(), public_credential_type);
+
   switch (public_credential_type) {
     case (mojom::PublicCredentialType::kLocalPublicCredential):
-      local_public_db_->LoadEntries(base::BindOnce(
-          &NearbyPresenceCredentialStorage::OnPublicCredentialsRetrieved,
-          weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+      local_public_db_->LoadEntries(
+          std::move(on_credentials_received_callback));
       break;
     case (mojom::PublicCredentialType::kRemotePublicCredential):
-      remote_public_db_->LoadEntries(base::BindOnce(
-          &NearbyPresenceCredentialStorage::OnPublicCredentialsRetrieved,
-          weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+      remote_public_db_->LoadEntries(
+          std::move(on_credentials_received_callback));
       break;
   }
 }
@@ -176,7 +180,8 @@
   CHECK(callback);
   private_db_->LoadEntries(base::BindOnce(
       &NearbyPresenceCredentialStorage::OnPrivateCredentialsRetrieved,
-      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+      weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+      /*retrieval_start_time=*/base::TimeTicks::Now()));
 }
 
 void NearbyPresenceCredentialStorage::UpdateLocalCredential(
@@ -225,6 +230,7 @@
 
 void NearbyPresenceCredentialStorage::OnPrivateCredentialsRetrieved(
     GetPrivateCredentialsCallback callback,
+    base::TimeTicks retrieval_start_time,
     bool success,
     std::unique_ptr<std::vector<::nearby::internal::LocalCredential>> entries) {
   CHECK(callback);
@@ -237,6 +243,11 @@
     return;
   }
 
+  base::TimeDelta retrieval_duration =
+      base::TimeTicks::Now() - retrieval_start_time;
+  metrics::RecordCredentialStorageRetrievePrivateCredentialsDuration(
+      retrieval_duration);
+
   CHECK(entries);
 
   std::vector<ash::nearby::presence::mojom::LocalCredentialPtr>
@@ -252,6 +263,8 @@
 
 void NearbyPresenceCredentialStorage::OnPublicCredentialsRetrieved(
     GetPublicCredentialsCallback callback,
+    base::TimeTicks retrieval_start_time,
+    mojom::PublicCredentialType public_credential_type,
     bool success,
     std::unique_ptr<std::vector<::nearby::internal::SharedCredential>>
         entries) {
@@ -265,6 +278,19 @@
     return;
   }
 
+  base::TimeDelta retrieval_duration =
+      base::TimeTicks::Now() - retrieval_start_time;
+  switch (public_credential_type) {
+    case (mojom::PublicCredentialType::kLocalPublicCredential):
+      metrics::RecordCredentialStorageRetrieveLocalPublicCredentialsDuration(
+          retrieval_duration);
+      break;
+    case (mojom::PublicCredentialType::kRemotePublicCredential):
+      metrics::RecordCredentialStorageRetrieveRemotePublicCredentialsDuration(
+          retrieval_duration);
+      break;
+  }
+
   CHECK(entries);
 
   std::vector<ash::nearby::presence::mojom::SharedCredentialPtr>
@@ -357,12 +383,21 @@
 
 void NearbyPresenceCredentialStorage::OnPrivateDatabaseInitialized(
     base::OnceCallback<void(bool)> on_fully_initialized,
+    base::TimeTicks initialization_start_time,
     leveldb_proto::Enums::InitStatus private_db_initialization_status) {
-  // If the private initialization failed, do not attempt to initialize the
-  // public databases.
-  if (private_db_initialization_status !=
+  if (private_db_initialization_status ==
       leveldb_proto::Enums::InitStatus::kOK) {
     metrics::RecordCredentialStoragePrivateInitializationResult(
+        /*success=*/true);
+
+    base::TimeDelta initialization_duration =
+        base::TimeTicks::Now() - initialization_start_time;
+    metrics::RecordCredentialStoragePrivateDatabaseInitializationDuration(
+        initialization_duration);
+  } else {
+    // If the private initialization failed, do not attempt to initialize the
+    // public databases.
+    metrics::RecordCredentialStoragePrivateInitializationResult(
         /*success=*/false);
     LOG(ERROR) << __func__
                << ": failed to initialize private credential database with "
@@ -372,24 +407,31 @@
     return;
   }
 
-  metrics::RecordCredentialStoragePrivateInitializationResult(
-      /*success=*/true);
-
   // Attempt to initialize the local public credential database. Iff successful,
   // then attempt to initialize the remote public credential database.
   local_public_db_->Init(base::BindOnce(
       &NearbyPresenceCredentialStorage::OnLocalPublicDatabaseInitialized,
-      weak_ptr_factory_.GetWeakPtr(), std::move(on_fully_initialized)));
+      weak_ptr_factory_.GetWeakPtr(), std::move(on_fully_initialized),
+      /*initialization_start_time=*/base::TimeTicks::Now()));
 }
 
 void NearbyPresenceCredentialStorage::OnLocalPublicDatabaseInitialized(
     base::OnceCallback<void(bool)> on_fully_initialized,
+    base::TimeTicks initialization_start_time,
     leveldb_proto::Enums::InitStatus local_public_db_initialization_status) {
-  // If the local public initialization failed, do not attempt to initialize the
-  // remote public database.
-  if (local_public_db_initialization_status !=
+  if (local_public_db_initialization_status ==
       leveldb_proto::Enums::InitStatus::kOK) {
     metrics::RecordCredentialStorageLocalPublicInitializationResult(
+        /*success=*/true);
+
+    base::TimeDelta initialization_duration =
+        base::TimeTicks::Now() - initialization_start_time;
+    metrics::RecordCredentialStorageLocalPublicDatabaseInitializationDuration(
+        initialization_duration);
+  } else {
+    // If the local public initialization failed, do not attempt to initialize
+    // the remote public database.
+    metrics::RecordCredentialStorageLocalPublicInitializationResult(
         /*success=*/false);
     LOG(ERROR) << __func__
                << ": failed to initialize local public credential database "
@@ -399,20 +441,27 @@
     return;
   }
 
-  metrics::RecordCredentialStorageLocalPublicInitializationResult(
-      /*success=*/true);
-
   remote_public_db_->Init(base::BindOnce(
       &NearbyPresenceCredentialStorage::OnRemotePublicDatabaseInitialized,
-      weak_ptr_factory_.GetWeakPtr(), std::move(on_fully_initialized)));
+      weak_ptr_factory_.GetWeakPtr(), std::move(on_fully_initialized),
+      /*initialization_start_time=*/base::TimeTicks::Now()));
 }
 
 void NearbyPresenceCredentialStorage::OnRemotePublicDatabaseInitialized(
     base::OnceCallback<void(bool)> on_fully_initialized,
+    base::TimeTicks initialization_start_time,
     leveldb_proto::Enums::InitStatus remote_public_db_initialization_status) {
-  if (remote_public_db_initialization_status !=
+  if (remote_public_db_initialization_status ==
       leveldb_proto::Enums::InitStatus::kOK) {
     metrics::RecordCredentialStorageRemotePublicInitializationResult(
+        /*success=*/true);
+
+    base::TimeDelta initialization_duration =
+        base::TimeTicks::Now() - initialization_start_time;
+    metrics::RecordCredentialStorageRemotePublicDatabaseInitializationDuration(
+        initialization_duration);
+  } else {
+    metrics::RecordCredentialStorageRemotePublicInitializationResult(
         /*success=*/false);
     LOG(ERROR) << __func__
                << ": failed to initialize remote public credential database "
@@ -422,9 +471,6 @@
     return;
   }
 
-  metrics::RecordCredentialStorageRemotePublicInitializationResult(
-      /*success=*/true);
-
   CHECK(pending_receiver_);
   // All databases were successfully initialized, so it's safe to process
   // interface calls.
diff --git a/chrome/browser/ash/nearby/presence/credential_storage/nearby_presence_credential_storage.h b/chrome/browser/ash/nearby/presence/credential_storage/nearby_presence_credential_storage.h
index d7762d8ef..9eccde7 100644
--- a/chrome/browser/ash/nearby/presence/credential_storage/nearby_presence_credential_storage.h
+++ b/chrome/browser/ash/nearby/presence/credential_storage/nearby_presence_credential_storage.h
@@ -7,6 +7,7 @@
 
 #include "base/files/file_path.h"
 #include "base/functional/callback.h"
+#include "base/time/time.h"
 #include "chromeos/ash/components/nearby/presence/conversions/proto_conversions.h"
 #include "chromeos/ash/services/nearby/public/mojom/nearby_presence.mojom.h"
 #include "chromeos/ash/services/nearby/public/mojom/nearby_presence_credential_storage.mojom.h"
@@ -88,11 +89,14 @@
                                 bool success);
   void OnPrivateCredentialsRetrieved(
       GetPrivateCredentialsCallback callback,
+      base::TimeTicks retrieval_start_time,
       bool success,
       std::unique_ptr<std::vector<::nearby::internal::LocalCredential>>
           entries);
   void OnPublicCredentialsRetrieved(
       GetPublicCredentialsCallback callback,
+      base::TimeTicks retrieval_start_time,
+      mojom::PublicCredentialType public_credential_type,
       bool success,
       std::unique_ptr<std::vector<::nearby::internal::SharedCredential>>
           entries);
@@ -110,12 +114,15 @@
 
   void OnPrivateDatabaseInitialized(
       base::OnceCallback<void(bool)> on_fully_initialized,
+      base::TimeTicks initialization_start_time,
       leveldb_proto::Enums::InitStatus private_db_initialization_status);
   void OnLocalPublicDatabaseInitialized(
       base::OnceCallback<void(bool)> on_fully_initialized,
+      base::TimeTicks initialization_start_time,
       leveldb_proto::Enums::InitStatus local_public_db_initialization_status);
   void OnRemotePublicDatabaseInitialized(
       base::OnceCallback<void(bool)> on_fully_initialized,
+      base::TimeTicks initialization_start_time,
       leveldb_proto::Enums::InitStatus remote_public_db_initialization_status);
 
   std::unique_ptr<
diff --git a/chrome/browser/ash/nearby/presence/credential_storage/nearby_presence_credential_storage_unittest.cc b/chrome/browser/ash/nearby/presence/credential_storage/nearby_presence_credential_storage_unittest.cc
index d2853e8e..7d859db 100644
--- a/chrome/browser/ash/nearby/presence/credential_storage/nearby_presence_credential_storage_unittest.cc
+++ b/chrome/browser/ash/nearby/presence/credential_storage/nearby_presence_credential_storage_unittest.cc
@@ -854,6 +854,15 @@
 
     run_loop.Run();
   }
+
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Storage."
+      "RetrieveLocalPublicCredentialsDuration",
+      1);
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Storage."
+      "RetrieveRemotePublicCredentialsDuration",
+      0);
 }
 
 TEST_F(NearbyPresenceCredentialStorageTest, GetPublicCredentials_Local_Fail) {
@@ -891,6 +900,16 @@
 
     run_loop.Run();
   }
+
+  // Only record duration for successful loads.
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Storage."
+      "RetrieveLocalPublicCredentialsDuration",
+      0);
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Storage."
+      "RetrieveRemotePublicCredentialsDuration",
+      0);
 }
 
 TEST_F(NearbyPresenceCredentialStorageTest,
@@ -930,6 +949,15 @@
 
     run_loop.Run();
   }
+
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Storage."
+      "RetrieveLocalPublicCredentialsDuration",
+      0);
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Storage."
+      "RetrieveRemotePublicCredentialsDuration",
+      1);
 }
 
 TEST_F(NearbyPresenceCredentialStorageTest, GetPublicCredentials_Remote_Fail) {
@@ -966,6 +994,15 @@
 
     run_loop.Run();
   }
+
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Storage."
+      "RetrieveLocalPublicCredentialsDuration",
+      0);
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Storage."
+      "RetrieveRemotePublicCredentialsDuration",
+      0);
 }
 
 TEST_F(NearbyPresenceCredentialStorageTest, GetPrivateCredentials_Success) {
@@ -999,6 +1036,10 @@
 
     run_loop.Run();
   }
+
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Storage.RetrievePrivateCredentialsDuration",
+      1);
 }
 
 TEST_F(NearbyPresenceCredentialStorageTest, GetPrivateCredentials_Fail) {
@@ -1033,6 +1074,10 @@
 
     run_loop.Run();
   }
+
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Storage.RetrievePrivateCredentialsDuration",
+      0);
 }
 
 TEST_F(NearbyPresenceCredentialStorageTest, UpdateLocalCredential_Success) {
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index c23b11e..8295e2a 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -367,7 +367,6 @@
 #include "sandbox/policy/features.h"
 #include "sandbox/policy/mojom/sandbox.mojom.h"
 #include "sandbox/policy/switches.h"
-#include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
@@ -757,6 +756,10 @@
 #include "chrome/browser/enterprise/data_protection/data_protection_clipboard_utils.h"
 #endif  // BUILDFLAG(ENTERPRISE_DATA_CONTROLS)
 
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
+#include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
+
 using blink::mojom::EffectiveConnectionType;
 using blink::web_pref::WebPreferences;
 using content::BrowserThread;
@@ -3538,7 +3541,7 @@
   return google_apis::GetAPIKey();
 }
 
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 device::GeolocationSystemPermissionManager*
 ChromeContentBrowserClient::GetGeolocationSystemPermissionManager() {
   return device::GeolocationSystemPermissionManager::GetInstance();
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 9271426..6bf9c58b 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -38,6 +38,7 @@
 #include "media/media_buildflags.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
+#include "services/device/public/cpp/geolocation/buildflags.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "services/video_effects/public/mojom/video_effects_processor.mojom-forward.h"
 #include "third_party/blink/public/mojom/worker/shared_worker_info.mojom.h"
@@ -395,7 +396,7 @@
   network::mojom::NetworkContext* GetSystemNetworkContext() override;
   std::string GetGeolocationApiKey() override;
 
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
   device::GeolocationSystemPermissionManager*
   GetGeolocationSystemPermissionManager() override;
 #endif
diff --git a/chrome/browser/chrome_navigation_browsertest.cc b/chrome/browser/chrome_navigation_browsertest.cc
index 15f8844..a824e23 100644
--- a/chrome/browser/chrome_navigation_browsertest.cc
+++ b/chrome/browser/chrome_navigation_browsertest.cc
@@ -68,6 +68,7 @@
 #include "extensions/test/test_extension_dir.h"
 #include "google_apis/gaia/gaia_switches.h"
 #include "net/dns/mock_host_resolver.h"
+#include "pdf/buildflags.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/network_switches.h"
@@ -1994,11 +1995,11 @@
   ASSERT_EQ(GURL("about:blank"), main_contents->GetLastCommittedURL());
 }
 
+#if BUILDFLAG(ENABLE_PDF)
 // Tests that a main frame hosting pdf does not get skipped because of history
 // manipulation intervention if there was a user gesture.
-// TODO(crbug.com/333829580): Final navigation is flaky on all platforms.
 IN_PROC_BROWSER_TEST_F(HistoryManipulationInterventionBrowserTest,
-                       DISABLED_PDFDoNotSkipOnBackForwardDueToUserGesture) {
+                       PDFDoNotSkipOnBackForwardDueToUserGesture) {
   GURL pdf_url(embedded_test_server()->GetURL("/pdf/test.pdf"));
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), pdf_url));
 
@@ -2018,16 +2019,17 @@
   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_BACK));
 
   ASSERT_TRUE(chrome::CanGoBack(browser()));
+
+  content::TestNavigationObserver go_back_observer(main_contents);
   chrome::GoBack(browser(), WindowOpenDisposition::CURRENT_TAB);
-  EXPECT_TRUE(content::WaitForLoadStop(main_contents));
+  go_back_observer.WaitForNavigationFinished();
   ASSERT_EQ(pdf_url, main_contents->GetLastCommittedURL());
 }
 
 // Tests that a main frame hosting pdf gets skipped because of history
 // manipulation intervention if there was no user gesture.
 IN_PROC_BROWSER_TEST_F(HistoryManipulationInterventionBrowserTest,
-                       // TODO(crbug.com/333829580): Re-enable this test
-                       DISABLED_PDFSkipOnBackForwardNoUserGesture) {
+                       PDFSkipOnBackForwardNoUserGesture) {
   GURL pdf_url(embedded_test_server()->GetURL("/pdf/test.pdf"));
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), pdf_url));
 
@@ -2048,10 +2050,12 @@
   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_BACK));
 
   ASSERT_TRUE(chrome::CanGoBack(browser()));
+  content::TestNavigationObserver go_back_observer(main_contents);
   chrome::GoBack(browser(), WindowOpenDisposition::CURRENT_TAB);
-  EXPECT_TRUE(content::WaitForLoadStop(main_contents));
+  go_back_observer.WaitForNavigationFinished();
   ASSERT_EQ(GURL("about:blank"), main_contents->GetLastCommittedURL());
 }
+#endif  // BUILDFLAG(ENABLE_PDF)
 
 // This test class turns on the mode where sites where the user enters a
 // password are dynamically added to the list of sites requiring a dedicated
diff --git a/chrome/browser/extensions/activity_log/activity_log_unittest.cc b/chrome/browser/extensions/activity_log/activity_log_unittest.cc
index d79fcb35..a891ab1 100644
--- a/chrome/browser/extensions/activity_log/activity_log_unittest.cc
+++ b/chrome/browser/extensions/activity_log/activity_log_unittest.cc
@@ -101,6 +101,9 @@
       const std::vector<std::string>& extension_ids) override {}
   void UpdateUserScriptWorlds(
       std::vector<mojom::UserScriptWorldInfoPtr> info) override {}
+  void ClearUserScriptWorldConfig(
+      const std::string& extension_id,
+      const std::optional<std::string>& world_id) override {}
   void ShouldSuspend(ShouldSuspendCallback callback) override {
     std::move(callback).Run();
   }
diff --git a/chrome/browser/extensions/api/automation/automation_apitest.cc b/chrome/browser/extensions/api/automation/automation_apitest.cc
index ca449cc5..94018ce 100644
--- a/chrome/browser/extensions/api/automation/automation_apitest.cc
+++ b/chrome/browser/extensions/api/automation/automation_apitest.cc
@@ -40,11 +40,11 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
 #include "ui/accessibility/accessibility_switches.h"
-#include "ui/accessibility/ax_event_notification_details.h"
 #include "ui/accessibility/ax_node.h"
 #include "ui/accessibility/ax_serializable_tree.h"
 #include "ui/accessibility/ax_tree.h"
 #include "ui/accessibility/ax_tree_serializer.h"
+#include "ui/accessibility/ax_updates_and_events.h"
 #include "ui/accessibility/tree_generator.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/display/display_switches.h"
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc
index 4a45f29..9367cee 100644
--- a/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc
@@ -81,6 +81,9 @@
       const std::vector<ExtensionId>& extension_ids) override {}
   void UpdateUserScriptWorlds(
       std::vector<mojom::UserScriptWorldInfoPtr> info) override {}
+  void ClearUserScriptWorldConfig(
+      const std::string& extension_id,
+      const std::optional<std::string>& world_id) override {}
   void ShouldSuspend(ShouldSuspendCallback callback) override {
     std::move(callback).Run();
   }
diff --git a/chrome/browser/extensions/permissions/active_tab_permission_granter.cc b/chrome/browser/extensions/permissions/active_tab_permission_granter.cc
index a1729cd5..149e9d8 100644
--- a/chrome/browser/extensions/permissions/active_tab_permission_granter.cc
+++ b/chrome/browser/extensions/permissions/active_tab_permission_granter.cc
@@ -202,7 +202,8 @@
 
       auto* permissions_manager =
           PermissionsManager::Get(web_contents()->GetBrowserContext());
-      permissions_manager->NotifyActiveTabPermisssionGranted(*extension);
+      permissions_manager->NotifyActiveTabPermisssionGranted(
+          web_contents(), tab_id_, *extension);
     }
   }
 }
diff --git a/chrome/browser/extensions/permissions/site_access_requests_helper_unittest.cc b/chrome/browser/extensions/permissions/site_access_requests_helper_unittest.cc
new file mode 100644
index 0000000..4f3e917
--- /dev/null
+++ b/chrome/browser/extensions/permissions/site_access_requests_helper_unittest.cc
@@ -0,0 +1,265 @@
+// 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 "extensions/browser/site_access_requests_helper.h"
+
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_service_test_base.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/extensions/permissions/active_tab_permission_granter.h"
+#include "chrome/browser/extensions/permissions/scripting_permissions_modifier.h"
+#include "chrome/browser/extensions/permissions/site_permissions_helper.h"
+#include "chrome/browser/extensions/tab_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/test_browser_window.h"
+#include "components/crx_file/id_util.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/web_contents_tester.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/permissions_manager.h"
+#include "extensions/common/extension_builder.h"
+#include "extensions/test/permissions_manager_waiter.h"
+
+namespace extensions {
+
+class SiteAccessRequestsHelperUnittest : public ExtensionServiceTestBase {
+ public:
+  SiteAccessRequestsHelperUnittest() = default;
+  ~SiteAccessRequestsHelperUnittest() override = default;
+
+  SiteAccessRequestsHelperUnittest(const SiteAccessRequestsHelperUnittest&) =
+      delete;
+  SiteAccessRequestsHelperUnittest& operator=(
+      const SiteAccessRequestsHelperUnittest&) = delete;
+
+  // Installs an extension with `host_permission` and withhelds them.
+  scoped_refptr<const Extension> InstallExtensionAndWithholdHostPermissions(
+      const std::string& name,
+      const std::string& host_permission);
+
+  // Installs an extension with activeTab permission.
+  scoped_refptr<const Extension> InstallExtensionWithActiveTab(
+      const std::string& name);
+
+  // Adds a new tab with `url` to the tab strip, and returns the WebContents
+  // associated with it.
+  content::WebContents* AddTab(const GURL& url);
+
+  // Returns the browser. Creates a new one if it doesn't exist.
+  Browser* browser();
+
+  PermissionsManager* permissions_manager() { return permissions_manager_; }
+
+  // ExtensionServiceTestBase:
+  void SetUp() override;
+  void TearDown() override;
+
+ private:
+  // The browser and accompaying window.
+  std::unique_ptr<Browser> browser_;
+  std::unique_ptr<TestBrowserWindow> browser_window_;
+
+  raw_ptr<PermissionsManager> permissions_manager_;
+};
+
+scoped_refptr<const Extension>
+SiteAccessRequestsHelperUnittest::InstallExtensionAndWithholdHostPermissions(
+    const std::string& name,
+    const std::string& host_permission) {
+  auto extension =
+      ExtensionBuilder(name)
+          .SetManifestVersion(3)
+          .SetManifestKey("host_permissions",
+                          base::Value::List().Append(host_permission))
+          .SetID(crx_file::id_util::GenerateId(name))
+          .Build();
+  service()->AddExtension(extension.get());
+
+  ScriptingPermissionsModifier(profile(), extension)
+      .SetWithholdHostPermissions(true);
+
+  return extension;
+}
+
+scoped_refptr<const Extension>
+SiteAccessRequestsHelperUnittest::InstallExtensionWithActiveTab(
+    const std::string& name) {
+  auto extension = ExtensionBuilder(name)
+                       .SetManifestVersion(3)
+                       .SetID(crx_file::id_util::GenerateId(name))
+                       .AddPermission("activeTab")
+                       .Build();
+  service()->AddExtension(extension.get());
+
+  return extension;
+}
+
+content::WebContents* SiteAccessRequestsHelperUnittest::AddTab(
+    const GURL& url) {
+  std::unique_ptr<content::WebContents> web_contents(
+      content::WebContentsTester::CreateTestWebContents(profile(), nullptr));
+  content::WebContents* raw_contents = web_contents.get();
+
+  browser()->tab_strip_model()->AppendWebContents(std::move(web_contents),
+                                                  true);
+  EXPECT_EQ(browser()->tab_strip_model()->GetActiveWebContents(), raw_contents);
+
+  content::NavigationSimulator::NavigateAndCommitFromBrowser(raw_contents, url);
+  EXPECT_EQ(url, raw_contents->GetLastCommittedURL());
+
+  return raw_contents;
+}
+
+Browser* SiteAccessRequestsHelperUnittest::browser() {
+  if (!browser_) {
+    Browser::CreateParams params(profile(), true);
+    browser_window_ = std::make_unique<TestBrowserWindow>();
+    params.window = browser_window_.get();
+    browser_.reset(Browser::Create(params));
+  }
+  return browser_.get();
+}
+
+void SiteAccessRequestsHelperUnittest::SetUp() {
+  ExtensionServiceTestBase::SetUp();
+  InitializeEmptyExtensionService();
+
+  permissions_manager_ = PermissionsManager::Get(profile());
+}
+
+void SiteAccessRequestsHelperUnittest::TearDown() {
+  // Remove any tabs in the tab strip; else the test crashes.
+  if (browser_) {
+    while (!browser_->tab_strip_model()->empty()) {
+      browser_->tab_strip_model()->DetachAndDeleteWebContentsAt(0);
+    }
+  }
+  permissions_manager_ = nullptr;
+
+  ExtensionServiceTestBase::TearDown();
+}
+
+// Tests site access requests are properly added and removed.
+TEST_F(SiteAccessRequestsHelperUnittest, AddAndRemoveRequests) {
+  auto extension_A =
+      InstallExtensionAndWithholdHostPermissions("Extension A", "<all_urls>");
+  auto extension_B =
+      InstallExtensionAndWithholdHostPermissions("Extension B", "<all_urls>");
+
+  content::WebContents* web_contents = AddTab(GURL("http://www.example.com/"));
+  int tab_id = ExtensionTabUtil::GetTabId(web_contents);
+
+  // Add site access request for extension A. Verify only extension A has a
+  // request.
+  permissions_manager()->AddSiteAccessRequest(web_contents, tab_id,
+                                              *extension_A);
+  EXPECT_TRUE(
+      permissions_manager()->HasSiteAccessRequest(tab_id, extension_A->id()));
+  EXPECT_FALSE(
+      permissions_manager()->HasSiteAccessRequest(tab_id, extension_B->id()));
+
+  // Add site access request for extension B. Verify both extensions have a
+  // request.
+  permissions_manager()->AddSiteAccessRequest(web_contents, tab_id,
+                                              *extension_B);
+  EXPECT_TRUE(
+      permissions_manager()->HasSiteAccessRequest(tab_id, extension_A->id()));
+  EXPECT_TRUE(
+      permissions_manager()->HasSiteAccessRequest(tab_id, extension_B->id()));
+
+  // Remove site access request for extension A. Verify only extension B has a
+  // request.
+  permissions_manager()->RemoveSiteAccessRequest(tab_id, extension_A->id());
+  EXPECT_FALSE(
+      permissions_manager()->HasSiteAccessRequest(tab_id, extension_A->id()));
+  EXPECT_TRUE(
+      permissions_manager()->HasSiteAccessRequest(tab_id, extension_B->id()));
+}
+
+// Tests request is removed on cross-origin navigations.
+TEST_F(SiteAccessRequestsHelperUnittest,
+       RequestRemovedOnCrossOriginNavigation) {
+  auto extension =
+      InstallExtensionAndWithholdHostPermissions("Extension", "<all_urls>");
+
+  content::WebContents* web_contents =
+      AddTab(GURL("http://www.same-origin.com/a"));
+  content::WebContentsTester* web_contents_tester =
+      content::WebContentsTester::For(web_contents);
+  int tab_id = ExtensionTabUtil::GetTabId(web_contents);
+
+  // Add site access request for extension.
+  permissions_manager()->AddSiteAccessRequest(web_contents, tab_id, *extension);
+  EXPECT_TRUE(
+      permissions_manager()->HasSiteAccessRequest(tab_id, extension->id()));
+
+  // Same-origin navigation should retain request.
+  web_contents_tester->NavigateAndCommit(GURL("http://www.same-origin.com/b"));
+  EXPECT_TRUE(
+      permissions_manager()->HasSiteAccessRequest(tab_id, extension->id()));
+
+  // Cross-origin navigation should remove request.
+  web_contents_tester->NavigateAndCommit(GURL("http://www.cross-origin.com/c"));
+  EXPECT_FALSE(
+      permissions_manager()->HasSiteAccessRequest(tab_id, extension->id()));
+}
+
+// Test request is removed when extension is granted "always on this site" site
+// access.
+TEST_F(SiteAccessRequestsHelperUnittest,
+       RequestRemovedWhenExtensionHasSiteAccess) {
+  auto extension =
+      InstallExtensionAndWithholdHostPermissions("Extension", "<all_urls>");
+
+  content::WebContents* web_contents =
+      AddTab(GURL("http://www.same-origin.com/a"));
+  int tab_id = ExtensionTabUtil::GetTabId(web_contents);
+
+  // Add site access request for extension.
+  permissions_manager()->AddSiteAccessRequest(web_contents, tab_id, *extension);
+  EXPECT_TRUE(
+      permissions_manager()->HasSiteAccessRequest(tab_id, extension->id()));
+
+  // Grant "always on this site" access to the extension.
+  PermissionsManagerWaiter waiter(PermissionsManager::Get(profile()));
+  SitePermissionsHelper permissions(profile());
+  permissions.UpdateSiteAccess(*extension, web_contents,
+                               PermissionsManager::UserSiteAccess::kOnSite);
+  waiter.WaitForExtensionPermissionsUpdate();
+
+  // Request should be removed since extension has granted site access.
+  EXPECT_FALSE(
+      permissions_manager()->HasSiteAccessRequest(tab_id, extension->id()));
+}
+
+// Test request is removed when extension is granted one-time site access.
+TEST_F(SiteAccessRequestsHelperUnittest,
+       RequestRemovedWhenExtensionHasGrantedActiveTab) {
+  auto extension = InstallExtensionWithActiveTab("Extension");
+
+  content::WebContents* web_contents =
+      AddTab(GURL("http://www.same-origin.com/a"));
+  int tab_id = ExtensionTabUtil::GetTabId(web_contents);
+
+  // Add site access request for extension.
+  permissions_manager()->AddSiteAccessRequest(web_contents, tab_id, *extension);
+  EXPECT_TRUE(
+      permissions_manager()->HasSiteAccessRequest(tab_id, extension->id()));
+
+  // Grant tab permission to extension.
+  ActiveTabPermissionGranter* active_tab_permission_granter =
+      TabHelper::FromWebContents(
+          browser()->tab_strip_model()->GetActiveWebContents())
+          ->active_tab_permission_granter();
+  ASSERT_TRUE(active_tab_permission_granter);
+  active_tab_permission_granter->GrantIfRequested(extension.get());
+
+  // Request should be removed since extension has granted site access.
+  EXPECT_FALSE(
+      permissions_manager()->HasSiteAccessRequest(tab_id, extension->id()));
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/user_script_world_browsertest.cc b/chrome/browser/extensions/user_script_world_browsertest.cc
index ed8b91e..f4b8eea 100644
--- a/chrome/browser/extensions/user_script_world_browsertest.cc
+++ b/chrome/browser/extensions/user_script_world_browsertest.cc
@@ -163,6 +163,13 @@
                                        std::move(csp), enable_messaging);
   }
 
+  // Clears associated user script world properties in the renderer(s).
+  void ClearUserScriptWorldProperties(const Extension& extension,
+                                      std::optional<std::string> world_id) {
+    RendererStartupHelperFactory::GetForBrowserContext(profile())
+        ->ClearUserScriptWorldProperties(extension, std::move(world_id));
+  }
+
   content::WebContents* GetActiveWebContents() {
     return browser()->tab_strip_model()->GetActiveWebContents();
   }
@@ -623,6 +630,46 @@
             "disallowed eval");
 }
 
+// Tests clearing configurations for user script worlds.
+IN_PROC_BROWSER_TEST_F(UserScriptWorldBrowserTest,
+                       ClearingUserScriptWorldConfigurations) {
+  // Load a simple extension with permission to example.com.
+  const Extension* extension =
+      LoadExtensionWithHostPermission("http://example.com/*");
+
+  // Allow eval in "world 1".
+  SetUserScriptWorldProperties(*extension, "world 1",
+                               "script-src 'unsafe-eval'",
+                               /*enable_messaging=*/false);
+
+  // Navigate to example.com and check the world's CSP.
+  const GURL url =
+      embedded_test_server()->GetURL("example.com", "/simple.html");
+  NavigateToURL(url);
+  EXPECT_EQ(ExecuteScriptInUserScriptWorld(kCheckIfEvalAllowedScriptSource,
+                                           *extension, "world 1"),
+            "allowed eval");
+
+  // Now, clear the configuration for "world 1".
+  ClearUserScriptWorldProperties(*extension, "world 1");
+  // Ensure the roundtrip to the renderer completes by sending another script
+  // to inject. Otherwise, the call to clear the configuration may race with the
+  // new document creation and, as described in
+  // `CspMayBeGreedilyInitializedOnDocumentCreation`, this may initialize the
+  // CSP to the old one.
+  EXPECT_EQ("foo",
+            ExecuteScriptInUserScriptWorld("'foo';", *extension, "world 1"));
+
+  // Navigate to create a new isolated world.
+  NavigateToURL(url);
+
+  // Eval should be disallowed (the default) since the configuration was
+  // cleared.
+  EXPECT_EQ(ExecuteScriptInUserScriptWorld(kCheckIfEvalAllowedScriptSource,
+                                           *extension, "world 1"),
+            "disallowed eval");
+}
+
 // Tests that different user script worlds have unique configurations for
 // enabling messaging.
 IN_PROC_BROWSER_TEST_F(UserScriptWorldBrowserTest,
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 9c74e35..9a0abfa 100644
--- a/chrome/browser/extensions/user_script_world_configuration_manager_unittest.cc
+++ b/chrome/browser/extensions/user_script_world_configuration_manager_unittest.cc
@@ -5,22 +5,62 @@
 #include "extensions/browser/user_script_world_configuration_manager.h"
 
 #include "chrome/browser/extensions/extension_service_test_with_install.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_builder.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/test/test_extension_dir.h"
+#include "testing/gmock/include/gmock/gmock.h"
 
 namespace extensions {
 
-using UserScriptWorldConfigurationManagerTest = ExtensionServiceTestWithInstall;
+class UserScriptWorldConfigurationManagerTest
+    : public ExtensionServiceTestWithInstall {
+ public:
+  UserScriptWorldConfigurationManagerTest() = default;
+  ~UserScriptWorldConfigurationManagerTest() override = default;
+
+  void SetUp() override {
+    ExtensionServiceTestWithInstall::SetUp();
+    InitializeEmptyExtensionService();
+
+    configuration_manager_ =
+        UserScriptWorldConfigurationManager::Get(browser_context());
+  }
+
+  void TearDown() override {
+    configuration_manager_ = nullptr;
+    ExtensionServiceTestWithInstall::TearDown();
+  }
+
+  UserScriptWorldConfigurationManager* configuration_manager() {
+    return configuration_manager_.get();
+  }
+
+ private:
+  raw_ptr<UserScriptWorldConfigurationManager> configuration_manager_;
+};
+
+// Returns a matcher for a mojom::UserScriptWorldInfoPtr.
+auto GetWorldMatcher(const ExtensionId& extension_id,
+                     const std::optional<std::string>& world_id,
+                     const std::optional<std::string>& csp,
+                     bool enable_messaging = false) {
+  return testing::Pointer(testing::AllOf(
+      testing::Field("extension id", &mojom::UserScriptWorldInfo::extension_id,
+                     testing::Eq(extension_id)),
+      testing::Field("world id", &mojom::UserScriptWorldInfo::world_id,
+                     testing::Eq(world_id)),
+      testing::Field("csp", &mojom::UserScriptWorldInfo::csp, testing::Eq(csp)),
+      testing::Field("enable messaging",
+                     &mojom::UserScriptWorldInfo::enable_messaging,
+                     testing::Eq(enable_messaging))));
+}
 
 // Tests that extension-specified world configurations are cleared on
 // extension update. This matches the behavior of the registered content and
 // user scripts.
 TEST_F(UserScriptWorldConfigurationManagerTest,
        ConfigurationsAreClearedOnExtensionUpdate) {
-  InitializeEmptyExtensionService();
-
-  UserScriptWorldConfigurationManager* manager =
-      UserScriptWorldConfigurationManager::Get(browser_context());
-
   static constexpr char kManifest[] =
       R"({
            "name": "World Configuration",
@@ -44,18 +84,84 @@
 
   // Register two different configurations for user script worlds, one for the
   // default world and another for "world 1".
-  manager->SetUserScriptWorldInfo(
+  configuration_manager()->SetUserScriptWorldInfo(
       *extension, std::nullopt, "script-src: self", /*enable_messaging=*/false);
-  manager->SetUserScriptWorldInfo(
+  configuration_manager()->SetUserScriptWorldInfo(
       *extension, "world 1", "script-src: none", /*enable_messaging=*/false);
-  EXPECT_EQ(2u, manager->GetAllUserScriptWorlds(extension->id()).size());
+  EXPECT_EQ(
+      2u,
+      configuration_manager()->GetAllUserScriptWorlds(extension->id()).size());
 
   extension = InstallCRX(crx_v2, INSTALL_UPDATED);
   ASSERT_TRUE(extension);
 
   // Since the extension updated to a new version, the world configurations
   // should have been removed.
-  EXPECT_EQ(0u, manager->GetAllUserScriptWorlds(extension->id()).size());
+  EXPECT_EQ(
+      0u,
+      configuration_manager()->GetAllUserScriptWorlds(extension->id()).size());
+}
+
+// Tests clearing configurations for particular user script worlds.
+TEST_F(UserScriptWorldConfigurationManagerTest, ClearingConfigurations) {
+  // Create two extensions.
+  scoped_refptr<const Extension> extension1 = ExtensionBuilder("ext1").Build();
+  scoped_refptr<const Extension> extension2 = ExtensionBuilder("ext2").Build();
+
+  const std::string other_world = "other world";
+  const std::string csp1 = "csp1";
+  const std::string csp2 = "csp2";
+  static constexpr bool kEnableMessaging = false;
+  static constexpr std::optional<std::string> default_world;
+
+  // 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(*extension2, default_world,
+                                                  csp1, kEnableMessaging);
+  configuration_manager()->SetUserScriptWorldInfo(*extension2, other_world,
+                                                  csp2, kEnableMessaging);
+
+  // Verify initial state. Each extension should have those two worlds
+  // configured.
+  auto ext1_default_world =
+      GetWorldMatcher(extension1->id(), default_world, csp1);
+  auto ext1_other_world = GetWorldMatcher(extension1->id(), other_world, csp2);
+  auto ext2_default_world =
+      GetWorldMatcher(extension2->id(), default_world, csp1);
+  auto ext2_other_world = GetWorldMatcher(extension2->id(), other_world, csp2);
+
+  EXPECT_THAT(
+      configuration_manager()->GetAllUserScriptWorlds(extension1->id()),
+      testing::UnorderedElementsAre(ext1_default_world, ext1_other_world));
+  EXPECT_THAT(
+      configuration_manager()->GetAllUserScriptWorlds(extension2->id()),
+      testing::UnorderedElementsAre(ext2_default_world, ext2_other_world));
+
+  // Next, clear "other world" for the first extension.
+  configuration_manager()->ClearUserScriptWorldInfo(*extension1, other_world);
+
+  // The first extension should now only have a configuration for the default
+  // world, while the configurations for the second extension are unchanged.
+  EXPECT_THAT(configuration_manager()->GetAllUserScriptWorlds(extension1->id()),
+              testing::UnorderedElementsAre(ext1_default_world));
+  EXPECT_THAT(
+      configuration_manager()->GetAllUserScriptWorlds(extension2->id()),
+      testing::UnorderedElementsAre(ext2_default_world, ext2_other_world));
+
+  // Remove the configuration for the default world for the second extension.
+  configuration_manager()->ClearUserScriptWorldInfo(*extension2, default_world);
+
+  // Now, the first extension should only have the default configuration, while
+  // the second extension should only have the other world's configuration.
+  EXPECT_THAT(configuration_manager()->GetAllUserScriptWorlds(extension1->id()),
+              testing::UnorderedElementsAre(ext1_default_world));
+  EXPECT_THAT(configuration_manager()->GetAllUserScriptWorlds(extension2->id()),
+              testing::UnorderedElementsAre(ext2_other_world));
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 4a9791e..81ab9895 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1431,17 +1431,6 @@
     "expiry_milestone": 125
   },
   {
-    "name": "clipboard-well-formed-html-sanitization-write",
-    "owners": [
-      "ansollan@microsoft.com",
-      "asully@chromium.org",
-      "estade@chromium.org",
-      "snianu@microsoft.com",
-      "chrome-owp-storage@google.com"
-    ],
-    "expiry_milestone": 125
-  },
-  {
     "name": "cloud-gaming-device",
     "owners": [
       "dgrebenyuk@chromium.org",
@@ -1763,7 +1752,7 @@
   {
     "name": "customize-chrome-side-panel-extensions-card",
     "owners": [ "chrome-desktop-ntp@google.com" ],
-    "expiry_milestone": 125
+    "expiry_milestone": 134
   },
   {
     "name": "customize-chrome-wallpaper-search",
@@ -5077,11 +5066,6 @@
     "expiry_milestone": 125
   },
   {
-    "name": "ios-hide-feed-with-search-choice",
-    "owners": ["scottyoder@google.com", "bling-get-set-up@google.com"],
-    "expiry_milestone": 127
-  },
-  {
     "name": "ios-iph-for-safari-switcher",
     "owners": [ "huitingyu@chromium.org", "bling-flags@google.com" ],
     "expiry_milestone": 121
@@ -5728,7 +5712,7 @@
   {
     "name": "nearby-presence",
     "owners": ["chromeos-cross-device-eng@google.com", "hansberry@chromium.org"],
-    "expiry_milestone": 125
+    "expiry_milestone": 150
   },
   {"name": "nearby-sharing-self-share",
    "owners": ["brandosocarras@google.com", "hansenmichael@google.com", "chromeos-cross-device-eng@google.com"],
@@ -6693,13 +6677,13 @@
   },
   {
     "name": "pdf-portfolio",
-    "owners": [ "nigi@chromium.org", "//pdf/OWNERS" ],
+    "owners": [ "thestig@chromium.org", "//pdf/OWNERS" ],
     "expiry_milestone": 130
   },
   {
     "name": "pdf-use-skia-renderer",
-    "owners": [ "nigi@chromium.org", "//pdf/OWNERS" ],
-    "expiry_milestone": 126
+    "owners": [ "thestig@chromium.org", "//pdf/OWNERS" ],
+    "expiry_milestone": 129
   },
   {
     "name": "pdf-xfa-forms",
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 487642b..946dedd 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -206,7 +206,6 @@
     &kContextMenuSysUiMatchesActivity,
     &kContextualSearchDisableOnlineDetection,
     &kContextualSearchSuppressShortView,
-    &kContextualSearchThinWebViewImplementation,
     &kDeferTabSwitcherLayoutCreation,
     &kDelayTempStripRemoval,
     &kDragDropIntoOmnibox,
@@ -600,10 +599,6 @@
              "ContextualSearchSuppressShortView",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kContextualSearchThinWebViewImplementation,
-             "ContextualSearchThinWebViewImplementation",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 BASE_FEATURE(kDataSharingAndroid,
              "DataSharingAndroid",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index c2a7e06c..ab4f5ab 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -76,7 +76,6 @@
 BASE_DECLARE_FEATURE(kContextMenuTranslateWithGoogleLens);
 BASE_DECLARE_FEATURE(kContextualSearchDisableOnlineDetection);
 BASE_DECLARE_FEATURE(kContextualSearchSuppressShortView);
-BASE_DECLARE_FEATURE(kContextualSearchThinWebViewImplementation);
 BASE_DECLARE_FEATURE(kDeferTabSwitcherLayoutCreation);
 BASE_DECLARE_FEATURE(kDelayTempStripRemoval);
 BASE_DECLARE_FEATURE(kDontPrefetchLibraries);
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 94ad41e..a28a6e21 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
@@ -251,8 +251,6 @@
             "ContextualSearchDisableOnlineDetection";
     public static final String CONTEXTUAL_SEARCH_SUPPRESS_SHORT_VIEW =
             "ContextualSearchSuppressShortView";
-    public static final String CONTEXTUAL_SEARCH_THIN_WEB_VIEW_IMPLEMENTATION =
-            "ContextualSearchThinWebViewImplementation";
     public static final String CONTEXT_MENU_POPUP_FOR_ALL_SCREEN_SIZES =
             "ContextMenuPopupForAllScreenSizes";
     public static final String CONTEXT_MENU_SYS_UI_MATCHES_ACTIVITY =
diff --git a/chrome/browser/lacros/automation_manager_lacros.cc b/chrome/browser/lacros/automation_manager_lacros.cc
index f100a379..ddd28fd 100644
--- a/chrome/browser/lacros/automation_manager_lacros.cc
+++ b/chrome/browser/lacros/automation_manager_lacros.cc
@@ -56,7 +56,7 @@
 }
 
 void AutomationManagerLacros::DispatchAccessibilityLocationChange(
-    const ui::AXLocationChangeNotificationDetails& details) {
+    const ui::AXLocationChanges& details) {
   ui::AXTreeID tree_id = details.ax_tree_id;
   if (!tree_id.token())
     return;
diff --git a/chrome/browser/lacros/automation_manager_lacros.h b/chrome/browser/lacros/automation_manager_lacros.h
index 99aa91b..e07c21d8 100644
--- a/chrome/browser/lacros/automation_manager_lacros.h
+++ b/chrome/browser/lacros/automation_manager_lacros.h
@@ -30,7 +30,7 @@
                                    const gfx::Point& mouse_location,
                                    std::vector<ui::AXEvent> events) override;
   void DispatchAccessibilityLocationChange(
-      const ui::AXLocationChangeNotificationDetails& details) override;
+      const ui::AXLocationChanges& details) override;
   void DispatchTreeDestroyedEvent(ui::AXTreeID tree_id) override;
   void DispatchActionResult(const ui::AXActionData& data,
                             bool result,
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLanguagePromoDialog.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLanguagePromoDialog.java
index b750242..4b35e72 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLanguagePromoDialog.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLanguagePromoDialog.java
@@ -468,7 +468,7 @@
             LanguageItem currentOverrideLanguage) {
         LinkedHashSet<String> topLanguageCodes = new LinkedHashSet<>();
 
-        topLanguageCodes.addAll(LanguageBridge.getULPFromPreference());
+        topLanguageCodes.addAll(LanguageBridge.getULPFromPreference(profile));
         // Add current Accept-Languages to bottom of top languages list.
         topLanguageCodes.addAll(TranslateBridge.getUserLanguageCodes(profile));
 
@@ -657,7 +657,8 @@
         // Don't show if prompt has already been shown.
         if (TranslateBridge.getAppLanguagePromptShown(profile)) return false;
         @TopULPMatchType
-        int hasULPMatch = LanguageBridge.isTopULPBaseLanguage(Locale.getDefault().toLanguageTag());
+        int hasULPMatch =
+                LanguageBridge.isTopULPBaseLanguage(profile, Locale.getDefault().toLanguageTag());
         recordTopULPMatchStatus(hasULPMatch);
         // Don't show if UI language doesn't match the top ULP language.
         if (hasULPMatch != TopULPMatchType.NO) {
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/FakeLanguageBridgeJni.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/FakeLanguageBridgeJni.java
index 93b4f9a9..37eb361 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/FakeLanguageBridgeJni.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/FakeLanguageBridgeJni.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.language;
 
+import org.chromium.chrome.browser.profiles.Profile;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -20,7 +22,7 @@
     }
 
     @Override
-    public String[] getULPFromPreference() {
+    public String[] getULPFromPreference(Profile profile) {
         return mULPLanguages.toArray(new String[mULPLanguages.size()]);
     }
 }
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/LanguageBridge.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/LanguageBridge.java
index e241b2b..f159d25 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/LanguageBridge.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/LanguageBridge.java
@@ -10,6 +10,7 @@
 import org.jni_zero.NativeMethods;
 
 import org.chromium.base.LocaleUtils;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.components.language.LanguageProfileController;
 import org.chromium.components.language.LanguageProfileDelegateImpl;
 
@@ -23,12 +24,14 @@
     /**
      * Returns the TopULPMatchType for |language| and the top ULP language. Only language bases are
      * compared (e.g. en-US = en-GB).
+     *
+     * @param profile
      * @param language String of language tag to check.
      * @return TopULPMatchType
      */
     public static @AppLanguagePromoDialog.TopULPMatchType int isTopULPBaseLanguage(
-            String language) {
-        LinkedHashSet<String> ulpLanguages = getULPFromPreference();
+            Profile profile, String language) {
+        LinkedHashSet<String> ulpLanguages = getULPFromPreference(profile);
 
         Iterator<String> ulpIterator = ulpLanguages.iterator();
         if (!ulpIterator.hasNext()) return AppLanguagePromoDialog.TopULPMatchType.EMPTY;
@@ -55,8 +58,9 @@
     /**
      * @return The ordered set of ULP languages as saved in the Chrome preference.
      */
-    public static LinkedHashSet<String> getULPFromPreference() {
-        return new LinkedHashSet<>(Arrays.asList(LanguageBridgeJni.get().getULPFromPreference()));
+    public static LinkedHashSet<String> getULPFromPreference(Profile profile) {
+        return new LinkedHashSet<>(
+                Arrays.asList(LanguageBridgeJni.get().getULPFromPreference(profile)));
     }
 
     /** Blocking call used by native ULPLanguageModel to get device ULP languages. */
@@ -74,6 +78,6 @@
 
     @NativeMethods
     interface Natives {
-        String[] getULPFromPreference();
+        String[] getULPFromPreference(Profile profile);
     }
 }
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/LanguageBridgeTest.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/LanguageBridgeTest.java
index 1627511..2bd77da 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/LanguageBridgeTest.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/LanguageBridgeTest.java
@@ -11,12 +11,14 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.browser.profiles.Profile;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -28,6 +30,7 @@
     @Rule public JniMocker mJniMocker = new JniMocker();
 
     private FakeLanguageBridgeJni mFakeLanguageBridge;
+    @Mock private Profile mProfile;
 
     @Before
     public void setUp() throws Exception {
@@ -43,39 +46,39 @@
         mFakeLanguageBridge.setULPLanguages(Arrays.asList("pt-BR", "en-US"));
 
         Assert.assertEquals(
-                LanguageBridge.isTopULPBaseLanguage("pt"),
+                LanguageBridge.isTopULPBaseLanguage(mProfile, "pt"),
                 AppLanguagePromoDialog.TopULPMatchType.YES);
         Assert.assertEquals(
-                LanguageBridge.isTopULPBaseLanguage("pt-PT"),
+                LanguageBridge.isTopULPBaseLanguage(mProfile, "pt-PT"),
                 AppLanguagePromoDialog.TopULPMatchType.YES);
         Assert.assertEquals(
-                LanguageBridge.isTopULPBaseLanguage("pt-BR"),
+                LanguageBridge.isTopULPBaseLanguage(mProfile, "pt-BR"),
                 AppLanguagePromoDialog.TopULPMatchType.YES);
         Assert.assertEquals(
-                LanguageBridge.isTopULPBaseLanguage("en"),
+                LanguageBridge.isTopULPBaseLanguage(mProfile, "en"),
                 AppLanguagePromoDialog.TopULPMatchType.NO);
         Assert.assertEquals(
-                LanguageBridge.isTopULPBaseLanguage("en-US"),
+                LanguageBridge.isTopULPBaseLanguage(mProfile, "en-US"),
                 AppLanguagePromoDialog.TopULPMatchType.NO);
 
         mFakeLanguageBridge.setULPLanguages(Arrays.asList("no", "en-US"));
         Assert.assertEquals(
-                LanguageBridge.isTopULPBaseLanguage("nb"),
+                LanguageBridge.isTopULPBaseLanguage(mProfile, "nb"),
                 AppLanguagePromoDialog.TopULPMatchType.YES);
 
         mFakeLanguageBridge.setULPLanguages(Arrays.asList("nn-NO", "en-US"));
         Assert.assertEquals(
-                LanguageBridge.isTopULPBaseLanguage("nb"),
+                LanguageBridge.isTopULPBaseLanguage(mProfile, "nb"),
                 AppLanguagePromoDialog.TopULPMatchType.YES);
 
         mFakeLanguageBridge.setULPLanguages(Arrays.asList("tl-PH", "en-US"));
         Assert.assertEquals(
-                LanguageBridge.isTopULPBaseLanguage("fil"),
+                LanguageBridge.isTopULPBaseLanguage(mProfile, "fil"),
                 AppLanguagePromoDialog.TopULPMatchType.YES);
 
         mFakeLanguageBridge.setULPLanguages(new ArrayList<>());
         Assert.assertEquals(
-                LanguageBridge.isTopULPBaseLanguage("en-US"),
+                LanguageBridge.isTopULPBaseLanguage(mProfile, "en-US"),
                 AppLanguagePromoDialog.TopULPMatchType.EMPTY);
     }
 }
diff --git a/chrome/browser/language/android/language_bridge.cc b/chrome/browser/language/android/language_bridge.cc
index 2e2c1cf4..4359cc9c3d 100644
--- a/chrome/browser/language/android/language_bridge.cc
+++ b/chrome/browser/language/android/language_bridge.cc
@@ -9,7 +9,7 @@
 #include "chrome/browser/language/android/jni_headers/LanguageBridge_jni.h"
 #include "chrome/browser/language/language_model_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profile_android.h"
 #include "components/language/core/browser/language_model.h"
 #include "components/language/core/browser/language_model_manager.h"
 #include "components/language/core/browser/language_prefs.h"
@@ -21,10 +21,8 @@
 
 namespace {
 
-PrefService* GetPrefService() {
-  return ProfileManager::GetActiveUserProfile()
-      ->GetOriginalProfile()
-      ->GetPrefs();
+PrefService* GetPrefService(const base::android::JavaRef<jobject>& j_profile) {
+  return ProfileAndroid::FromProfileAndroid(j_profile)->GetPrefs();
 }
 
 }  // namespace
@@ -52,7 +50,9 @@
 
 // Gets the ULP languages from the Android only preference.
 static ScopedJavaLocalRef<jobjectArray> JNI_LanguageBridge_GetULPFromPreference(
-    JNIEnv* env) {
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& j_profile) {
   return ToJavaArrayOfStrings(
-      env, language::LanguagePrefs(GetPrefService()).GetULPLanguages());
+      env,
+      language::LanguagePrefs(GetPrefService(j_profile)).GetULPLanguages());
 }
diff --git a/chrome/browser/media_galleries/COMMON_METADATA b/chrome/browser/media_galleries/COMMON_METADATA
index a1ce9790..a4fa4c3 100644
--- a/chrome/browser/media_galleries/COMMON_METADATA
+++ b/chrome/browser/media_galleries/COMMON_METADATA
@@ -1,6 +1,3 @@
-monorail: {
-  component: "Platform>Apps>MediaGalleries"
-}
 buganizer_public: {
-  component_id: 1456653
+  component_id: 1253877  #  ChromeOS Public Tracker > Enterprise & Edu > ChromeApps and Extensions
 }
diff --git a/chrome/browser/new_tab_page/modules/new_tab_page_modules.cc b/chrome/browser/new_tab_page/modules/new_tab_page_modules.cc
index 62ef0bd2..f4becab1 100644
--- a/chrome/browser/new_tab_page/modules/new_tab_page_modules.cc
+++ b/chrome/browser/new_tab_page/modules/new_tab_page_modules.cc
@@ -33,6 +33,11 @@
                          IDS_NTP_MODULES_GOOGLE_CALENDAR_TITLE);
   }
 
+  if (base::FeatureList::IsEnabled(ntp_features::kNtpOutlookCalendarModule)) {
+    details.emplace_back("outlook_calendar",
+                         IDS_NTP_MODULES_OUTLOOK_CALENDAR_TITLE);
+  }
+
   if (drive_module_enabled) {
     details.emplace_back("drive", IDS_NTP_MODULES_DRIVE_SENTENCE);
   }
diff --git a/chrome/browser/permissions/permission_manager_factory.cc b/chrome/browser/permissions/permission_manager_factory.cc
index da83f96..e3a545a 100644
--- a/chrome/browser/permissions/permission_manager_factory.cc
+++ b/chrome/browser/permissions/permission_manager_factory.cc
@@ -36,7 +36,7 @@
 #include "components/permissions/contexts/window_management_permission_context.h"
 #include "components/permissions/permission_manager.h"
 #include "ppapi/buildflags/buildflags.h"
-#include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
+#include "services/device/public/cpp/geolocation/buildflags.h"
 
 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
 #include "chrome/browser/media/protected_media_identifier_permission_context.h"
@@ -50,6 +50,10 @@
 #include "chrome/browser/printing/web_api/web_printing_permission_context.h"
 #endif  // BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(USE_CUPS)
 
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
+#include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
+
 namespace {
 
 permissions::PermissionManager::PermissionContextMap CreatePermissionContexts(
@@ -63,7 +67,7 @@
   delegates.geolocation_permission_context_delegate =
       std::make_unique<GeolocationPermissionContextDelegate>(profile);
 #endif  // BUILDFLAG(IS_ANDROID)
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
   delegates.geolocation_system_permission_manager =
       device::GeolocationSystemPermissionManager::GetInstance();
   DCHECK(delegates.geolocation_system_permission_manager);
diff --git a/chrome/browser/resources/history/app.html b/chrome/browser/resources/history/app.html
index 600d407..6364d23 100644
--- a/chrome/browser/resources/history/app.html
+++ b/chrome/browser/resources/history/app.html
@@ -143,7 +143,9 @@
                     if="[[shouldShowHistoryEmbeddings_(queryState_.searchTerm)]]">
                   <cr-history-embeddings
                       search-query="[[queryState_.searchTerm]]"
-                      time-range-start="[[timeRangeStart_]]">
+                      time-range-start="[[timeRangeStart_]]"
+                      on-more-from-site-click="onHistoryEmbeddingsItemMoreFromSiteClick_"
+                      on-remove-item-click="onHistoryEmbeddingsItemRemoveClick_">
                   </cr-history-embeddings>
                 </template>
               </div>
diff --git a/chrome/browser/resources/history/app.ts b/chrome/browser/resources/history/app.ts
index 6a9b81ef..14de854 100644
--- a/chrome/browser/resources/history/app.ts
+++ b/chrome/browser/resources/history/app.ts
@@ -19,6 +19,7 @@
 import './side_bar.js';
 import './strings.m.js';
 
+import type {HistoryEmbeddingsMoreActionsClickEvent} from 'chrome://resources/cr_components/history_embeddings/history_embeddings.js';
 import type {Suggestion} from 'chrome://resources/cr_components/history_embeddings/filter_chips.js';
 import type {CrDrawerElement} from 'chrome://resources/cr_elements/cr_drawer/cr_drawer.js';
 import type {CrLazyRenderElement} from 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.js';
@@ -663,6 +664,23 @@
   private onSelectedSuggestionChanged_(e: CustomEvent<{value: Suggestion}>) {
     this.timeRangeStart_ = e.detail.value?.timeRangeStart;
   }
+
+  private onHistoryEmbeddingsItemMoreFromSiteClick_(
+      e: HistoryEmbeddingsMoreActionsClickEvent) {
+    const historyEmbeddingsItem = e.detail;
+    this.fire_(
+        'change-query',
+        {search: 'host:' + new URL(historyEmbeddingsItem.url.url).hostname});
+  }
+
+  private onHistoryEmbeddingsItemRemoveClick_(
+      e: HistoryEmbeddingsMoreActionsClickEvent) {
+    const historyEmbeddingsItem = e.detail;
+    this.browserService_.removeVisits([{
+      url: historyEmbeddingsItem.url.url,
+      timestamps: [historyEmbeddingsItem.lastUrlVisitTimestamp],
+    }]);
+  }
 }
 
 declare global {
diff --git a/chrome/browser/resources/history/history.ts b/chrome/browser/resources/history/history.ts
index bcab0ad..3e9763c4 100644
--- a/chrome/browser/resources/history/history.ts
+++ b/chrome/browser/resources/history/history.ts
@@ -10,6 +10,7 @@
 export {HistoryEmbeddingsBrowserProxyImpl} from 'chrome://resources/cr_components/history_embeddings/browser_proxy.js';
 export {PageHandlerRemote as HistoryEmbeddingsPageHandlerRemote} from 'chrome://resources/cr_components/history_embeddings/history_embeddings.mojom-webui.js';
 export {CrActionMenuElement} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
+export {HistoryEmbeddingsMoreActionsClickEvent} from 'chrome://resources/cr_components/history_embeddings/history_embeddings.js';
 export {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
 export {getTrustedHTML} from 'chrome://resources/js/static_types.js';
 export {ensureLazyLoaded, HistoryAppElement, listenForPrivilegedLinkClicks} from './app.js';
diff --git a/chrome/browser/resources/new_tab_page/lazy_load.ts b/chrome/browser/resources/new_tab_page/lazy_load.ts
index cee54b8..1fbdb38 100644
--- a/chrome/browser/resources/new_tab_page/lazy_load.ts
+++ b/chrome/browser/resources/new_tab_page/lazy_load.ts
@@ -46,7 +46,7 @@
 export {DisableModuleEvent, DismissModuleEvent, ModulesElement} from './modules/modules.js';
 export {photosDescriptor, PhotosModuleElement} from './modules/photos/module.js';
 export {PhotosProxy} from './modules/photos/photos_module_proxy.js';
-export {googleCalendarDescriptor, CalendarModuleElement} from './modules/v2/calendar/module.js';
+export {CalendarModuleElement, googleCalendarDescriptor, outlookCalendarDescriptor} from './modules/v2/calendar/module.js';
 // <if expr="not is_official_build">
 export {FooProxy} from './modules/v2/dummy/foo_proxy.js';
 export {DummyModuleElement, dummyV2Descriptor} from './modules/v2/dummy/module.js';
diff --git a/chrome/browser/resources/new_tab_page/modules/module_descriptors.ts b/chrome/browser/resources/new_tab_page/modules/module_descriptors.ts
index 6099fda..e90786ca 100644
--- a/chrome/browser/resources/new_tab_page/modules/module_descriptors.ts
+++ b/chrome/browser/resources/new_tab_page/modules/module_descriptors.ts
@@ -17,7 +17,7 @@
 import type {ModuleDescriptor} from './module_descriptor.js';
 import {ModuleRegistry} from './module_registry.js';
 import {photosDescriptor} from './photos/module.js';
-import {googleCalendarDescriptor} from './v2/calendar/module.js';
+import {googleCalendarDescriptor, outlookCalendarDescriptor} from './v2/calendar/module.js';
 // <if expr="not is_official_build">
 import {dummyV2Descriptor} from './v2/dummy/module.js';
 // </if>
@@ -43,6 +43,7 @@
   descriptors.push(tabResumptionDescriptor);
 }
 descriptors.push(googleCalendarDescriptor);
+descriptors.push(outlookCalendarDescriptor);
 
 // <if expr="not is_official_build">
 if (modulesRedesignedEnabled) {
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/calendar/module.html b/chrome/browser/resources/new_tab_page/modules/v2/calendar/module.html
index cb0c40a..c1c39ca 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/calendar/module.html
+++ b/chrome/browser/resources/new_tab_page/modules/v2/calendar/module.html
@@ -1,4 +1,5 @@
 <ntp-module-header-v2
     id="moduleHeaderElementV2"
-    header-text="[[i18n('modulesGoogleCalendarTitle')]]">
-</ntp-module-header-v2>
\ No newline at end of file
+    header-text="[[i18n('modulesTodayCalendarHeader')]]">
+</ntp-module-header-v2>
+<p>[[calendarSource_]]</p>
\ No newline at end of file
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/calendar/module.ts b/chrome/browser/resources/new_tab_page/modules/v2/calendar/module.ts
index baf4c12..0cc5fb46 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/calendar/module.ts
+++ b/chrome/browser/resources/new_tab_page/modules/v2/calendar/module.ts
@@ -11,6 +11,11 @@
 
 import {getTemplate} from './module.html.js';
 
+export enum CalendarSource {
+  GOOGLE,
+  OUTLOOK,
+}
+
 /**
  * The Calendar module, which serves as an inside look in to upcoming events on
  * a user's Google Calendar or Microsoft Outlook.
@@ -26,16 +31,31 @@
   }
 
   static get properties() {
-    return {};
+    return {
+      calendarSource_: Object,
+    };
+  }
+
+  private calendarSource_: CalendarSource;
+
+  constructor(calendarSource: CalendarSource) {
+    super();
+    this.calendarSource_ = calendarSource;
   }
 }
 
 customElements.define(CalendarModuleElement.is, CalendarModuleElement);
 
-async function createCalendarElement(): Promise<CalendarModuleElement|null> {
+async function createCalendarElement(calendarSource: CalendarSource):
+    Promise<CalendarModuleElement|null> {
   return new Promise<CalendarModuleElement>(
-      (resolve) => resolve(new CalendarModuleElement()));
+      (resolve) => resolve(new CalendarModuleElement(calendarSource)));
 }
 
 export const googleCalendarDescriptor: ModuleDescriptor = new ModuleDescriptor(
-    /*id*/ 'google_calendar', createCalendarElement);
+    /*id*/ 'google_calendar',
+    () => createCalendarElement(CalendarSource.GOOGLE));
+
+export const outlookCalendarDescriptor: ModuleDescriptor = new ModuleDescriptor(
+    /*id*/ 'outlook_calendar',
+    () => createCalendarElement(CalendarSource.OUTLOOK));
diff --git a/chrome/browser/resources/side_panel/customize_chrome/BUILD.gn b/chrome/browser/resources/side_panel/customize_chrome/BUILD.gn
index 022f16d..a0bc59d 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/BUILD.gn
+++ b/chrome/browser/resources/side_panel/customize_chrome/BUILD.gn
@@ -22,7 +22,6 @@
     "cards.ts",
     "categories.ts",
     "check_mark_wrapper.ts",
-    "chrome_colors.ts",
     "hover_button.ts",
     "shortcuts.ts",
     "themes.ts",
diff --git a/chrome/browser/resources/side_panel/customize_chrome/app.html b/chrome/browser/resources/side_panel/customize_chrome/app.html
index 5cfbb91..b44caa9 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/app.html
+++ b/chrome/browser/resources/side_panel/customize_chrome/app.html
@@ -35,7 +35,6 @@
   customize-chrome-cards,
   customize-chrome-categories,
   customize-chrome-themes,
-  customize-chrome-chrome-colors,
   customize-chrome-wallpaper-search,
   customize-chrome-toolbar {
     display: block;
@@ -148,16 +147,12 @@
   <customize-chrome-categories on-back-click="onBackClick_"
       on-collection-select="onCollectionSelect_" page-name="categories"
       id="categoriesPage" on-local-image-upload="onLocalImageUpload_"
-      on-chrome-colors-select="onChromeColorsSelect_"
       on-wallpaper-search-select="onWallpaperSearchSelect_">
   </customize-chrome-categories>
   <customize-chrome-themes on-back-click="onBackClick_"
       page-name="themes" id="themesPage"
       selected-collection="[[selectedCollection_]]">
   </customize-chrome-themes>
-  <customize-chrome-chrome-colors on-back-click="onBackClick_"
-      page-name="chrome-colors" id="chromeColorsPage">
-  </customize-chrome-chrome-colors>
   <template is="dom-if" if="[[wallpaperSearchEnabled_]]">
     <customize-chrome-wallpaper-search on-back-click="onBackClick_"
         page-name="wallpaper-search" id="wallpaperSearchPage">
diff --git a/chrome/browser/resources/side_panel/customize_chrome/app.ts b/chrome/browser/resources/side_panel/customize_chrome/app.ts
index 49bc162..c76066c 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/app.ts
+++ b/chrome/browser/resources/side_panel/customize_chrome/app.ts
@@ -10,7 +10,6 @@
 import './appearance.js';
 import './cards.js';
 import './categories.js';
-import './chrome_colors.js';
 import './shortcuts.js';
 import './themes.js';
 import './toolbar.js';
@@ -26,7 +25,6 @@
 import {getTemplate} from './app.html.js';
 import type {AppearanceElement} from './appearance.js';
 import type {CategoriesElement} from './categories.js';
-import type {ChromeColorsElement} from './chrome_colors.js';
 import type {BackgroundCollection, CustomizeChromePageHandlerInterface} from './customize_chrome.mojom-webui.js';
 import {ChromeWebStoreCategory, ChromeWebStoreCollection, CustomizeChromeSection} from './customize_chrome.mojom-webui.js';
 import {CustomizeChromeApiProxy} from './customize_chrome_api_proxy.js';
@@ -46,7 +44,6 @@
   CATEGORIES = 'categories',
   THEMES = 'themes',
   TOOLBAR = 'toolbar',
-  CHROME_COLORS = 'chrome-colors',
   WALLPAPER_SEARCH = 'wallpaper-search',
 }
 
@@ -59,7 +56,6 @@
     categoriesPage: CategoriesElement,
     themesPage: ThemesElement,
     appearanceElement: AppearanceElement,
-    chromeColorsPage: ChromeColorsElement,
   };
 }
 
@@ -159,7 +155,6 @@
         this.$.appearanceElement.focusOnThemeButton();
         break;
       case CustomizeChromePage.THEMES:
-      case CustomizeChromePage.CHROME_COLORS:
       case CustomizeChromePage.WALLPAPER_SEARCH:
         this.page_ = CustomizeChromePage.CATEGORIES;
         this.$.categoriesPage.focusOnBackButton();
@@ -183,11 +178,6 @@
     this.$.appearanceElement.focusOnThemeButton();
   }
 
-  private onChromeColorsSelect_() {
-    this.page_ = CustomizeChromePage.CHROME_COLORS;
-    this.$.chromeColorsPage.focusOnBackButton();
-  }
-
   private onWallpaperSearchSelect_() {
     this.page_ = CustomizeChromePage.WALLPAPER_SEARCH;
     const page =
diff --git a/chrome/browser/resources/side_panel/customize_chrome/appearance.html b/chrome/browser/resources/side_panel/customize_chrome/appearance.html
index d05ae71..f4e9a73 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/appearance.html
+++ b/chrome/browser/resources/side_panel/customize_chrome/appearance.html
@@ -117,14 +117,14 @@
 </customize-chrome-hover-button>
 <div id="editButtonsContainer">
   <cr-button id="editThemeButton" on-click="onEditThemeClicked_"
-      class$="[[themeButtonClass_]]">
+      class="floating-button">
     <div id="editThemeIcon" class="cr-icon edit-theme-icon" slot="prefix-icon"
         hidden$="[[wallpaperSearchButtonEnabled_]]"></div>
     [[editThemeButtonText_]]
   </cr-button>
   <template is="dom-if" if="[[wallpaperSearchButtonEnabled_]]">
     <cr-button id="wallpaperSearchButton" on-click="onWallpaperSearchClicked_"
-        class$="[[themeButtonClass_]]">
+        class="floating-button">
       <div id="wallpaperSearchIcon" class="cr-icon edit-theme-icon"
           slot="prefix-icon"></div>
       $i18n{wallpaperSearchTileLabel}
@@ -132,10 +132,8 @@
   </template>
 </div>
 <hr class="sp-hr">
-<customize-color-scheme-mode>
-</customize-color-scheme-mode>
-<cr-theme-color-picker id="chromeColors"
-    hidden$="[[!showColorPicker_]]">
+<customize-color-scheme-mode></customize-color-scheme-mode>
+<cr-theme-color-picker id="chromeColors" hidden$="[[!showColorPicker_]]">
 </cr-theme-color-picker>
 <hr class="sp-hr" hidden$="[[!showBottomDivider_]]">
 <div id="followThemeToggle" class="sp-card-content"
diff --git a/chrome/browser/resources/side_panel/customize_chrome/appearance.ts b/chrome/browser/resources/side_panel/customize_chrome/appearance.ts
index 241ee46..23ee73e 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/appearance.ts
+++ b/chrome/browser/resources/side_panel/customize_chrome/appearance.ts
@@ -51,13 +51,6 @@
   static get properties() {
     return {
       theme_: Object,
-      themeButtonClass_: String,
-
-      chromeRefresh2023Enabled_: {
-        type: Boolean,
-        value: () =>
-            document.documentElement.hasAttribute('chrome-refresh-2023'),
-      },
 
       editThemeButtonText_: {
         type: String,
@@ -135,8 +128,6 @@
   }
 
   private theme_: Theme|undefined = undefined;
-  private themeButtonClass_: string;
-  private chromeRefresh2023Enabled_: boolean;
   private editThemeButtonText_:
     string;
   private thirdPartyThemeId_: string|null = null;
@@ -166,8 +157,6 @@
 
   override connectedCallback() {
     super.connectedCallback();
-    this.themeButtonClass_ =
-        this.chromeRefresh2023Enabled_ ? 'floating-button' : 'action-button';
     this.setThemeListenerId_ =
         this.callbackRouter_.setTheme.addListener((theme: Theme) => {
           this.theme_ = theme;
@@ -231,23 +220,20 @@
 
   private computeShowThemeSnapshot_(): boolean {
     return !!this.theme_ && !this.theme_.thirdPartyThemeInfo &&
-        (!this.chromeRefresh2023Enabled_ ||
-         !(this.theme_.backgroundImage &&
+        (!(this.theme_.backgroundImage &&
            this.theme_.backgroundImage.isUploadedImage));
   }
 
   private computeShowUploadedImageButton_(): boolean {
     return !!(
-        this.chromeRefresh2023Enabled_ && this.theme_ &&
-        this.theme_.backgroundImage &&
+        this.theme_ && this.theme_.backgroundImage &&
         this.theme_.backgroundImage.isUploadedImage &&
         !this.theme_.backgroundImage.localBackgroundId);
   }
 
   private computeShowSearchedImageButton_(): boolean {
     return !!(
-        this.chromeRefresh2023Enabled_ && this.theme_ &&
-        this.theme_.backgroundImage &&
+        this.theme_ && this.theme_.backgroundImage &&
         this.theme_.backgroundImage.localBackgroundId);
   }
 
diff --git a/chrome/browser/resources/side_panel/customize_chrome/categories.html b/chrome/browser/resources/side_panel/customize_chrome/categories.html
index d23450b3..bcfa79f3 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/categories.html
+++ b/chrome/browser/resources/side_panel/customize_chrome/categories.html
@@ -232,16 +232,7 @@
       <customize-chrome-check-mark-wrapper
           checked="[[isClassicChromeSelected_]]">
         <div id="cornerNewTabPageTile" class="image-container">
-          <template is="dom-if" if="[[!chromeRefresh2023Enabled_]]">
-            <img id="cornerNewTabPage"
-                src="icons/corner_new_tab_page.svg">
-            </img>
-          </template>
-          <template is="dom-if" if="[[chromeRefresh2023Enabled_]]">
-            <img id="cornerNewTabPage"
-                src="icons/gm3_corner_new_tab_page.svg">
-            </img>
-          </template>
+          <img id="cornerNewTabPage" src="icons/gm3_corner_new_tab_page.svg">
         </div>
       </customize-chrome-check-mark-wrapper>
       <div class="label">$i18n{classicChrome}</div>
@@ -272,25 +263,6 @@
       </customize-chrome-check-mark-wrapper>
       <div class="label">$i18n{uploadImage}</div>
     </div>
-    <template is="dom-if" if="[[!chromeRefresh2023Enabled_]]">
-      <div class="tile" tabindex="0" id="chromeColorsTile"
-          role="button" on-click="onChromeColorsClick_"
-          aria-current$="[[boolToString_(isChromeColorsSelected_)]]">
-        <customize-chrome-check-mark-wrapper
-            checked="[[isChromeColorsSelected_]]">
-          <div class="image-container">
-            <svg viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg"
-                xmlns:xlink="http://www.w3.org/1999/xlink">
-              <rect id="foreground" x="0" y="0" width="50" height="50">
-              </rect>
-              <rect id="background" x="0" y="25" width="50" height="25">
-              </rect>
-            </svg>
-          </div>
-        </customize-chrome-check-mark-wrapper>
-        <div class="label">$i18n{chromeColors}</div>
-      </div>
-    </template>
     <template is="dom-repeat" id="collectionsRepeat" items="[[collections_]]"
         on-rendered-item-count-changed="onCollectionsRendered_">
       <div class="tile collection" tabindex="0" role="button"
diff --git a/chrome/browser/resources/side_panel/customize_chrome/categories.ts b/chrome/browser/resources/side_panel/customize_chrome/categories.ts
index f9983c0..f01d3a3 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/categories.ts
+++ b/chrome/browser/resources/side_panel/customize_chrome/categories.ts
@@ -69,11 +69,6 @@
 
   static get properties() {
     return {
-      chromeRefresh2023Enabled_: {
-        type: Boolean,
-        value: () =>
-            document.documentElement.hasAttribute('chrome-refresh-2023'),
-      },
       collections_: Array,
       theme_: Object,
       selectedCategory_: {
@@ -92,10 +87,6 @@
         type: Boolean,
         computed: 'computeIsWallpaperSearchSelected_(selectedCategory_)',
       },
-      isChromeColorsSelected_: {
-        type: Boolean,
-        computed: 'computeIsChromeColorsSelected_(selectedCategory_)',
-      },
       wallpaperSearchEnabled_: {
         type: Boolean,
         value: () => loadTimeData.getBoolean('wallpaperSearchEnabled'),
@@ -205,10 +196,6 @@
     return this.selectedCategory_.type === CategoryType.WALLPAPER_SEARCH;
   }
 
-  private computeIsChromeColorsSelected_() {
-    return this.selectedCategory_.type === CategoryType.COLOR;
-  }
-
   private isCollectionSelected_(id: string) {
     return this.selectedCategory_.type === CategoryType.COLLECTION &&
         this.selectedCategory_.collectionId === id;
@@ -246,10 +233,6 @@
     }
   }
 
-  private async onChromeColorsClick_() {
-    this.dispatchEvent(new Event('chrome-colors-select'));
-  }
-
   private onCollectionClick_(e: DomRepeatEvent<BackgroundCollection>) {
     recordCustomizeChromeAction(
         CustomizeChromeAction.CATEGORIES_FIRST_PARTY_COLLECTION_SELECTED);
diff --git a/chrome/browser/resources/side_panel/customize_chrome/chrome_colors.html b/chrome/browser/resources/side_panel/customize_chrome/chrome_colors.html
deleted file mode 100644
index 1354bf4..0000000
--- a/chrome/browser/resources/side_panel/customize_chrome/chrome_colors.html
+++ /dev/null
@@ -1,118 +0,0 @@
-<style include="cr-hidden-style cr-icons sp-shared-style">
-  sp-heading {
-    margin: 0 0 8px;
-  }
-
-  cr-grid {
-    --cr-column-width: 1fr;
-    --cr-grid-gap: 16px 12px;
-    --cr-grid-width: 100%;
-    display: block;
-    padding: 0 16px 32px;
-  }
-
-  .tile {
-    cursor: pointer;
-    outline-width: 0;
-    place-self: stretch;
-  }
-
-  :host-context(.focus-outline-visible) #customColorContainer:focus {
-    box-shadow: 0 0 0 2px var(--cr-focus-outline-color);
-  }
-
-  #customColorContainer {
-    position: relative;
-  }
-
-  #colorPicker {
-    bottom: 0;
-    opacity: 0;
-    pointer-events: none;
-    position: absolute;
-  }
-
-  #colorPickerIcon {
-    -webkit-mask-image: url(chrome://resources/cr_components/customize_themes/colorize.svg);
-    -webkit-mask-repeat: no-repeat;
-    -webkit-mask-size: 100%;
-    background-color: var(--google-grey-700);
-    height: 20px;
-    left: calc(50% - 10px);
-    pointer-events: none;
-    position: absolute;
-    top: calc(50% - 10px);
-    width: 20px;
-  }
-
-  cr-theme-color {
-    --cr-theme-color-border-radius: 12px;
-    --cr-theme-color-check-mark-end: -4px;
-    --cr-theme-color-check-mark-size: 20px;
-    --cr-theme-color-check-mark-top: -6px;
-    padding: 0;
-  }
-
-  /* Set styles for high contrast mode in Windows. */
-  @media (forced-colors: active) {
-    :host-context(.focus-outline-visible) #customColorContainer:focus {
-      /* Set outline to hcm (high contrast mode) value. */
-      outline: var(--cr-focus-outline-hcm);
-    }
-  }
-</style>
-<div class="sp-card">
-  <sp-heading id="heading" on-back-button-click="onBackClick_"
-      back-button-aria-label="$i18n{backButton}"
-      back-button-title="$i18n{backButton}">
-    <h2 slot="heading">$i18n{chromeColors}</h2>
-  </sp-heading>
-  <cr-grid columns="3" disable-arrow-navigation>
-    <div id="customColorContainer"
-        class="tile"
-        title="$i18n{colorPickerLabel}"
-        aria-label$="$i18n{colorPickerLabel}"
-        role="button"
-        aria-current$="[[boolToString_(isCustomColorSelected_)]]"
-        tabindex="0">
-      <cr-theme-color
-          id="customColor"
-          background-color="[[customColor_.background]]"
-          foreground-color="[[customColor_.foreground]]"
-          checked="[[isCustomColorSelected_]]"
-          on-click="onCustomColorClick_">
-      </cr-theme-color>
-      <div id="colorPickerIcon"></div>
-      <input id="colorPicker" type="color" tabindex="-1" aria-hidden="true"
-          on-change="onCustomColorChange_">
-    </div>
-    <cr-theme-color
-        id="defaultColor"
-        class="tile"
-        title="$i18n{defaultColorName}"
-        aria-label$="$i18n{defaultColorName}"
-        role="button"
-        aria-current$="[[boolToString_(isDefaultColorSelected_)]]"
-        tabindex="0"
-        on-click="onDefaultColorClick_"
-        background-color="[[defaultColor_.background]]"
-        foreground-color="[[defaultColor_.foreground]]"
-        checked="[[isDefaultColorSelected_]]">
-    </cr-theme-color>
-    <template is="dom-repeat" id="chromeColorsRepeat" items="[[colors_]]">
-      <cr-theme-color
-          class="chrome-color tile"
-          title="[[item.name]]"
-          aria-label$="[[item.name]]"
-          role="button"
-          aria-current$=
-              "[[getChromeColorCheckedStatus_(item.seed, selectedColor_)]]"
-          tabindex="0"
-          on-click="onChromeColorClick_"
-          background-color="[[item.background]]"
-          foreground-color="[[item.foreground]]"
-          checked="[[isChromeColorSelected_(item.seed, selectedColor_)]]">
-      </cr-theme-color>
-    </template>
-  </cr-grid>
-</div>
diff --git a/chrome/browser/resources/side_panel/customize_chrome/chrome_colors.ts b/chrome/browser/resources/side_panel/customize_chrome/chrome_colors.ts
deleted file mode 100644
index a5fd8f5..0000000
--- a/chrome/browser/resources/side_panel/customize_chrome/chrome_colors.ts
+++ /dev/null
@@ -1,223 +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.
-
-import 'chrome://customize-chrome-side-panel.top-chrome/shared/sp_heading.js';
-import 'chrome://customize-chrome-side-panel.top-chrome/shared/sp_shared_style.css.js';
-import 'chrome://resources/cr_components/theme_color_picker/theme_color.js';
-import 'chrome://resources/cr_elements/cr_hidden_style.css.js';
-import 'chrome://resources/cr_elements/cr_grid/cr_grid.js';
-import 'chrome://resources/cr_elements/cr_icons.css.js';
-import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
-
-import type {SpHeading} from 'chrome://customize-chrome-side-panel.top-chrome/shared/sp_heading.js';
-import {ThemeColorPickerBrowserProxy} from 'chrome://resources/cr_components/theme_color_picker/browser_proxy.js';
-import type {Color, SelectedColor} from 'chrome://resources/cr_components/theme_color_picker/color_utils.js';
-import {ColorType, DARK_DEFAULT_COLOR, LIGHT_DEFAULT_COLOR} from 'chrome://resources/cr_components/theme_color_picker/color_utils.js';
-import type {ThemeColorElement} from 'chrome://resources/cr_components/theme_color_picker/theme_color.js';
-import type {ChromeColor, Theme, ThemeColorPickerHandlerInterface} from 'chrome://resources/cr_components/theme_color_picker/theme_color_picker.mojom-webui.js';
-import {hexColorToSkColor, skColorToRgba} from 'chrome://resources/js/color_utils.js';
-import {FocusOutlineManager} from 'chrome://resources/js/focus_outline_manager.js';
-import type {SkColor} from 'chrome://resources/mojo/skia/public/mojom/skcolor.mojom-webui.js';
-import {BrowserColorVariant} from 'chrome://resources/mojo/ui/base/mojom/themes.mojom-webui.js';
-import type {DomRepeatEvent} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {getTemplate} from './chrome_colors.html.js';
-import {CustomizeChromeAction, recordCustomizeChromeAction} from './common.js';
-
-export interface ChromeColorsElement {
-  $: {
-    colorPicker: HTMLInputElement,
-    colorPickerIcon: HTMLElement,
-    defaultColor: ThemeColorElement,
-    customColor: ThemeColorElement,
-    customColorContainer: HTMLElement,
-    heading: SpHeading,
-  };
-}
-
-export class ChromeColorsElement extends PolymerElement {
-  static get is() {
-    return 'customize-chrome-chrome-colors';
-  }
-
-  static get template() {
-    return getTemplate();
-  }
-
-  static get properties() {
-    return {
-      defaultColor_: {
-        type: Object,
-        computed: 'computeDefaultColor_(theme_)',
-      },
-      colors_: Array,
-      theme_: Object,
-      selectedColor_: {
-        type: Object,
-        computed: 'computeSelectedColor_(theme_, colors_)',
-      },
-      isDefaultColorSelected_: {
-        type: Object,
-        computed: 'computeIsDefaultColorSelected_(selectedColor_)',
-      },
-      isCustomColorSelected_: {
-        type: Object,
-        computed: 'computeIsCustomColorSelected_(selectedColor_)',
-      },
-      customColor_: {
-        type: Object,
-        value: {
-          background: {value: 0xffffffff},
-          foreground: {value: 0xfff1f3f4},
-        },
-      },
-    };
-  }
-
-  static get observers() {
-    return [
-      'updateCustomColor_(colors_, theme_, isCustomColorSelected_)',
-    ];
-  }
-
-  private colors_: ChromeColor[];
-  private theme_: Theme;
-  private setThemeListenerId_: number|null = null;
-  private isCustomColorSelected_: boolean;
-  private customColor_: Color;
-  private selectedColor_: SelectedColor;
-
-  private pageHandler_: ThemeColorPickerHandlerInterface;
-
-  constructor() {
-    super();
-    this.pageHandler_ = ThemeColorPickerBrowserProxy.getInstance().handler;
-    this.pageHandler_
-        .getChromeColors(
-            /* isDarkMode (unimportant for this component) */ false,
-            /* extendedList */ true)
-        .then(({colors}) => {
-          this.colors_ = colors;
-        });
-  }
-
-  override connectedCallback() {
-    super.connectedCallback();
-    this.setThemeListenerId_ =
-        ThemeColorPickerBrowserProxy.getInstance()
-            .callbackRouter.setTheme.addListener((theme: Theme) => {
-              this.theme_ = theme;
-            });
-    this.pageHandler_.updateTheme();
-    FocusOutlineManager.forDocument(document);
-  }
-
-  override disconnectedCallback() {
-    super.disconnectedCallback();
-    ThemeColorPickerBrowserProxy.getInstance().callbackRouter.removeListener(
-        this.setThemeListenerId_!);
-  }
-
-  focusOnBackButton() {
-    this.$.heading.getBackButton().focus();
-  }
-
-  private computeIsDefaultColorSelected_(): boolean {
-    return this.selectedColor_.type === ColorType.DEFAULT;
-  }
-
-  private computeIsCustomColorSelected_(): boolean {
-    return this.selectedColor_.type === ColorType.CUSTOM;
-  }
-
-  private computeSelectedColor_(): SelectedColor {
-    // None will be considered selected if it isn't classic chrome.
-    if (!this.colors_ || !this.theme_ || this.theme_.hasBackgroundImage ||
-        this.theme_.hasThirdPartyTheme) {
-      return {type: ColorType.NONE};
-    }
-    if (!this.theme_.foregroundColor) {
-      return {type: ColorType.DEFAULT};
-    }
-    if (this.colors_.find(
-            (color: ChromeColor) =>
-                color.seed.value === this.theme_.seedColor.value)) {
-      return {
-        type: ColorType.CHROME,
-        chromeColor: this.theme_.seedColor,
-      };
-    }
-    return {type: ColorType.CUSTOM};
-  }
-
-  private computeDefaultColor_(): Color {
-    return this.theme_.isDarkMode ? DARK_DEFAULT_COLOR : LIGHT_DEFAULT_COLOR;
-  }
-
-  private isChromeColorSelected_(color: SkColor): boolean {
-    return this.selectedColor_.type === ColorType.CHROME &&
-        this.selectedColor_.chromeColor!.value === color.value;
-  }
-
-  private boolToString_(value: boolean): string {
-    return value ? 'true' : 'false';
-  }
-
-  private getChromeColorCheckedStatus_(color: SkColor): string {
-    return this.boolToString_(this.isChromeColorSelected_(color));
-  }
-
-  private onBackClick_() {
-    this.dispatchEvent(new Event('back-click'));
-  }
-
-  private onDefaultColorClick_() {
-    recordCustomizeChromeAction(CustomizeChromeAction.DEFAULT_COLOR_CLICKED);
-    this.pageHandler_.setDefaultColor();
-    this.pageHandler_.removeBackgroundImage();
-  }
-
-  private onChromeColorClick_(e: DomRepeatEvent<ChromeColor>) {
-    recordCustomizeChromeAction(CustomizeChromeAction.CHROME_COLOR_CLICKED);
-    this.pageHandler_.setSeedColor(
-        e.model.item.seed, BrowserColorVariant.kTonalSpot);
-    this.pageHandler_.removeBackgroundImage();
-  }
-
-  private onCustomColorClick_() {
-    recordCustomizeChromeAction(CustomizeChromeAction.CUSTOM_COLOR_CLICKED);
-    this.$.colorPicker.focus();
-    this.$.colorPicker.click();
-  }
-
-  private onCustomColorChange_(e: Event) {
-    this.pageHandler_.setSeedColor(
-        hexColorToSkColor((e.target as HTMLInputElement).value),
-        BrowserColorVariant.kTonalSpot);
-    this.pageHandler_.removeBackgroundImage();
-  }
-
-  private updateCustomColor_() {
-    // We only change the custom color when theme updates to a new custom color
-    // so that the picked color persists while clicking on other color circles.
-    if (!this.isCustomColorSelected_) {
-      return;
-    }
-    this.customColor_ = {
-      background: this.theme_.backgroundColor,
-      foreground: this.theme_.foregroundColor!,
-    };
-    this.$.colorPickerIcon.style.setProperty(
-        'background-color', skColorToRgba(this.theme_.colorPickerIconColor));
-  }
-}
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'customize-chrome-chrome-colors': ChromeColorsElement;
-  }
-}
-
-customElements.define(ChromeColorsElement.is, ChromeColorsElement);
diff --git a/chrome/browser/resources/side_panel/customize_chrome/customize_chrome.html b/chrome/browser/resources/side_panel/customize_chrome/customize_chrome.html
index 99697b22..50d1faf 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/customize_chrome.html
+++ b/chrome/browser/resources/side_panel/customize_chrome/customize_chrome.html
@@ -1,12 +1,10 @@
 <!doctype html>
-<html dir="$i18n{textdirection}" lang="$i18n{language}"
-    $i18n{chromeRefresh2023Attribute}>
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
   <head>
     <meta charset="utf-8">
     <title>$i18n{title}</title>
     <meta name="color-scheme" content="light dark">
     <link rel="stylesheet" href="chrome://theme/colors.css?sets=ui,chrome">
-    <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
     <style>
       html,
       body {
@@ -17,18 +15,8 @@
       }
 
       body {
-        background: white;
-        overflow: auto;
-      }
-
-      @media (prefers-color-scheme: dark) {
-        body {
-          background: var(--google-grey-900);
-        }
-      }
-
-      html[chrome-refresh-2023] body {
         background: var(--color-side-panel-content-background);
+        overflow: auto;
       }
     </style>
   </head>
diff --git a/chrome/browser/resources/side_panel/customize_chrome/icons/BUILD.gn b/chrome/browser/resources/side_panel/customize_chrome/icons/BUILD.gn
index 1f3835be..260c2c6 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/icons/BUILD.gn
+++ b/chrome/browser/resources/side_panel/customize_chrome/icons/BUILD.gn
@@ -12,7 +12,6 @@
   input_files = [
     "collapse_carets.svg",
     "chrome_web_store.svg",
-    "corner_new_tab_page.svg",
     "coupons.svg",
     "delete.svg",
     "expand_carets.svg",
@@ -20,7 +19,6 @@
     "gm3_corner_new_tab_page.svg",
     "gm3_mini_new_tab_page.svg",
     "image.svg",
-    "mini_new_tab_page.svg",
     "productivity.svg",
     "reset.svg",
     "sparkle.svg",
diff --git a/chrome/browser/resources/side_panel/customize_chrome/icons/corner_new_tab_page.svg b/chrome/browser/resources/side_panel/customize_chrome/icons/corner_new_tab_page.svg
deleted file mode 100644
index 92c9460..0000000
--- a/chrome/browser/resources/side_panel/customize_chrome/icons/corner_new_tab_page.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="120" height="116" viewBox="0 0 120 116" fill="none" xmlns="http://www.w3.org/2000/svg"><g filter="url(#a)"><g clip-path="url(#b)"><rect x="4" width="240" height="122" rx="8" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M89.164 49.53c-3.181 0-5.854-2.588-5.854-5.765 0-3.176 2.673-5.765 5.854-5.765 1.761 0 3.014.687 3.957 1.592L92.01 40.7c-.676-.632-1.594-1.127-2.847-1.127-2.325 0-4.142 1.87-4.142 4.192s1.817 4.193 4.142 4.193c1.507 0 2.363-.608 2.915-1.152.453-.452.744-1.096.856-1.982h-3.77v-1.579h5.308c.055.279.086.62.086.985 0 1.183-.322 2.644-1.364 3.685-1.017 1.052-2.307 1.616-4.03 1.616" fill="#4285F4"/><path fill-rule="evenodd" clip-rule="evenodd" d="M101.246 45.884c0-1.347-.957-2.265-2.064-2.265-1.106 0-2.063.924-2.063 2.265 0 1.33.957 2.265 2.063 2.265 1.107 0 2.064-.93 2.064-2.265m1.61 0c0 2.153-1.647 3.737-3.673 3.737-2.027 0-3.674-1.584-3.674-3.737 0-2.165 1.647-3.737 3.674-3.737 2.026 0 3.673 1.572 3.673 3.737" fill="#E94235"/><path fill-rule="evenodd" clip-rule="evenodd" d="M109.43 45.884c0-1.347-.957-2.265-2.063-2.265-1.107 0-2.064.924-2.064 2.265 0 1.33.957 2.265 2.064 2.265 1.106.007 2.063-.93 2.063-2.265m1.603 0c0 2.153-1.647 3.737-3.673 3.737-2.02 0-3.673-1.584-3.673-3.737 0-2.165 1.647-3.737 3.673-3.737s3.673 1.572 3.673 3.737" fill="#FABB05"/><path fill-rule="evenodd" clip-rule="evenodd" d="M117.507 45.895c0-1.312-.867-2.276-1.969-2.276-1.119 0-2.055.958-2.055 2.276 0 1.299.936 2.244 2.055 2.244 1.102 0 1.969-.945 1.969-2.244Zm1.428-3.519v6.689c0 2.754-1.606 3.879-3.507 3.879-1.791 0-2.861-1.212-3.267-2.2l1.409-.591c.252.61.868 1.324 1.858 1.324 1.219 0 1.969-.765 1.969-2.188v-.535h-.056c-.362.455-1.064.846-1.944.846-1.846 0-3.532-1.623-3.532-3.712 0-2.1 1.692-3.741 3.532-3.741.88 0 1.582.397 1.944.832h.056v-.602h1.538Z" fill="#4285F4"/><rect x="61" y="57.501" width="91" height="7.15" rx="3.575" fill="#E8EAED"/><path fill="#DADCE0" d="M4 0h240v23H4z"/><path fill="#fff" d="M4 12.67h239.97v10.905H4z"/><mask id="c" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="8" y="15" width="5" height="6"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.778 19.598 9.45 18.27h2.801a.295.295 0 0 0 0-.59H9.45l1.328-1.328-.026-.025a.295.295 0 0 0-.389-.39l-.025-.025L8.42 17.83l-.02.026a.293.293 0 0 0 0 .24l.02.026 1.918 1.917.025-.025a.295.295 0 0 0 .39-.39l.025-.025Z" fill="#fff"/></mask><g mask="url(#c)"><path fill="#BDC1C6" d="M8.125 15.617h4.715v4.715H8.125z"/></g><mask id="d" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="17" y="15" width="5" height="6"><path fill-rule="evenodd" clip-rule="evenodd" d="m19.62 19.598 1.329-1.328h-2.802a.295.295 0 0 1 0-.59h2.802l-1.328-1.328.025-.025a.295.295 0 0 1 .39-.39l.025-.025 1.918 1.917-.026.026a.294.294 0 0 1 0 .24l.026.026-1.918 1.917-.026-.025a.294.294 0 0 1-.389-.39l-.025-.025Z" fill="#fff"/></mask><g mask="url(#d)"><path fill="#BDC1C6" d="M17.558 15.617h4.715v4.715h-4.715z"/></g><path fill-rule="evenodd" clip-rule="evenodd" d="M31.408 15.912v1.768h-1.769l.771-.776c-.28-.276-.64-.402-1.065-.402-.859 0-1.474.619-1.474 1.473 0 .855.615 1.474 1.474 1.474.677 0 1.202-.35 1.4-.934l.004-.012c.048-.103.207-.18.292-.18.115 0 .305.067.305.243a.617.617 0 0 1-.038.166c-.295.755-1.085 1.306-1.954 1.306a2.068 2.068 0 0 1-2.072-2.063c0-1.14.927-2.063 2.072-2.063.568 0 1.083.228 1.457.597l.597-.597Z" fill="#000"/><mask id="e" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="27" y="15" width="5" height="6"><path fill-rule="evenodd" clip-rule="evenodd" d="M31.408 15.912v1.768h-1.769l.771-.776c-.28-.276-.64-.402-1.065-.402-.859 0-1.474.619-1.474 1.473 0 .855.615 1.474 1.474 1.474.677 0 1.202-.35 1.4-.934l.004-.012c.048-.103.207-.18.292-.18.115 0 .305.067.305.243a.617.617 0 0 1-.038.166c-.295.755-1.085 1.306-1.954 1.306a2.068 2.068 0 0 1-2.072-2.063c0-1.14.927-2.063 2.072-2.063.568 0 1.083.228 1.457.597l.597-.597Z" fill="#fff"/></mask><g mask="url(#e)"><path fill="#5F6368" d="M26.987 15.617h4.715v4.715h-4.715z"/></g><path fill-rule="evenodd" clip-rule="evenodd" d="M39 15a3 3 0 1 0 0 6h179a3 3 0 1 0 0-6H39Z" fill="#F1F3F4"/><path fill="#202124" fill-opacity=".28" d="M85.634 4.715h.295v5.894h-.295z"/><path d="M15.2 4.99a2.358 2.358 0 0 1 2.357-2.358h65.98a2.358 2.358 0 0 1 2.357 2.358v7.662H15.2V4.99Z" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M15.2 10.295v2.358h-2.653v-.019a2.358 2.358 0 0 0 2.652-2.34Zm70.694 0v2.358h2.653v-.019a2.358 2.358 0 0 1-2.652-2.34Z" fill="#DADCE0"/><path fill-rule="evenodd" clip-rule="evenodd" d="M79.953 6.483a.21.21 0 0 1 .172.09l.796.796.793-.79a.21.21 0 1 1 .32.271l.001.003-.818.81.79.791a.21.21 0 1 1-.29.297l-.796-.794-.791.784a.21.21 0 1 1-.316-.27l.813-.809-.804-.803a.21.21 0 0 1 .13-.376Z" fill="#5F6368"/><g clip-path="url(#f)"><path d="M21.129 8.715V6.783h.028l1.352 1.932h.302V6.223h-.307v1.94h-.028l-1.352-1.94h-.302v2.492h.307Zm3.512-.482c-.077.164-.24.252-.48.252-.316 0-.521-.233-.537-.6V7.87h1.338v-.114c0-.578-.305-.935-.808-.935-.51 0-.839.38-.839.965 0 .589.323.962.84.962.407 0 .697-.197.783-.515h-.297Zm-.49-1.15c.295 0 .492.218.499.547h-1.026c.023-.33.23-.547.527-.547Zm3.62-.23h-.3l-.366 1.489h-.027l-.416-1.489h-.285l-.416 1.489h-.028l-.366-1.489h-.3l.521 1.862h.3l.415-1.44h.027l.417 1.44h.302l.521-1.862Zm1.519-.481v.481h-.3v.249h.3v1.13c0 .355.154.497.537.497a.995.995 0 0 0 .174-.018v-.25a1.255 1.255 0 0 1-.138.007c-.193 0-.276-.093-.276-.313V7.102H30v-.249h-.414v-.481h-.297Zm1.678 2.376a.643.643 0 0 0 .574-.308h.027v.275h.284V7.44c0-.386-.254-.62-.709-.62-.397 0-.69.197-.73.496h.3c.042-.147.197-.231.42-.231.278 0 .421.126.421.355v.17l-.537.032c-.433.026-.678.218-.678.551 0 .34.268.555.628.555Zm.056-.261c-.216 0-.377-.11-.377-.3 0-.187.125-.285.408-.304l.5-.033v.17c0 .267-.226.467-.531.467Zm2.303.26c.472 0 .78-.381.78-.963 0-.585-.307-.963-.78-.963-.255 0-.482.126-.583.326h-.028V6.114h-.297v2.6h.283v-.296h.028c.117.207.338.33.597.33Zm-.069-1.659c.34 0 .542.26.542.696 0 .435-.202.696-.542.696-.338 0-.549-.266-.549-.696 0-.43.21-.696.55-.696Z" fill="#202124"/></g><path fill-rule="evenodd" clip-rule="evenodd" d="M92.358 5.59c.162 0 .294.132.294.295v1.179h1.18a.295.295 0 0 1 0 .59h-1.18v1.178a.295.295 0 1 1-.589 0V7.653h-1.179a.295.295 0 1 1 0-.589h1.179V5.885c0-.163.132-.295.295-.295Z" fill="#000"/><mask id="g" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="90" y="5" width="5" height="5"><path fill-rule="evenodd" clip-rule="evenodd" d="M92.358 5.59c.162 0 .294.132.294.295v1.179h1.18a.295.295 0 0 1 0 .59h-1.18v1.178a.295.295 0 1 1-.589 0V7.653h-1.179a.295.295 0 1 1 0-.589h1.179V5.885c0-.163.132-.295.295-.295Z" fill="#fff"/></mask><g mask="url(#g)"><path fill="#5F6368" d="M94.716 9.716H90V5h4.715z"/></g><path stroke="#000" stroke-opacity=".14" stroke-width=".3" d="M4 25.85h256"/></g></g><defs><clipPath id="b"><rect x="4" width="240" height="122" rx="8" fill="#fff"/></clipPath><clipPath id="f"><path fill="#fff" transform="translate(20.504 4.715)" d="M0 0h51.869v5.894H0z"/></clipPath><filter id="a" x="0" y="0" width="248" height="130" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/><feOffset dy="4"/><feGaussianBlur stdDeviation="2"/><feComposite in2="hardAlpha" operator="out"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/><feBlend in2="BackgroundImageFix" result="effect1_dropShadow_2338_309339"/><feBlend in="SourceGraphic" in2="effect1_dropShadow_2338_309339" result="shape"/></filter></defs></svg>
\ No newline at end of file
diff --git a/chrome/browser/resources/side_panel/customize_chrome/icons/mini_new_tab_page.svg b/chrome/browser/resources/side_panel/customize_chrome/icons/mini_new_tab_page.svg
deleted file mode 100644
index 8916d4a..0000000
--- a/chrome/browser/resources/side_panel/customize_chrome/icons/mini_new_tab_page.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="256" height="130" viewBox="0 0 256 130" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="256" height="130" rx="8" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M110.164 50.53c-3.181 0-5.854-2.588-5.854-5.765 0-3.176 2.673-5.765 5.854-5.765 1.761 0 3.014.687 3.956 1.592l-1.11 1.108c-.676-.632-1.593-1.127-2.846-1.127-2.326 0-4.143 1.87-4.143 4.192s1.817 4.193 4.143 4.193c1.507 0 2.363-.608 2.915-1.152.452-.452.744-1.096.855-1.982h-3.77v-1.579h5.308c.056.279.087.62.087.985 0 1.183-.322 2.644-1.364 3.685-1.017 1.052-2.307 1.616-4.031 1.616" fill="#4285F4"/><path fill-rule="evenodd" clip-rule="evenodd" d="M122.246 46.884c0-1.347-.958-2.265-2.064-2.265s-2.064.924-2.064 2.265c0 1.33.958 2.265 2.064 2.265s2.064-.93 2.064-2.265m1.61 0c0 2.153-1.647 3.737-3.674 3.737-2.026 0-3.673-1.584-3.673-3.737 0-2.165 1.647-3.737 3.673-3.737 2.027 0 3.674 1.572 3.674 3.737" fill="#E94235"/><path fill-rule="evenodd" clip-rule="evenodd" d="M130.43 46.884c0-1.347-.957-2.265-2.063-2.265-1.107 0-2.064.924-2.064 2.265 0 1.33.957 2.265 2.064 2.265 1.106.007 2.063-.93 2.063-2.265m1.603 0c0 2.153-1.647 3.737-3.673 3.737-2.02 0-3.673-1.584-3.673-3.737 0-2.165 1.647-3.737 3.673-3.737s3.673 1.572 3.673 3.737" fill="#FABB05"/><path fill-rule="evenodd" clip-rule="evenodd" d="M138.507 46.895c0-1.312-.868-2.276-1.969-2.276-1.12 0-2.055.958-2.055 2.276 0 1.299.935 2.244 2.055 2.244 1.101 0 1.969-.945 1.969-2.244Zm1.427-3.519v6.689c0 2.754-1.606 3.879-3.507 3.879-1.79 0-2.86-1.212-3.266-2.2l1.409-.591c.252.61.867 1.324 1.857 1.324 1.219 0 1.969-.765 1.969-2.188v-.535h-.055c-.363.455-1.065.846-1.945.846-1.845 0-3.531-1.623-3.531-3.712 0-2.1 1.692-3.741 3.531-3.741.88 0 1.582.397 1.945.832h.055v-.602h1.538Z" fill="#4285F4"/><path fill-rule="evenodd" clip-rule="evenodd" d="M141.321 50.345h1.663V39.409h-1.663v10.936Z" fill="#34A853"/><path fill-rule="evenodd" clip-rule="evenodd" d="m145.382 46.766 3.319-1.386c-.185-.468-.73-.792-1.381-.792-.83 0-1.981.736-1.938 2.178m3.895 1.347 1.263.849c-.409.611-1.393 1.66-3.096 1.66-2.112 0-3.628-1.642-3.628-3.738 0-2.221 1.535-3.737 3.448-3.737 1.926 0 2.867 1.54 3.177 2.377l.167.424-4.959 2.072c.377.748.971 1.135 1.801 1.135.831 0 1.406-.418 1.827-1.042" fill="#E94235"/><path fill-rule="evenodd" clip-rule="evenodd" d="M82 62.076c0-1.974 1.6-3.575 3.575-3.575h83.85a3.575 3.575 0 0 1 0 7.15h-83.85A3.575 3.575 0 0 1 82 62.076Zm9.102 20.476a3.9 3.9 0 1 0 0-7.8 3.9 3.9 0 0 0 0 7.8Zm40.297-3.9a3.9 3.9 0 1 1-7.8 0 3.9 3.9 0 0 1 7.8 0Zm-22.1 3.9a3.9 3.9 0 1 0 0-7.8 3.9 3.9 0 0 0 0 7.8Zm40.298-3.9a3.9 3.9 0 1 1-7.8 0 3.9 3.9 0 0 1 7.8 0Zm14.3 3.9a3.9 3.9 0 1 0 0-7.8 3.9 3.9 0 0 0 0 7.8Zm-68.895 16.9a3.9 3.9 0 1 1-7.8 0 3.9 3.9 0 0 1 7.8 0Zm32.497 3.9a3.9 3.9 0 1 0 0-7.8 3.9 3.9 0 0 0 0 7.8Zm-14.3-3.9a3.9 3.9 0 1 1-7.8 0 3.9 3.9 0 0 1 7.8 0Zm32.498 3.9a3.9 3.9 0 1 0 0-7.8 3.9 3.9 0 0 0 0 7.8Zm22.1-3.9a3.9 3.9 0 1 1-7.8 0 3.9 3.9 0 0 1 7.8 0Z" fill="#E8EAED"/><path stroke="#000" stroke-opacity=".14" stroke-width=".3" d="M0 25.85h256"/><rect width="256" height="23" rx="8" fill="#DADCE0"/><path fill="#fff" d="M0 12.67h255.97v10.905H0z"/><mask id="a" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="4" y="15" width="5" height="6"><path fill-rule="evenodd" clip-rule="evenodd" d="M6.777 19.598 5.45 18.27h2.802a.295.295 0 0 0 0-.59H5.449l1.329-1.328-.026-.025a.294.294 0 0 0-.27-.415.293.293 0 0 0-.12.026l-.025-.026L4.42 17.83l-.021.026a.294.294 0 0 0 0 .24l.02.026 1.918 1.917.026-.025a.295.295 0 0 0 .389-.39l.026-.025Z" fill="#fff"/></mask><g mask="url(#a)"><path fill="#BDC1C6" d="M4.125 15.617H8.84v4.715H4.125z"/></g><mask id="b" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="13" y="15" width="5" height="6"><path fill-rule="evenodd" clip-rule="evenodd" d="m15.62 19.598 1.329-1.328h-2.802a.295.295 0 0 1 0-.59h2.802l-1.328-1.328.025-.025a.295.295 0 0 1 .39-.39l.025-.025 1.918 1.917-.026.026a.294.294 0 0 1 0 .24l.026.026-1.918 1.917-.026-.025a.294.294 0 0 1-.389-.39l-.025-.025Z" fill="#fff"/></mask><g mask="url(#b)"><path fill="#BDC1C6" d="M13.558 15.617h4.715v4.715h-4.715z"/></g><path fill-rule="evenodd" clip-rule="evenodd" d="M27.407 15.912v1.768H25.64l.77-.776c-.28-.276-.639-.402-1.065-.402-.858 0-1.473.619-1.473 1.473 0 .855.615 1.474 1.473 1.474.677 0 1.203-.35 1.4-.934l.005-.012c.048-.103.206-.18.292-.18.114 0 .305.067.305.243a.617.617 0 0 1-.038.166c-.296.755-1.085 1.306-1.955 1.306a2.068 2.068 0 0 1-2.072-2.063c0-1.14.928-2.063 2.072-2.063.569 0 1.083.228 1.457.597l.597-.597Z" fill="#000"/><mask id="c" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="23" y="15" width="5" height="6"><path fill-rule="evenodd" clip-rule="evenodd" d="M27.407 15.912v1.768H25.64l.77-.776c-.28-.276-.639-.402-1.065-.402-.858 0-1.473.619-1.473 1.473 0 .855.615 1.474 1.473 1.474.677 0 1.203-.35 1.4-.934l.005-.012c.048-.103.206-.18.292-.18.114 0 .305.067.305.243a.617.617 0 0 1-.038.166c-.296.755-1.085 1.306-1.955 1.306a2.068 2.068 0 0 1-2.072-2.063c0-1.14.928-2.063 2.072-2.063.569 0 1.083.228 1.457.597l.597-.597Z" fill="#fff"/></mask><g mask="url(#c)"><path fill="#5F6368" d="M22.987 15.617h4.715v4.715h-4.715z"/></g><path fill-rule="evenodd" clip-rule="evenodd" d="M35 15a3 3 0 1 0 0 6h195a3 3 0 1 0 0-6H35Z" fill="#F1F3F4"/><circle cx="239.76" cy="17.975" r="3.242" fill="#1A73E8"/><g clip-path="url(#d)"><circle cx="239.76" cy="17.974" r="3.242" fill="#C4C4C4"/></g><path fill-rule="evenodd" clip-rule="evenodd" d="M248.896 16.647a.441.441 0 1 1 .442.442.441.441 0 0 1-.442-.442Zm0 1.473a.441.441 0 1 1 .442.442.441.441 0 0 1-.442-.442Zm0 1.474a.441.441 0 1 1 .442.442.441.441 0 0 1-.442-.442Z" fill="#000"/><mask id="e" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="248" y="16" width="2" height="5"><path fill-rule="evenodd" clip-rule="evenodd" d="M248.896 16.647a.441.441 0 1 1 .442.442.441.441 0 0 1-.442-.442Zm0 1.473a.441.441 0 1 1 .442.442.441.441 0 0 1-.442-.442Zm0 1.474a.441.441 0 1 1 .442.442.441.441 0 0 1-.442-.442Z" fill="#fff"/></mask><g mask="url(#e)"><path fill="#9AA0A6" d="M246.833 15.615h4.715v4.715h-4.715z"/></g><path fill="#202124" fill-opacity=".28" d="M81.634 4.714h.295v5.894h-.295z"/><path d="M11.2 4.989a2.358 2.358 0 0 1 2.357-2.358h65.98a2.358 2.358 0 0 1 2.357 2.358v7.663H11.2V4.989Z" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M11.2 10.293v2.358H8.546v-.018a2.358 2.358 0 0 0 2.652-2.34Zm70.694 0v2.358h2.653v-.018a2.358 2.358 0 0 1-2.652-2.34Z" fill="#DADCE0"/><path fill-rule="evenodd" clip-rule="evenodd" d="M75.953 6.482a.21.21 0 0 1 .172.09l.796.796.793-.79a.21.21 0 1 1 .32.271l.001.003-.818.81.79.791a.21.21 0 1 1-.29.297l-.796-.794-.791.784a.21.21 0 1 1-.316-.27l.813-.809-.804-.803a.21.21 0 0 1 .13-.376Z" fill="#5F6368"/><g clip-path="url(#f)"><path d="M17.13 8.714V6.782h.027l1.352 1.932h.302V6.222h-.307v1.94h-.028l-1.352-1.94h-.302v2.492h.307Zm3.512-.482c-.078.164-.24.252-.48.252-.316 0-.522-.233-.537-.6v-.015h1.338v-.114c0-.578-.306-.935-.808-.935-.512 0-.84.38-.84.965 0 .589.323.962.84.962.407 0 .697-.197.784-.515h-.297Zm-.49-1.15c.294 0 .491.218.498.547h-1.025c.022-.33.23-.547.526-.547Zm3.619-.23h-.3l-.365 1.489h-.028l-.416-1.489h-.285l-.416 1.489h-.028l-.366-1.489h-.3l.521 1.862h.3l.415-1.44h.028l.416 1.44h.302l.522-1.862Zm1.52-.481v.481h-.301v.249h.3v1.13c0 .355.154.497.537.497a.995.995 0 0 0 .175-.018v-.25a1.253 1.253 0 0 1-.139.007c-.193 0-.276-.093-.276-.313V7.101h.415v-.249h-.415v-.481h-.297Zm1.678 2.376a.643.643 0 0 0 .573-.308h.028v.275h.283V7.439c0-.386-.254-.62-.708-.62-.397 0-.69.197-.73.496h.3c.041-.147.197-.231.42-.231.277 0 .42.126.42.355v.17l-.536.033c-.434.025-.679.217-.679.55 0 .34.268.555.629.555Zm.055-.261c-.216 0-.377-.11-.377-.3 0-.187.125-.285.408-.304l.5-.033v.17c0 .267-.226.467-.531.467Zm2.303.26c.472 0 .781-.381.781-.963 0-.585-.307-.963-.78-.963-.256 0-.482.126-.584.326h-.028V6.113h-.297v2.6h.283v-.296h.028c.117.207.338.33.598.33Zm-.069-1.659c.34 0 .543.261.543.696 0 .435-.202.696-.543.696-.338 0-.549-.266-.549-.696 0-.43.21-.696.55-.696Z" fill="#202124"/></g><path fill-rule="evenodd" clip-rule="evenodd" d="M88.358 5.59c.162 0 .294.131.294.294v1.179h1.18a.295.295 0 0 1 0 .59h-1.18V8.83a.295.295 0 1 1-.589 0V7.652h-1.179a.295.295 0 1 1 0-.589h1.179V5.884c0-.163.132-.295.295-.295Z" fill="#000"/><mask id="g" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="86" y="5" width="5" height="5"><path fill-rule="evenodd" clip-rule="evenodd" d="M88.358 5.59c.162 0 .294.131.294.294v1.179h1.18a.295.295 0 0 1 0 .59h-1.18V8.83a.295.295 0 1 1-.589 0V7.652h-1.179a.295.295 0 1 1 0-.589h1.179V5.884c0-.163.132-.295.295-.295Z" fill="#fff"/></mask><g mask="url(#g)"><path fill="#5F6368" d="M90.716 9.716H86V5h4.715z"/></g><path d="m249.487 8.529-1.319-1.316.279-.28 1.04 1.042 1.039-1.041.279.279-1.318 1.316Z" fill="#5F6368"/><defs><clipPath id="d"><rect x="236.519" y="14.733" width="6.484" height="6.484" rx="3.242" fill="#fff"/></clipPath><clipPath id="f"><path fill="#fff" transform="translate(16.504 4.714)" d="M0 0h51.869v5.894H0z"/></clipPath></defs></svg>
\ No newline at end of file
diff --git a/chrome/browser/resources/side_panel/customize_chrome/theme_snapshot.html b/chrome/browser/resources/side_panel/customize_chrome/theme_snapshot.html
index fa1a152..c767e6b2 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/theme_snapshot.html
+++ b/chrome/browser/resources/side_panel/customize_chrome/theme_snapshot.html
@@ -30,12 +30,6 @@
     justify-content: center;
   }
 
-  #miniNewTabPage {
-    height: auto;
-    margin: 17px;
-    width: 100%;
-  }
-
   #gm3MiniNewTabPage {
     height: auto;
     width: 100%;
@@ -113,17 +107,10 @@
     <div class="image-background image"
         id="classicChromeBackground"
         on-click="onThemeSnapshotClick_">
-      <template is="dom-if" if="[[!chromeRefresh2023Enabled_]]">
-        <img id="miniNewTabPage" src="icons/mini_new_tab_page.svg"
-            aria-labelledby="classicChromeThemeTitle">
-        </img>
-      </template>
-      <template is="dom-if" if="[[chromeRefresh2023Enabled_]]">
-        <svg id="gm3MiniNewTabPage" aria-labelledby="classicChromeThemeTitle"
-            viewBox="0 0 240 126" preserveAspectRatio="xMidYMid meet">
-          <use href="icons/gm3_mini_new_tab_page.svg#miniNewTabPage"></use>
-        </svg>
-      </template>
+      <svg id="gm3MiniNewTabPage" aria-labelledby="classicChromeThemeTitle"
+          viewBox="0 0 240 126" preserveAspectRatio="xMidYMid meet">
+        <use href="icons/gm3_mini_new_tab_page.svg#miniNewTabPage"></use>
+      </svg>
       <div class="overlay"></div>
       <cr-ripple></cr-ripple>
     </div>
diff --git a/chrome/browser/resources/side_panel/customize_chrome/theme_snapshot.ts b/chrome/browser/resources/side_panel/customize_chrome/theme_snapshot.ts
index 6bace85..fa75446b 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/theme_snapshot.ts
+++ b/chrome/browser/resources/side_panel/customize_chrome/theme_snapshot.ts
@@ -32,10 +32,6 @@
 
   static get properties() {
     return {
-      chromeRefresh2023Enabled_: {
-        type: Boolean,
-      },
-
       theme_: Object,
 
       themeType_: {
@@ -45,7 +41,6 @@
     };
   }
 
-  private chromeRefresh2023Enabled_: boolean;
   private theme_: Theme|undefined = undefined;
   private themeType_: CustomizeThemeType|null = null;
 
@@ -61,8 +56,6 @@
 
   override connectedCallback() {
     super.connectedCallback();
-    this.chromeRefresh2023Enabled_ =
-        document.documentElement.hasAttribute('chrome-refresh-2023');
     this.setThemeListenerId_ =
         this.callbackRouter_.setTheme.addListener((theme: Theme) => {
           this.theme_ = theme;
@@ -97,8 +90,7 @@
   }
 
   private onThemeSnapshotClick_() {
-    if (!this.chromeRefresh2023Enabled_ ||
-        (this.theme_ && this.theme_.backgroundManagedByPolicy)) {
+    if (this.theme_ && this.theme_.backgroundManagedByPolicy) {
       return;
     }
     this.dispatchEvent(new Event('edit-theme-click'));
diff --git a/chrome/browser/resources/side_panel/read_anything/app.ts b/chrome/browser/resources/side_panel/read_anything/app.ts
index 655b028..84e2139 100644
--- a/chrome/browser/resources/side_panel/read_anything/app.ts
+++ b/chrome/browser/resources/side_panel/read_anything/app.ts
@@ -956,8 +956,6 @@
       // Aloud play / pause or via a preference change, rehighlight the nodes
       // after a pause.
       if (!container.querySelector('.' + currentReadHighlightClass)) {
-        // TODO(crbug.com/1474951): Investigate adding a mock voice in tests
-        // to make this testable.
         this.highlightNodes(chrome.readingMode.getCurrentText());
       }
 
diff --git a/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.html b/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.html
index 7e077936..f45799ee 100644
--- a/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.html
+++ b/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.html
@@ -1,5 +1,5 @@
 <style include="cr-icons md-select">
-  iron-icon {
+  cr-icon {
     --icon-size: 20px;
     height: var(--icon-size);
     width: var(--icon-size);
@@ -278,9 +278,9 @@
         <template is="dom-repeat" items="[[rateOptions_]]" index-as="index"
                   initial-count="8">
           <button class="dropdown-item" on-click="onRateClick_">
-            <iron-icon class$="button-image check-mark
+            <cr-icon class$="button-image check-mark
               check-mark-hidden-[[isRateItemSelected_(index)]]"
-                icon="read-anything-20:check-mark"></iron-icon>
+                icon="read-anything-20:check-mark"></cr-icon>
             [[item]]x
           </button>
         </template>
@@ -321,10 +321,10 @@
         <template is="dom-repeat" items="[[colorOptions_]]" index-as="index"
                   initial-count="5">
           <button class="dropdown-item" on-click="onColorClick_">
-            <iron-icon class$="button-image check-mark
+            <cr-icon class$="button-image check-mark
                               check-mark-hidden-[[isColorItemSelected_(index)]]"
-                icon="read-anything-20:check-mark"></iron-icon>
-            <iron-icon class="button-image" icon="[[item.icon]]"></iron-icon>
+                icon="read-anything-20:check-mark"></cr-icon>
+            <cr-icon class="button-image" icon="[[item.icon]]"></cr-icon>
             [[item.title]]
           </button>
         </template>
@@ -338,10 +338,10 @@
                   items="[[lineSpacingOptions_]]" index-as="index"
                   initial-count="3">
           <button class="dropdown-item" on-click="onLineSpacingClick_">
-            <iron-icon class$="button-image check-mark
+            <cr-icon class$="button-image check-mark
                         check-mark-hidden-[[isLineSpacingItemSelected_(index)]]"
-                icon="read-anything-20:check-mark"></iron-icon>
-            <iron-icon class="button-image" icon="[[item.icon]]"></iron-icon>
+                icon="read-anything-20:check-mark"></cr-icon>
+            <cr-icon class="button-image" icon="[[item.icon]]"></cr-icon>
             [[item.title]]
           </button>
         </template>
@@ -355,10 +355,10 @@
                   items="[[letterSpacingOptions_]]" index-as="index"
                   initial-count="3">
           <button class="dropdown-item" on-click="onLetterSpacingClick_">
-            <iron-icon class$="button-image check-mark
+            <cr-icon class$="button-image check-mark
                       check-mark-hidden-[[isLetterSpacingItemSelected_(index)]]"
-                icon="read-anything-20:check-mark"></iron-icon>
-            <iron-icon class="button-image" icon="[[item.icon]]"></iron-icon>
+                icon="read-anything-20:check-mark"></cr-icon>
+            <cr-icon class="button-image" icon="[[item.icon]]"></cr-icon>
             [[item.title]]
           </button>
         </template>
@@ -372,10 +372,10 @@
                   initial-count="8">
           <button class="dropdown-item" on-click="onFontClick_"
               style$="font-family:[[item]]">
-            <iron-icon
+            <cr-icon
               class$="button-image check-mark
               check-mark-hidden-[[isFontItemSelected_(index)]]"
-              icon="read-anything-20:check-mark"></iron-icon>
+              icon="read-anything-20:check-mark"></cr-icon>
             [[getFontItemLabel_(item, areFontsLoaded_)]]
           </button>
         </template>
diff --git a/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.ts b/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.ts
index bc7af1d14..8f840215 100644
--- a/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.ts
+++ b/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.ts
@@ -14,13 +14,13 @@
 
 import type {CrActionMenuElement, ShowAtPositionConfig} from '//resources/cr_elements/cr_action_menu/cr_action_menu.js';
 import {AnchorAlignment} from '//resources/cr_elements/cr_action_menu/cr_action_menu.js';
+import type {CrIconElement} from '//resources/cr_elements/cr_icon/cr_icon.js';
 import type {CrIconButtonElement} from '//resources/cr_elements/cr_icon_button/cr_icon_button.js';
 import type {CrLazyRenderElement} from '//resources/cr_elements/cr_lazy_render/cr_lazy_render.js';
 import {I18nMixin} from '//resources/cr_elements/i18n_mixin.js';
 import {WebUiListenerMixin} from '//resources/cr_elements/web_ui_listener_mixin.js';
 import {assert} from '//resources/js/assert.js';
 import {loadTimeData} from '//resources/js/load_time_data.js';
-import type {IronIconElement} from '//resources/polymer/v3_0/iron-icon/iron-icon.js';
 import type {DomRepeatEvent} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
@@ -733,7 +733,7 @@
     const checked =
         Array.from(menu.getElementsByClassName('check-mark-hidden-false'));
     checked.forEach(element => {
-      const iconElement = element as IronIconElement;
+      const iconElement = element as CrIconElement;
       // TODO(crbug.com/1465029): Ensure this works with screen readers
       if (iconElement) {
         iconElement.classList.toggle('check-mark-hidden-true', true);
@@ -742,7 +742,7 @@
     });
 
     const checkMarks = Array.from(menu.getElementsByClassName('check-mark'));
-    const checkMark = checkMarks[index] as IronIconElement;
+    const checkMark = checkMarks[index] as CrIconElement;
     if (checkMark) {
       checkMark.classList.toggle('check-mark-hidden-true', false);
       checkMark.classList.toggle('check-mark-hidden-false', true);
diff --git a/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.html b/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.html
index d44cd48f..f4941c9 100644
--- a/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.html
+++ b/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.html
@@ -1,5 +1,5 @@
 <style include="cr-icons">
-  iron-icon {
+  cr-icon {
     --icon-size: 20px;
     height: var(--icon-size);
     width: var(--icon-size);
@@ -86,9 +86,9 @@
               class="dropdown-item dropdown-voice-selection-button"
               on-click="onVoiceSelectClick_">
               <span class="voice-name">
-                <iron-icon id="check-mark"
+                <cr-icon id="check-mark"
                   class$="item-invisible-[[!item.selected]] check-mark"
-                  icon="read-anything-20:check-mark"></iron-icon>
+                  icon="read-anything-20:check-mark"></cr-icon>
                 [[item.title]]
               </span>
               <!-- TODO(b/333958820): Ensure keyboard focus is handled correctly
diff --git a/chrome/browser/resources/tab_search/app.html b/chrome/browser/resources/tab_search/app.html
index bdb213a..b6872ef 100644
--- a/chrome/browser/resources/tab_search/app.html
+++ b/chrome/browser/resources/tab_search/app.html
@@ -1,5 +1,5 @@
 <style include="mwb-shared-style">
-  :host-context([chrome-refresh-2023]) {
+  :host {
     --cr-primary-text-color: var(--color-tab-search-primary-foreground);
     --cr-secondary-text-color: var(--color-tab-search-secondary-foreground);
     --cr-separator-color: var(--color-tab-search-divider);
@@ -23,9 +23,7 @@
     --mwb-scrollbar-thumb-color: var(--color-tab-search-scrollbar-thumb);
     --mwb-scrollbar-thumb-hover-color: var(--color-tab-search-scrollbar-thumb);
     --mwb-scrollbar-track-color: transparent;
-  }
 
-  :host {
     user-select: none;
   }
 </style>
diff --git a/chrome/browser/resources/tab_search/tab_organization_not_started_image.html b/chrome/browser/resources/tab_search/tab_organization_not_started_image.html
index 8ccab9d..df7caab0 100644
--- a/chrome/browser/resources/tab_search/tab_organization_not_started_image.html
+++ b/chrome/browser/resources/tab_search/tab_organization_not_started_image.html
@@ -1,29 +1,5 @@
 <style>
   :host {
-    --image-background-color-1: rgb(211, 227, 253);
-    --image-background_color-2: rgb(231, 248, 237);
-    --window_frame_color: #A8C7FA;
-    --tab-group-1-color: #0B57D0;
-    --tab-group-2-color: #1EA446;
-    --tab-content-color-top: #fff;
-    --tab-content-color-bottom: #ECF3FE;
-    --active-tab-text-color: #D3E3FD;
-    --inactive-tab-text-color: #1B6EF3;
-  }
-
-  @media (prefers-color-scheme: dark) {
-    :host {
-        --image-background-color-1: rgb(8, 66, 160);
-        --image-background_color-2: rgb(15, 82, 35);
-        --window_frame_color: #0B57D0;
-        --tab-group-1-color: #A8C7FA;
-        --tab-content-color-top: #041E49;
-        --tab-content-color-bottom: #062E6F;
-        --active-tab-text-color: var(--inactive-tab-text-color);
-    }
-  }
-
-  :host-context([chrome-refresh-2023]):host {
     --image-background-color-1: var(--color-loading-gradient-middle);
     --image-background_color-2: var(--color-loading-gradient-end);
     --window_frame_color: var(--color-tab-search-image-window-frame);
@@ -88,7 +64,7 @@
     fill: var(--inactive-tab-text-color);
   }
 </style>
-  
+
 <svg xmlns="http://www.w3.org/2000/svg" width="280" height="103" fill="none">
   <g clip-path="url(#a)">
     <rect width="280" height="103" fill="url(#b)" rx="8"></rect>
diff --git a/chrome/browser/resources/tab_search/tab_search.html b/chrome/browser/resources/tab_search/tab_search.html
index e4545bf..5fcaa4d 100644
--- a/chrome/browser/resources/tab_search/tab_search.html
+++ b/chrome/browser/resources/tab_search/tab_search.html
@@ -1,6 +1,5 @@
 <!doctype html>
-<html dir="$i18n{textdirection}" lang="$i18n{language}"
-    $i18n{chromeRefresh2023Attribute}>
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
 <head>
   <meta charset="utf-8">
   <title>Tab Search</title>
@@ -20,19 +19,13 @@
       /* Using a var here for the background color is not currently an issue for
          Tab Search UI as it is shown asynchronously after the onload handler of
          the main frame has completed. */
-      background-color: var(--mwb-background-color);
-      margin: 0;
-    }
-
-    html[chrome-refresh-2023] body {
       background-color: var(--color-tab-search-background);
+      margin: 0;
     }
   </style>
 </head>
 <body>
   <tab-search-app></tab-search-app>
   <script type="module" src="tab_search.js"></script>
-  <script type="module" src="chrome://resources/cr_elements/mwb_shared_vars.css.js">
-  </script>
 </body>
 </html>
diff --git a/chrome/browser/resources/tab_search/tab_search_group_item.html b/chrome/browser/resources/tab_search/tab_search_group_item.html
index 9968061..733c93f8 100644
--- a/chrome/browser/resources/tab_search/tab_search_group_item.html
+++ b/chrome/browser/resources/tab_search/tab_search_group_item.html
@@ -66,10 +66,6 @@
   }
 
   #iconContainer {
-    margin-inline-end: 16px;
-  }
-
-  :host-context([chrome-refresh-2023]) #iconContainer {
     align-items: center;
     background: var(--color-list-item-url-favicon-background);
     border-radius: 8px;
@@ -78,6 +74,7 @@
     height: 40px;
     justify-content: center;
     overflow: hidden;
+    margin-inline-end: 16px;
     width: 40px;
   }
 </style>
diff --git a/chrome/browser/resources/tab_search/tab_search_item.html b/chrome/browser/resources/tab_search/tab_search_item.html
index a7cd561..920d7ac3 100644
--- a/chrome/browser/resources/tab_search/tab_search_item.html
+++ b/chrome/browser/resources/tab_search/tab_search_item.html
@@ -1,17 +1,5 @@
 <style include="mwb-element-shared-style">
   :host {
-     --audio-icon-color: var(--google-grey-700);
-     --media-recording-icon-color:  var(--google-red-600);
-   }
-
-  @media (prefers-color-scheme: dark) {
-    :host {
-      --audio-icon-color: var(--google-grey-300);
-      --media-recording-icon-color:  var(--google-red-300);
-    }
-  }
-
-  :host-context([chrome-refresh-2023]):host {
      --audio-icon-color: var(--color-tab-search-media-icon);
      --media-recording-icon-color:  var(--color-tab-search-media-recording-icon);
    }
@@ -154,10 +142,6 @@
   }
 
   #iconContainer {
-    margin-inline-end: 16px;
-  }
-
-  :host-context([chrome-refresh-2023]) #iconContainer {
     align-items: center;
     background: var(--tab-search-favicon-background,
         var(--color-list-item-url-favicon-background));
@@ -167,10 +151,11 @@
     height: 40px;
     justify-content: center;
     overflow: hidden;
+    margin-inline-end: 16px;
     width: 40px;
   }
 
-  :host-context([chrome-refresh-2023]):host([compact]) #iconContainer {
+  :host([compact]) #iconContainer {
     height: 24px;
     width: 24px;
   }
diff --git a/chrome/browser/resources/tab_search/tab_search_page.html b/chrome/browser/resources/tab_search/tab_search_page.html
index 020c20d..52b7171 100644
--- a/chrome/browser/resources/tab_search/tab_search_page.html
+++ b/chrome/browser/resources/tab_search/tab_search_page.html
@@ -108,24 +108,17 @@
     background-color: var(--mwb-background-color);
     color: var(--cr-secondary-text-color);
     display: flex;
-    font-size: var(--mwb-list-section-title-font-size);
-    font-weight: bolder;
+    font-size: var(--mwb-primary-text-font-size);
+    font-weight: var(--mwb-primary-text-font-weight);
     height: var(--mwb-list-section-title-height);
     padding-inline-end: 28px;
     padding-inline-start: var(--mwb-list-item-horizontal-margin);
     position: sticky;
-    text-transform: uppercase;
     top: 0;
     user-select: none;
     z-index: 1000;
   }
 
-  :host-context([chrome-refresh-2023]) .list-section-title {
-    font-size: var(--mwb-primary-text-font-size);
-    font-weight: var(--mwb-primary-text-font-weight);
-    text-transform: none;
-  }
-
   cr-expand-button {
     --cr-expand-button-size: 24px;
     --cr-expand-button-icon-size: 16px;
diff --git a/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoCoordinator.java b/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoCoordinator.java
index cba8b956..21aebfaf 100644
--- a/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoCoordinator.java
+++ b/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoCoordinator.java
@@ -36,9 +36,6 @@
      * @param logoView The view that shows the search provider logo.
      * @param shouldFetchDoodle Whether to fetch doodle if there is.
      * @param onLogoAvailableCallback The callback for when logo is available.
-     * @param isParentSurfaceShown Whether Start surface homepage or NTP is shown. This value
-     *                             is true when this class is used by NTP; while used by Start,
-     *                             it's only true on Start homepage.
      * @param visibilityObserver Observer object monitoring logo visibility.
      */
     public LogoCoordinator(
@@ -47,7 +44,6 @@
             LogoView logoView,
             boolean shouldFetchDoodle,
             Callback<Logo> onLogoAvailableCallback,
-            boolean isParentSurfaceShown,
             VisibilityObserver visibilityObserver) {
         // TODO(crbug.com/1394983): This is weird that we're passing in our view,
         //  and we have to expose our view via getView. We shouldn't only have to do one of these.
@@ -61,7 +57,6 @@
                         mLogoModel,
                         shouldFetchDoodle,
                         onLogoAvailableCallback,
-                        isParentSurfaceShown,
                         visibilityObserver,
                         sDefaultGoogleLogo);
     }
@@ -79,14 +74,16 @@
         mMediator.loadSearchProviderLogoWithAnimation();
     }
 
-    /** @see LogoMediator#updateVisibilityAndMaybeCleanUp */
-    public void updateVisibilityAndMaybeCleanUp(
-            boolean isParentSurfaceShown, boolean shouldDestroyBridge, boolean animationEnabled) {
-        mMediator.updateVisibilityAndMaybeCleanUp(
-                isParentSurfaceShown, shouldDestroyBridge, animationEnabled);
+    /**
+     * @see LogoMediator#updateVisibility
+     */
+    public void updateVisibility(boolean animationEnabled) {
+        mMediator.updateVisibility(animationEnabled);
     }
 
-    /** @see LogoMediator#destroy */
+    /**
+     * @see LogoMediator#destroy
+     */
     public void destroy() {
         mMediator.destroy();
         mLogoView.destroy();
diff --git a/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoMediator.java b/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoMediator.java
index a356637b..a9525ee 100644
--- a/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoMediator.java
+++ b/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoMediator.java
@@ -19,6 +19,7 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.logo.LogoBridge.Logo;
 import org.chromium.chrome.browser.logo.LogoBridge.LogoObserver;
+import org.chromium.chrome.browser.logo.LogoCoordinator.VisibilityObserver;
 import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.profiles.ProfileManager;
@@ -78,8 +79,6 @@
     private final Callback<LogoBridge.Logo> mOnLogoAvailableRunnable;
     private boolean mHasLogoLoadedForCurrentSearchEngine;
     private final boolean mShouldFetchDoodle;
-    private boolean mIsParentSurfaceShown; // This value should always be true when this class
-    // is used by NTP.
     private final LogoCoordinator.VisibilityObserver mVisibilityObserver;
     private final CachedTintedBitmap mDefaultGoogleLogo;
     private boolean mShouldShowLogo;
@@ -99,28 +98,23 @@
      * @param logoModel The model that is required to build the logo on start surface or ntp.
      * @param shouldFetchDoodle Whether to fetch doodle if there is.
      * @param onLogoAvailableCallback The callback for when logo is available.
-     * @param isParentSurfaceShown Whether Start surface homepage or NTP is shown. This value
-     *                             is true when this class is used by NTP; while used by Start,
-     *                             it's only true on Start homepage.
      * @param visibilityObserver Observer object monitoring logo visibility.
      * @param defaultGoogleLogo The google logo shared across all NTPs when Google is the default
-     *                          search engine.
+     *     search engine.
      */
     LogoMediator(
             Context context,
             Callback<LoadUrlParams> logoClickedCallback,
             PropertyModel logoModel,
             boolean shouldFetchDoodle,
-            Callback<LogoBridge.Logo> onLogoAvailableCallback,
-            boolean isParentSurfaceShown,
-            LogoCoordinator.VisibilityObserver visibilityObserver,
+            Callback<Logo> onLogoAvailableCallback,
+            VisibilityObserver visibilityObserver,
             CachedTintedBitmap defaultGoogleLogo) {
         mContext = context;
         mLogoModel = logoModel;
         mLogoClickedCallback = logoClickedCallback;
         mShouldFetchDoodle = shouldFetchDoodle;
         mOnLogoAvailableRunnable = onLogoAvailableCallback;
-        mIsParentSurfaceShown = isParentSurfaceShown;
         mVisibilityObserver = visibilityObserver;
         mVisibilityObservers.addObserver(mVisibilityObserver);
         mDefaultGoogleLogo = defaultGoogleLogo;
@@ -151,31 +145,17 @@
         loadSearchProviderLogoWithAnimation();
     }
 
-    /** Force to load the search provider logo with animation enabled.*/
+    /** Force to load the search provider logo with animation enabled. */
     void loadSearchProviderLogoWithAnimation() {
-        updateVisibilityAndMaybeCleanUp(
-                mIsParentSurfaceShown, /* shouldDestroyBridge= */ false, true);
+        updateVisibility(/* animationEnabled= */ true);
     }
 
     /**
-     * If it's on Start surface homepage or on NTP, load search provider logo; If it's not on Start
-     * surface homepage, destroy the part of LogoBridge which includes mImageFetcher.
+     * Loads the search provider logo.
      *
-     * @param isParentSurfaceShown Whether Start surface homepage or NTP is shown. This value
-     *                             should always be true when this class is used by NTP.
-     * @param shouldDestroyBridge Whether to destroy the part of LogoBridge for saving memory. This
-     *                              value should always be false when this class is used by NTP.
-     *                              TODO(crbug.com/1315676): Remove this variable once the refactor
-     *                              is launched and StartSurfaceState is removed. Now we check this
-     *                              because there are some intermediate StartSurfaceStates,
-     *                              i.e. SHOWING_START.
      * @param animationEnabled Whether to enable the fade in animation.
      */
-    void updateVisibilityAndMaybeCleanUp(
-            boolean isParentSurfaceShown, boolean shouldDestroyBridge, boolean animationEnabled) {
-        assert !isParentSurfaceShown || !shouldDestroyBridge;
-
-        mIsParentSurfaceShown = isParentSurfaceShown;
+    void updateVisibility(boolean animationEnabled) {
         updateVisibility();
 
         if (mShouldShowLogo) {
@@ -184,10 +164,6 @@
             } else {
                 mIsLoadPending = true;
             }
-        } else if (shouldDestroyBridge && mLogoBridge != null) {
-            mHasLogoLoadedForCurrentSearchEngine = false;
-            // Destroy the part of logoBridge when hiding Start surface homepage to save memory.
-            cleanUp();
         }
     }
 
@@ -284,7 +260,7 @@
                                 .doesDefaultSearchEngineHaveLogo()
                         : ChromeSharedPreferences.getInstance()
                                 .readBoolean(APP_LAUNCH_SEARCH_ENGINE_HAD_LOGO, true);
-        mShouldShowLogo = mIsParentSurfaceShown && doesDseHaveLogo;
+        mShouldShowLogo = doesDseHaveLogo;
         mLogoModel.set(LogoProperties.VISIBILITY, mShouldShowLogo);
         for (LogoCoordinator.VisibilityObserver observer : mVisibilityObservers) {
             observer.onLogoVisibilityChanged();
diff --git a/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoMediatorUnitTest.java b/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoMediatorUnitTest.java
index c17347b..c079bb0b 100644
--- a/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoMediatorUnitTest.java
+++ b/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoMediatorUnitTest.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.logo;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -146,10 +147,7 @@
         logoMediator.setHasLogoLoadedForCurrentSearchEngineForTesting(false);
         when(mTemplateUrlService.isDefaultSearchEngineGoogle()).thenReturn(false);
 
-        logoMediator.updateVisibilityAndMaybeCleanUp(
-                /* isParentSurfaceShown= */ true,
-                /* shouldDestroyBridge= */ false,
-                /* animationEnabled= */ false);
+        logoMediator.updateVisibility(/* animationEnabled= */ false);
 
         verify(mLogoBridge, times(1)).getCurrentLogo(any());
     }
@@ -160,41 +158,15 @@
         logoMediator.setHasLogoLoadedForCurrentSearchEngineForTesting(true);
         when(mTemplateUrlService.isDefaultSearchEngineGoogle()).thenReturn(false);
 
-        logoMediator.updateVisibilityAndMaybeCleanUp(
-                /* isParentSurfaceShown= */ true,
-                /* shouldDestroyBridge= */ false,
-                /* animationEnabled= */ false);
+        logoMediator.updateVisibility(/* animationEnabled= */ false);
 
         verify(mLogoBridge, times(0)).getCurrentLogo(any());
     }
 
     @Test
-    public void testInitWithNativeWhenParentSurfaceIsNotVisible() {
-        LogoMediator logoMediator =
-                createMediatorWithoutNative(/* isParentSurfaceShown= */ false, true);
-        logoMediator.updateVisibilityAndMaybeCleanUp(
-                /* isParentSurfaceShown= */ false,
-                /* shouldDestroyBridge= */ false,
-                /* animationEnabled= */ false);
-        Assert.assertFalse(mLogoModel.get(LogoProperties.VISIBILITY));
-        // When parent surface isn't showing, calling updateVisibilityAndMaybeCleanUp() shouldn't
-        // trigger getSearchProviderLogo() nor add any pending load task.
-        Assert.assertFalse(logoMediator.getIsLoadPendingForTesting());
-        logoMediator.initWithNative();
-
-        Assert.assertFalse(mLogoModel.get(LogoProperties.VISIBILITY));
-        Assert.assertFalse(logoMediator.isLogoVisible());
-        verify(mLogoBridge, times(0)).getCurrentLogo(any());
-        verify(mTemplateUrlService).addObserver(logoMediator);
-    }
-
-    @Test
     public void testInitWithNativeWhenParentSurfaceIsVisible() {
-        LogoMediator logoMediator = createMediatorWithoutNative(true, true);
-        logoMediator.updateVisibilityAndMaybeCleanUp(
-                /* isParentSurfaceShown= */ true,
-                /* shouldDestroyBridge= */ false,
-                /* animationEnabled= */ false);
+        LogoMediator logoMediator = createMediatorWithoutNative(true);
+        logoMediator.updateVisibility(/* animationEnabled= */ false);
 
         Assert.assertTrue(logoMediator.isLogoVisible());
         // When parent surface is shown while native library isn't loaded, calling
@@ -209,7 +181,7 @@
 
     @Test
     public void testInitWithoutNativeWhenDseDoesNotHaveLogo() {
-        LogoMediator logoMediator = createMediatorWithoutNative(true, true);
+        LogoMediator logoMediator = createMediatorWithoutNative(true);
         boolean originKeyValue =
                 ChromeSharedPreferences.getInstance()
                         .readBoolean(
@@ -217,10 +189,7 @@
                                 mTemplateUrlService.doesDefaultSearchEngineHaveLogo());
         ChromeSharedPreferences.getInstance()
                 .writeBoolean(APP_LAUNCH_SEARCH_ENGINE_HAD_LOGO, false);
-        logoMediator.updateVisibilityAndMaybeCleanUp(
-                /* isParentSurfaceShown= */ true,
-                /* shouldDestroyBridge= */ false,
-                /* animationEnabled= */ false);
+        logoMediator.updateVisibility(/* animationEnabled= */ false);
         Assert.assertFalse(mLogoModel.get(LogoProperties.VISIBILITY));
         Assert.assertFalse(logoMediator.getIsLoadPendingForTesting());
         verify(mLogoBridge, times(0)).destroy();
@@ -229,67 +198,24 @@
     }
 
     @Test
-    public void testUpdateVisibilityAndMaybeCleanUp() {
+    public void testUpdateVisibility() {
         LogoMediator logoMediator = createMediator();
 
-        // If parent surface is not shown nor bridge shouldn't be destroyed, logo shouldn't be
-        // loaded and bridge isn't destroyed.
-        logoMediator.updateVisibilityAndMaybeCleanUp(
-                /* isParentSurfaceShown= */ false,
-                /* shouldDestroyBridge= */ false,
-                /* animationEnabled= */ false);
-        Assert.assertFalse(logoMediator.isLogoVisible());
-        verify(mLogoBridge, times(0)).getCurrentLogo(any());
-        verify(mLogoBridge, times(0)).destroy();
-
-        // If parent surface is not shown and bridge should be destroyed, logo should be
-        // loaded and bridge is destroyed.
-        logoMediator.setImageFetcherForTesting(mImageFetcher);
-        logoMediator.updateVisibilityAndMaybeCleanUp(
-                /* isParentSurfaceShown= */ false,
-                /* shouldDestroyBridge= */ true,
-                /* animationEnabled= */ false);
-        Assert.assertFalse(logoMediator.isLogoVisible());
-        verify(mLogoBridge, times(0)).getCurrentLogo(any());
-        verify(mLogoBridge, times(1)).destroy();
-        verify(mImageFetcher, times(1)).destroy();
-        Assert.assertNull(logoMediator.getLogoBridgeForTesting());
-        Assert.assertNull(logoMediator.getImageFetcherForTesting());
-
         // If parent surface is shown, logo should be loaded and bridge shouldn't be
         // destroyed.
         logoMediator.setLogoBridgeForTesting(mLogoBridge);
-        logoMediator.updateVisibilityAndMaybeCleanUp(
-                /* isParentSurfaceShown= */ true,
-                /* shouldDestroyBridge= */ false,
-                /* animationEnabled= */ false);
+        logoMediator.updateVisibility(/* animationEnabled= */ false);
         Assert.assertTrue(logoMediator.isLogoVisible());
-        verify(mLogoBridge, times(1)).getCurrentLogo(any());
-        verify(mLogoBridge, times(1)).destroy();
+        verify(mLogoBridge).getCurrentLogo(any());
+        verify(mLogoBridge, never()).destroy();
         Assert.assertFalse(mLogoModel.get(LogoProperties.ANIMATION_ENABLED));
 
         // Attached the test for animationEnabled.
         logoMediator.setHasLogoLoadedForCurrentSearchEngineForTesting(false);
-        logoMediator.updateVisibilityAndMaybeCleanUp(
-                /* isParentSurfaceShown= */ true,
-                /* shouldDestroyBridge= */ false,
-                /* animationEnabled= */ true);
+        logoMediator.updateVisibility(/* animationEnabled= */ true);
         Assert.assertTrue(mLogoModel.get(LogoProperties.ANIMATION_ENABLED));
     }
 
-    @Test(expected = AssertionError.class)
-    public void testUpdateVisibilityAndMaybeCleanUpAssertionError() {
-        LogoMediator logoMediator = createMediator();
-        verify(mLogoBridge, times(0)).getCurrentLogo(any());
-
-        // If parent surface is shown and bridge should be destroyed, an assertion error
-        // should be thrown.
-        logoMediator.updateVisibilityAndMaybeCleanUp(
-                /* isParentSurfaceShown= */ true,
-                /* shouldDestroyBridge= */ true,
-                /* animationEnabled= */ false); // should throw an exception
-    }
-
     @Test
     public void testDestroyWhenInitWithNative() {
         LogoMediator logoMediator = createMediator();
@@ -299,21 +225,18 @@
     }
 
     private LogoMediator createMediator(boolean shouldFetchDoodle) {
-        LogoMediator logoMediator =
-                createMediatorWithoutNative(/* isParentSurfaceShown= */ true, shouldFetchDoodle);
+        LogoMediator logoMediator = createMediatorWithoutNative(shouldFetchDoodle);
         logoMediator.initWithNative();
         return logoMediator;
     }
 
     private LogoMediator createMediator() {
-        LogoMediator logoMediator =
-                createMediatorWithoutNative(/* isParentSurfaceShown= */ true, true);
+        LogoMediator logoMediator = createMediatorWithoutNative(true);
         logoMediator.initWithNative();
         return logoMediator;
     }
 
-    private LogoMediator createMediatorWithoutNative(
-            boolean isParentSurfaceShown, boolean shouldFetchDoodle) {
+    private LogoMediator createMediatorWithoutNative(boolean shouldFetchDoodle) {
         LogoMediator logoMediator =
                 new LogoMediator(
                         mContext,
@@ -321,7 +244,6 @@
                         mLogoModel,
                         shouldFetchDoodle,
                         mOnLogoAvailableCallback,
-                        isParentSurfaceShown,
                         null,
                         new CachedTintedBitmap(
                                 R.drawable.google_logo, R.color.google_logo_tint_color));
diff --git a/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoViewBinderUnitTest.java b/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoViewBinderUnitTest.java
index 952d0801..f9a3e42e3 100644
--- a/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoViewBinderUnitTest.java
+++ b/chrome/browser/ui/android/logo/java/src/org/chromium/chrome/browser/logo/LogoViewBinderUnitTest.java
@@ -104,7 +104,6 @@
                         mLogoModel,
                         /* shouldFetchDoodle= */ true,
                         /* onLogoAvailableCallback= */ null,
-                        /* isParentSurfaceShown= */ true,
                         /* visibilityObserver= */ null,
                         /* defaultGoogleLogo= */ null);
     }
diff --git a/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfPage.java b/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfPage.java
index 404b73e..7c91a6e 100644
--- a/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfPage.java
+++ b/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfPage.java
@@ -27,14 +27,23 @@
      * @param activity The current Activity.
      * @param url The pdf url, which could be a pdf link, content uri or file uri.
      * @param pdfInfo Information of the pdf.
+     * @param defaultTitle Default title of the pdf page.
      */
     public PdfPage(
-            NativePageHost host, Profile profile, Activity activity, String url, PdfInfo pdfInfo) {
+            NativePageHost host,
+            Profile profile,
+            Activity activity,
+            String url,
+            PdfInfo pdfInfo,
+            String defaultTitle) {
         super(host);
 
         String filepath =
                 pdfInfo.filepath == null ? PdfUtils.getFilePathFromUrl(url) : pdfInfo.filepath;
-        mTitle = pdfInfo.filename == null ? PdfUtils.getFileNameFromUrl(url) : pdfInfo.filename;
+        mTitle =
+                pdfInfo.filename == null
+                        ? PdfUtils.getFileNameFromUrl(url, defaultTitle)
+                        : pdfInfo.filename;
         mUrl = url;
         mPdfCoordinator = new PdfCoordinator(host, profile, activity, filepath, url);
         initWithView(mPdfCoordinator.getView());
diff --git a/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfPageUnitTest.java b/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfPageUnitTest.java
index 3b575d53..e7bcb8b 100644
--- a/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfPageUnitTest.java
+++ b/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfPageUnitTest.java
@@ -48,6 +48,7 @@
     private AutoCloseable mCloseableMocks;
     private PdfInfo mPdfInfo;
 
+    private static final String DEFAULT_TAB_TITLE = "Loading PDF…";
     private static final String CONTENT_URL = "content://media/external/downloads/1000000022";
     private static final String FILE_URL = "file:///media/external/downloads/sample.pdf";
     private static final String PDF_LINK = "https://www.foo.com/testfiles/pdf/sample.pdf";
@@ -81,7 +82,13 @@
     @Test
     public void testCreatePdfPage_WithContentUri() {
         PdfPage pdfPage =
-                new PdfPage(mMockNativePageHost, mMockProfile, mActivity, CONTENT_URL, mPdfInfo);
+                new PdfPage(
+                        mMockNativePageHost,
+                        mMockProfile,
+                        mActivity,
+                        CONTENT_URL,
+                        mPdfInfo,
+                        DEFAULT_TAB_TITLE);
         Assert.assertNotNull(pdfPage);
         Assert.assertEquals(
                 "Pdf page host should match.", UrlConstants.PDF_HOST, pdfPage.getHost());
@@ -103,7 +110,13 @@
     @Test
     public void testCreatePdfPage_WithFileUri() {
         PdfPage pdfPage =
-                new PdfPage(mMockNativePageHost, mMockProfile, mActivity, FILE_URL, mPdfInfo);
+                new PdfPage(
+                        mMockNativePageHost,
+                        mMockProfile,
+                        mActivity,
+                        FILE_URL,
+                        mPdfInfo,
+                        DEFAULT_TAB_TITLE);
         Assert.assertNotNull(pdfPage);
         Assert.assertEquals("Pdf page title should match.", FILE_NAME, pdfPage.getTitle());
         Assert.assertEquals(
@@ -126,7 +139,13 @@
     @Test
     public void testCreatePdfPage_WithPdfLink() {
         PdfPage pdfPage =
-                new PdfPage(mMockNativePageHost, mMockProfile, mActivity, PDF_LINK, mPdfInfo);
+                new PdfPage(
+                        mMockNativePageHost,
+                        mMockProfile,
+                        mActivity,
+                        PDF_LINK,
+                        mPdfInfo,
+                        DEFAULT_TAB_TITLE);
         Assert.assertNotNull(pdfPage);
         Assert.assertFalse(
                 "Pdf should not be loaded when the download is not completed.",
@@ -154,12 +173,11 @@
 
     @Test
     public void testGetFileNameFromUrl() {
-        String filename = PdfUtils.getFileNameFromUrl(FILE_URL);
+        String filename = PdfUtils.getFileNameFromUrl(FILE_URL, DEFAULT_TAB_TITLE);
         Assert.assertEquals("Filename does not match for file url.", FILE_NAME, filename);
 
-        filename = PdfUtils.getFileNameFromUrl(PDF_LINK);
-        Assert.assertEquals(
-                "Filename does not match for pdf link.", PdfUtils.PDF_PAGE_TITLE, filename);
+        filename = PdfUtils.getFileNameFromUrl(PDF_LINK, DEFAULT_TAB_TITLE);
+        Assert.assertEquals("Filename does not match for pdf link.", DEFAULT_TAB_TITLE, filename);
     }
 
     @Test
diff --git a/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfUtils.java b/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfUtils.java
index fae4bf1..4a8cf46 100644
--- a/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfUtils.java
+++ b/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfUtils.java
@@ -28,8 +28,6 @@
 
 /** Utilities for inline pdf support. */
 public class PdfUtils {
-    // TODO(shuyng): add this to android_chrome_strings.grd once the UX spec is finalized.
-    static final String PDF_PAGE_TITLE = "PDF";
     private static final String TAG = "PdfUtils";
     private static final String PDF_EXTENSION = "pdf";
     private static boolean sShouldOpenPdfInlineForTesting;
@@ -81,7 +79,7 @@
         return new PdfInfo(nativePage.getTitle(), nativePage.getCanonicalFilepath());
     }
 
-    static String getFileNameFromUrl(String url) {
+    static String getFileNameFromUrl(String url, String defaultTitle) {
         Uri uri = Uri.parse(url);
         String scheme = uri.getScheme();
         assert scheme != null;
@@ -89,7 +87,7 @@
                 || scheme.equals(UrlConstants.HTTPS_SCHEME)
                 || scheme.equals(UrlConstants.CONTENT_SCHEME)
                 || scheme.equals(UrlConstants.FILE_SCHEME);
-        String fileName = PDF_PAGE_TITLE;
+        String fileName = defaultTitle;
         if (scheme.equals(UrlConstants.CONTENT_SCHEME)) {
             String displayName = ContentUriUtils.maybeGetDisplayName(url);
             if (!TextUtils.isEmpty(displayName)) {
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 490983f..261cf809 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -6158,6 +6158,11 @@
       <message name="IDS_DIGITAL_IDENTITY_INTERSTITIAL_NEGATIVE_BUTTON_TEXT" translateable="false">
         Do Not Share
       </message>
+
+      <!-- Inline PDF viewer support -->
+      <message name="IDS_PDF_TRANSIENT_TAB_TITLE" desc="This string is shown as the temporary tab title when a PDF file is loading in a tab. The tab title will be updated to the actual PDF file name once available.">
+        Loading PDF…
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PDF_TRANSIENT_TAB_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PDF_TRANSIENT_TAB_TITLE.png.sha1
new file mode 100644
index 0000000..1224471a
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PDF_TRANSIENT_TAB_TITLE.png.sha1
@@ -0,0 +1 @@
+dec02ba94f4098d0fa4aafd0c9a8ec4989939817
\ No newline at end of file
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
index 4df528d..763d3b4 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
@@ -333,7 +333,6 @@
                         logoView,
                         mShouldFetchDoodle,
                         /* onLogoAvailableCallback= */ null,
-                        isOnHomepage(),
                         null);
 
         // The logo view may be ready after native is initialized, so we need to call
@@ -413,8 +412,7 @@
     private void updateLogoVisibility() {
         if (mLogoCoordinator == null) return;
 
-        mLogoCoordinator.updateVisibilityAndMaybeCleanUp(
-                isOnHomepage(), isOnATab() || isOnGridTabSwitcher(), /* animationEnabled= */ false);
+        mLogoCoordinator.updateVisibility(/* animationEnabled= */ false);
     }
 
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
index 5ee8104..f037faf5 100644
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
@@ -159,7 +159,7 @@
     }
   }
   void DispatchAccessibilityLocationChange(
-      const ui::AXLocationChangeNotificationDetails& details) override {}
+      const ui::AXLocationChanges& details) override {}
   void DispatchTreeDestroyedEvent(ui::AXTreeID tree_id) override {}
   void DispatchActionResult(
       const ui::AXActionData& data,
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
index 67778cb6..a2c859a 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -75,8 +75,7 @@
 #include "mojo/public/cpp/bindings/associated_remote.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "services/device/public/cpp/device_features.h"
-#include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
-#include "services/device/public/cpp/geolocation/location_system_permission_status.h"
+#include "services/device/public/cpp/geolocation/buildflags.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/blink/public/common/features.h"
@@ -98,6 +97,11 @@
 #include "chrome/browser/web_applications/web_app_tab_helper.h"
 #endif
 
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
+#include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
+#include "services/device/public/cpp/geolocation/location_system_permission_status.h"
+#endif
+
 using base::UserMetricsAction;
 using content::WebContents;
 using content_settings::PageSpecificContentSettings;
@@ -106,7 +110,6 @@
 using content_settings::SettingInfo;
 using content_settings::SettingSource;
 using content_settings::mojom::SessionModel;
-using device::LocationSystemPermissionStatus;
 
 namespace {
 using ContentSettingBubbleAction =
@@ -1301,7 +1304,7 @@
                                      web_contents,
                                      ContentSettingsType::GEOLOCATION) {
   SetCustomLink();
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
   // Get the stored geolocation content setting and the system permission state
   // to determine whether geolocation is blocked by a system permission.
   //
@@ -1318,20 +1321,20 @@
   if (content_setting == CONTENT_SETTING_ALLOW &&
       device::GeolocationSystemPermissionManager::GetInstance()
               ->GetSystemPermission() !=
-          LocationSystemPermissionStatus::kAllowed) {
+          device::LocationSystemPermissionStatus::kAllowed) {
     // If the permission is turned off in supported operating systems
     // preferences, overwrite the bubble to enable the user to trigger the
     // system dialog.
     InitializeSystemGeolocationPermissionBubble();
   }
-#endif  // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 }
 
 ContentSettingGeolocationBubbleModel::~ContentSettingGeolocationBubbleModel() =
     default;
 
 void ContentSettingGeolocationBubbleModel::OnDoneButtonClicked() {
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
   if (show_system_geolocation_bubble_) {
     base::RecordAction(UserMetricsAction(
         "ContentSettings.GeolocationDialog.OpenPreferencesClicked"));
@@ -1341,7 +1344,7 @@
     DCHECK(geolocation_system_permission_manager);
     geolocation_system_permission_manager->OpenSystemPermissionSetting();
   }
-#endif  // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 }
 
 void ContentSettingGeolocationBubbleModel::OnManageButtonClicked() {
@@ -1357,7 +1360,7 @@
 
 void ContentSettingGeolocationBubbleModel::
     InitializeSystemGeolocationPermissionBubble() {
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 #if BUILDFLAG(IS_MAC)
   if (base::FeatureList::IsEnabled(features::kLocationPermissionsExperiment)) {
     set_title(l10n_util::GetStringUTF16(
@@ -1367,7 +1370,7 @@
   }
 #else
   set_title(l10n_util::GetStringUTF16(IDS_GEOLOCATION_TURNED_OFF_IN_OS));
-#endif
+#endif  // BUILDFLAG(IS_MAC)
 
   clear_message();
   AddListItem(ContentSettingBubbleModel::ListItem(
@@ -1378,7 +1381,7 @@
   set_done_button_text(l10n_util::GetStringUTF16(IDS_OPEN_SETTINGS_LINK));
   set_radio_group(RadioGroup());
   show_system_geolocation_bubble_ = true;
-#endif  // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 }
 
 void ContentSettingGeolocationBubbleModel::SetCustomLink() {
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model_unittest.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model_unittest.cc
index 7cfd4bb4d..2bc7f20 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model_unittest.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
+
 #include <stddef.h>
 
 #include <memory>
@@ -22,7 +24,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/blocked_content/blocked_window_params.h"
 #include "chrome/browser/ui/blocked_content/chrome_popup_navigation_delegate.h"
-#include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
 #include "chrome/browser/ui/content_settings/fake_owner.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
@@ -50,15 +51,16 @@
 #include "content/public/test/web_contents_tester.h"
 #include "net/base/schemeful_site.h"
 #include "services/device/public/cpp/device_features.h"
+#include "services/device/public/cpp/geolocation/buildflags.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 #include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
 #include "services/device/public/cpp/geolocation/location_system_permission_status.h"
 #include "services/device/public/cpp/test/fake_geolocation_system_permission_manager.h"
-#endif
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 
 #if !BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.h"
@@ -528,7 +530,7 @@
 }
 
 TEST_F(ContentSettingBubbleModelTest, Geolocation) {
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
   auto fake_geolocation_system_permission_manager =
       std::make_unique<device::FakeGeolocationSystemPermissionManager>();
   device::FakeGeolocationSystemPermissionManager*
@@ -536,7 +538,7 @@
           fake_geolocation_system_permission_manager.get();
   device::GeolocationSystemPermissionManager::SetInstance(
       std::move(fake_geolocation_system_permission_manager));
-#endif  // BUILDFLAG(IS_MAC)
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 
   WebContentsTester::For(web_contents())
       ->NavigateAndCommit(GURL("https://www.example.com"));
@@ -551,7 +553,7 @@
                                          CONTENT_SETTING_ALLOW);
   content_settings->OnContentAllowed(ContentSettingsType::GEOLOCATION);
 
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
   // System-level geolocation permission is blocked.
   {
     auto content_setting_bubble_model =
@@ -594,14 +596,14 @@
 #else
     EXPECT_EQ(bubble_content.title,
               l10n_util::GetStringUTF16(IDS_GEOLOCATION_TURNED_OFF_IN_OS));
-#endif
+#endif  // BUILDFLAG(IS_MAC)
     EXPECT_TRUE(bubble_content.message.empty());
     EXPECT_EQ(bubble_content.radio_group.radio_items.size(), 0U);
 
     // This should be a no-op.
     content_setting_bubble_model->CommitChanges();
   }
-#endif  // BUILDFLAG(IS_MAC)
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 
   // Go from allow by default to block by default to allow by default.
   {
diff --git a/chrome/browser/ui/content_settings/content_setting_image_model.cc b/chrome/browser/ui/content_settings/content_setting_image_model.cc
index d57dc213..59ec763 100644
--- a/chrome/browser/ui/content_settings/content_setting_image_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_image_model.cc
@@ -47,6 +47,7 @@
 #include "content/public/browser/web_contents.h"
 #include "net/base/schemeful_site.h"
 #include "services/device/public/cpp/device_features.h"
+#include "services/device/public/cpp/geolocation/buildflags.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/pointer/touch_ui_controller.h"
 #include "ui/base/ui_base_features.h"
@@ -63,7 +64,7 @@
 #include "chrome/browser/web_applications/web_app_tab_helper.h"
 #endif
 
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 #include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
 #include "services/device/public/cpp/geolocation/location_system_permission_status.h"
 #endif
@@ -796,7 +797,7 @@
 }
 
 bool ContentSettingGeolocationImageModel::IsGeolocationAllowedOnASystemLevel() {
-#if !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_CHROMEOS)
+#if !BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
   return true;
 #else
   device::GeolocationSystemPermissionManager*
@@ -811,7 +812,7 @@
 }
 
 bool ContentSettingGeolocationImageModel::IsGeolocationPermissionDetermined() {
-#if !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_CHROMEOS)
+#if !BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
   return true;
 #else
 
diff --git a/chrome/browser/ui/content_settings/content_setting_image_model_unittest.cc b/chrome/browser/ui/content_settings/content_setting_image_model_unittest.cc
index 206616b..f3b923b 100644
--- a/chrome/browser/ui/content_settings/content_setting_image_model_unittest.cc
+++ b/chrome/browser/ui/content_settings/content_setting_image_model_unittest.cc
@@ -46,6 +46,7 @@
 #include "content/public/test/web_contents_tester.h"
 #include "net/cookies/cookie_options.h"
 #include "services/device/public/cpp/device_features.h"
+#include "services/device/public/cpp/geolocation/buildflags.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/ui_base_features.h"
@@ -56,10 +57,13 @@
 #include "chrome/browser/web_applications/app_shim_registry_mac.h"
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
 #include "chrome/browser/web_applications/web_app_tab_helper.h"
+#endif  // BUILDFLAG(IS_MAC)
+
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 #include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
 #include "services/device/public/cpp/geolocation/location_system_permission_status.h"
 #include "services/device/public/cpp/test/fake_geolocation_system_permission_manager.h"
-#endif
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 
 using content_settings::PageSpecificContentSettings;
 
@@ -310,7 +314,7 @@
       /* explanatory_string_id = */ 0);
 }
 
-#if BUILDFLAG(IS_MAC)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 // Test the correct ContentSettingImageModel for various permutations of site
 // and system level Geolocation permissions
 TEST_F(ContentSettingImageModelTest, GeolocationAccessPermissionsChanged) {
@@ -418,7 +422,9 @@
       content_setting_image_model.get(), /* is_visible = */ true,
       /* tooltip_empty = */ false, IDS_BLOCKED_GEOLOCATION_MESSAGE, 0);
 }
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 
+#if BUILDFLAG(IS_MAC)
 TEST_F(ContentSettingImageModelTest, GeolocationAccessDeniedExperiment) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures({features::kLocationPermissionsExperiment}, {});
@@ -486,7 +492,7 @@
         IDS_GEOLOCATION_TURNED_OFF);
   }
 }
-#endif
+#endif  // BUILDFLAG(IS_MAC)
 
 // Regression test for https://crbug.com/955408
 // See also: ContentSettingBubbleModelTest.SensorAccessPermissionsChanged
diff --git a/chrome/browser/ui/views/media_preview/active_devices_media_coordinator.cc b/chrome/browser/ui/views/media_preview/active_devices_media_coordinator.cc
index be2fb72f..d5ca220 100644
--- a/chrome/browser/ui/views/media_preview/active_devices_media_coordinator.cc
+++ b/chrome/browser/ui/views/media_preview/active_devices_media_coordinator.cc
@@ -101,13 +101,8 @@
 
 void ActiveDevicesMediaCoordinator::GotDeviceIdsOpenedForWebContents(
     std::vector<std::string> active_device_ids) {
-  if (view_type_ == MediaCoordinator::ViewType::kCameraOnly) {
-    media_preview_metrics::RecordPageInfoCameraNumInUseDevices(
-        active_device_ids.size());
-  } else {
-    media_preview_metrics::RecordPageInfoMicNumInUseDevices(
-        active_device_ids.size());
-  }
+  media_preview_metrics::RecordPageInfoNumInUseDevices(
+      media_preview_metrics_context_, active_device_ids.size());
 
   if (active_device_ids.empty()) {
     if (media_coordinators_.contains(kMutableCoordinatorId)) {
diff --git a/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.cc b/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.cc
index e2d4768e..5235e970 100644
--- a/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.cc
+++ b/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.cc
@@ -20,7 +20,7 @@
     const std::vector<std::string>& eligible_camera_ids,
     PrefService& prefs,
     bool allow_device_selection,
-    media_preview_metrics::Context metrics_context)
+    const media_preview_metrics::Context& metrics_context)
     : camera_mediator_(
           prefs,
           base::BindRepeating(&CameraCoordinator::OnVideoSourceInfosReceived,
@@ -29,7 +29,8 @@
       eligible_camera_ids_(eligible_camera_ids),
       prefs_(&prefs),
       allow_device_selection_(allow_device_selection),
-      metrics_context_(metrics_context) {
+      metrics_context_(metrics_context.ui_location,
+                       media_preview_metrics::PreviewType::kCamera) {
   auto* camera_view = parent_view.AddChildView(std::make_unique<MediaView>());
   camera_view_tracker_.SetView(camera_view);
   // Safe to use base::Unretained() because `this` owns / outlives
@@ -37,8 +38,6 @@
   camera_view_tracker_.SetIsDeletingCallback(base::BindOnce(
       &CameraCoordinator::ResetViewController, base::Unretained(this)));
 
-  metrics_context_.preview_type = media_preview_metrics::PreviewType::kCamera;
-
   // Safe to use base::Unretained() because `this` owns / outlives
   // `camera_view_controller_`.
   camera_view_controller_.emplace(
diff --git a/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.h b/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.h
index aafe737..98951c9 100644
--- a/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.h
+++ b/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.h
@@ -26,7 +26,7 @@
                     const std::vector<std::string>& eligible_camera_ids,
                     PrefService& prefs,
                     bool allow_device_selection,
-                    media_preview_metrics::Context metrics_context);
+                    const media_preview_metrics::Context& metrics_context);
   CameraCoordinator(const CameraCoordinator&) = delete;
   CameraCoordinator& operator=(const CameraCoordinator&) = delete;
   ~CameraCoordinator();
@@ -59,7 +59,7 @@
   std::vector<media::VideoCaptureDeviceInfo> eligible_device_infos_;
   raw_ptr<PrefService> prefs_;
   const bool allow_device_selection_;
-  media_preview_metrics::Context metrics_context_;
+  const media_preview_metrics::Context metrics_context_;
   std::optional<CameraViewController> camera_view_controller_;
   std::optional<VideoStreamCoordinator> video_stream_coordinator_;
 };
diff --git a/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator_unittest.cc b/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator_unittest.cc
index 2c84eff..c94f134 100644
--- a/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator_unittest.cc
+++ b/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator_unittest.cc
@@ -37,6 +37,13 @@
 constexpr char kDeviceId2[] = "device_id_2";
 constexpr char kDeviceName2[] = "device_name_2";
 
+media_preview_metrics::Context GetMetricsContext() {
+  // Camera coordinator is expected to narrow preview type to kCamera.
+  // This is verified in ExpectHistogramTotalDevices() below.
+  return {media_preview_metrics::UiLocation::kPermissionPrompt,
+          media_preview_metrics::PreviewType::kCameraAndMic};
+}
+
 MATCHER_P(HasItems, items, "") {
   if (arg.GetItemCount() != items.size()) {
     *result_listener << "item count is " << arg.GetItemCount();
@@ -87,12 +94,10 @@
         replied_with_source_infos_future.GetCallback());
 
     CHECK(profile()->GetPrefs());
-    coordinator_.emplace(
-        *parent_view_,
-        /*needs_borders=*/true, eligible_camera_ids, *profile()->GetPrefs(),
-        /*allow_device_selection=*/true,
-        media_preview_metrics::Context(
-            media_preview_metrics::UiLocation::kPermissionPrompt));
+    coordinator_.emplace(*parent_view_,
+                         /*needs_borders=*/true, eligible_camera_ids,
+                         *profile()->GetPrefs(),
+                         /*allow_device_selection=*/true, GetMetricsContext());
 
     ASSERT_TRUE(replied_with_source_infos_future.WaitAndClear());
   }
diff --git a/chrome/browser/ui/views/media_preview/camera_preview/video_stream_coordinator_unittest.cc b/chrome/browser/ui/views/media_preview/camera_preview/video_stream_coordinator_unittest.cc
index ec9ec70..8f427c3a 100644
--- a/chrome/browser/ui/views/media_preview/camera_preview/video_stream_coordinator_unittest.cc
+++ b/chrome/browser/ui/views/media_preview/camera_preview/video_stream_coordinator_unittest.cc
@@ -144,9 +144,9 @@
     TestWithBrowserView::SetUp();
     parent_view_ = std::make_unique<views::View>();
     coordinator_ = std::make_unique<VideoStreamCoordinator>(
-        *parent_view_,
-        media_preview_metrics::Context(
-            media_preview_metrics::UiLocation::kPermissionPrompt));
+        *parent_view_, media_preview_metrics::Context(
+                           media_preview_metrics::UiLocation::kPermissionPrompt,
+                           media_preview_metrics::PreviewType::kCamera));
   }
 
   void TearDown() override {
diff --git a/chrome/browser/ui/views/media_preview/media_coordinator.cc b/chrome/browser/ui/views/media_preview/media_coordinator.cc
index 391582fe..3051dd7 100644
--- a/chrome/browser/ui/views/media_preview/media_coordinator.cc
+++ b/chrome/browser/ui/views/media_preview/media_coordinator.cc
@@ -31,7 +31,7 @@
     EligibleDevices eligible_devices,
     PrefService& prefs,
     bool allow_device_selection,
-    media_preview_metrics::Context metrics_context) {
+    const media_preview_metrics::Context& metrics_context) {
   media_view_ =
       parent_view.AddChildView(std::make_unique<MediaView>(is_subsection));
   media_view_->SetBetweenChildSpacing(
diff --git a/chrome/browser/ui/views/media_preview/media_coordinator.h b/chrome/browser/ui/views/media_preview/media_coordinator.h
index 0180eef1..b398ad5 100644
--- a/chrome/browser/ui/views/media_preview/media_coordinator.h
+++ b/chrome/browser/ui/views/media_preview/media_coordinator.h
@@ -43,7 +43,7 @@
                    EligibleDevices eligible_devices,
                    PrefService& prefs,
                    bool allow_device_selection,
-                   media_preview_metrics::Context metrics_context);
+                   const media_preview_metrics::Context& metrics_context);
   MediaCoordinator(const MediaCoordinator&) = delete;
   MediaCoordinator& operator=(const MediaCoordinator&) = delete;
   ~MediaCoordinator();
diff --git a/chrome/browser/ui/views/media_preview/media_preview_metrics.cc b/chrome/browser/ui/views/media_preview/media_preview_metrics.cc
index 8757302..668187c 100644
--- a/chrome/browser/ui/views/media_preview/media_preview_metrics.cc
+++ b/chrome/browser/ui/views/media_preview/media_preview_metrics.cc
@@ -4,16 +4,20 @@
 
 #include "chrome/browser/ui/views/media_preview/media_preview_metrics.h"
 
-#include <optional>
 #include <string>
 
-#include "base/logging.h"
+#include "base/check_op.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/histogram_functions.h"
-#include "base/notreached.h"
+
+namespace media_preview_metrics {
 
 namespace {
 
+constexpr char kUiPrefix[] = "MediaPreviews.UI.";
+constexpr char kDeviceSelectionPrefix[] = "MediaPreviews.UI.DeviceSelection.";
+constexpr char kVideoPrefix[] = "MediaPreviews.UI.Preview.";
+
 base::HistogramBase* GetMediaPreviewDurationHistogram(std::string name) {
   // Duration buckets as powers of 2
   const std::vector<int> custom_ranges{1, 2, 4, 8, 16, 32, 64, 128, 256, 512};
@@ -21,43 +25,38 @@
       name, custom_ranges, base::HistogramBase::kUmaTargetedHistogramFlag);
 }
 
-std::optional<std::string> MapContextToString(
-    media_preview_metrics::Context context) {
-  std::string ui_location;
-  std::string preview_type;
-
+std::string GetUiLocationString(const Context& context) {
   switch (context.ui_location) {
-    case media_preview_metrics::UiLocation::kPermissionPrompt:
-      ui_location = "Permissions";
-      break;
-    case media_preview_metrics::UiLocation::kPageInfo:
-      ui_location = "PageInfo";
-      break;
-    default:
-#if DCHECK_IS_ON()
-      DLOG(FATAL) << "Context ui_location is unknown";
-#else
-      LOG(ERROR) << "Context ui_location is unknown";
-#endif
-      return std::nullopt;
+    case UiLocation::kPermissionPrompt:
+      return "Permissions";
+    case UiLocation::kPageInfo:
+      return "PageInfo";
   }
+}
 
+std::string GetPreviewTypeString(const Context& context) {
   switch (context.preview_type) {
-    case media_preview_metrics::PreviewType::kCamera:
-      preview_type = "Camera";
-      break;
-    case media_preview_metrics::PreviewType::kMic:
-      preview_type = "Mic";
-      break;
-    default:
-#if DCHECK_IS_ON()
-      DLOG(FATAL) << "Context preview_type is unknown";
-#else
-      LOG(ERROR) << "Context preview_type is unknown";
-#endif
-      return std::nullopt;
+    case PreviewType::kCamera:
+      return "Camera";
+    case PreviewType::kMic:
+      return "Mic";
+    case PreviewType::kCameraAndMic:
+      return "CameraAndMic";
   }
-  return ui_location + "." + preview_type;
+}
+
+// Doesn't accept a Context with PreviewType::kCameraAndMic.
+std::string GetUiLocationAndPreviewTypeString(const Context& context) {
+  CHECK_NE(context.preview_type, PreviewType::kCameraAndMic);
+  return GetUiLocationString(context) + "." + GetPreviewTypeString(context);
+}
+
+std::string GetUiLocationAndPreviewTypeStringAllowingBoth(
+    const Context& context) {
+  if (context.preview_type == PreviewType::kCameraAndMic) {
+    CHECK_EQ(context.ui_location, UiLocation::kPermissionPrompt);
+  }
+  return GetUiLocationString(context) + "." + GetPreviewTypeString(context);
 }
 
 void UmaHistogramLinearCounts(const std::string& name,
@@ -73,152 +72,75 @@
 
 }  // anonymous namespace
 
-namespace media_preview_metrics {
-
-Context::Context(UiLocation ui_location) : ui_location(ui_location) {}
 Context::Context(UiLocation ui_location, PreviewType preview_type)
     : ui_location(ui_location), preview_type(preview_type) {}
 Context::~Context() = default;
 
-void RecordPageInfoCameraNumInUseDevices(int devices) {
-  base::UmaHistogramExactLinear(
-      "MediaPreviews.UI.PageInfo.Camera.NumInUseDevices", devices, 5);
+void RecordPageInfoNumInUseDevices(const Context& context, int devices) {
+  CHECK_EQ(context.ui_location, UiLocation::kPageInfo);
+  std::string location_plus_type = GetUiLocationAndPreviewTypeString(context);
+  std::string metric_name = kUiPrefix + location_plus_type + ".NumInUseDevices";
+  base::UmaHistogramExactLinear(metric_name, devices, /*exclusive_max=*/5);
 }
 
-void RecordPageInfoMicNumInUseDevices(int devices) {
-  base::UmaHistogramExactLinear("MediaPreviews.UI.PageInfo.Mic.NumInUseDevices",
-                                devices, 5);
-}
-
-void RecordDeviceSelectionTotalDevices(Context context, int devices) {
-  std::optional<std::string> context_metric_id = MapContextToString(context);
-  if (!context_metric_id) {
-    return;
-  }
-  std::string metric_name =
-      "MediaPreviews.UI.DeviceSelection." + *context_metric_id + ".NumDevices";
-  base::UmaHistogramExactLinear(metric_name, devices, 5);
-}
-
-void RecordPreviewCameraPixelHeight(Context context, int pixel_height) {
-  std::string context_metric_id;
-  switch (context.ui_location) {
-    case media_preview_metrics::UiLocation::kPermissionPrompt:
-      context_metric_id = "MediaPreviews.UI.Permissions.Camera.PixelHeight";
-      break;
-    case media_preview_metrics::UiLocation::kPageInfo:
-      context_metric_id = "MediaPreviews.UI.PageInfo.Camera.PixelHeight";
-      break;
-    default:
-#if DCHECK_IS_ON()
-      NOTREACHED_NORETURN() << "Context ui_location is unknown";
-#else
-      LOG(ERROR) << "Context ui_location is unknown";
-      return;
-#endif
-  }
-  // This really has 8 buckets for 1-1080, but we have to add 2 for underflow
-  // and overflow.
-  UmaHistogramLinearCounts(context_metric_id, pixel_height, 1, 1080, 10);
-}
-
-void RecordPreviewVideoExpectedFPS(Context context, int expected_fps) {
-  std::string context_metric_id;
-  switch (context.ui_location) {
-    case media_preview_metrics::UiLocation::kPermissionPrompt:
-      context_metric_id =
-          "MediaPreviews.UI.Preview.Permissions.Video.ExpectedFPS";
-      break;
-    case media_preview_metrics::UiLocation::kPageInfo:
-      context_metric_id = "MediaPreviews.UI.Preview.PageInfo.Video.ExpectedFPS";
-      break;
-    default:
-#if DCHECK_IS_ON()
-      NOTREACHED_NORETURN() << "Context ui_location is unknown";
-#else
-      LOG(ERROR) << "Context ui_location is unknown";
-      return;
-#endif
-  }
-  base::UmaHistogramExactLinear(context_metric_id, expected_fps,
-                                /*exclusive_max=*/61);
-}
-
-void RecordDeviceSelectionAction(
-    Context context,
-    MediaPreviewDeviceSelectionUserAction user_action) {
-  std::optional<std::string> context_metric_id = MapContextToString(context);
-  if (!context_metric_id) {
-    return;
-  }
-  std::string metric_name =
-      "MediaPreviews.UI.DeviceSelection." + *context_metric_id + ".Action";
-  base::UmaHistogramEnumeration(metric_name, user_action);
-}
-
-void RecordPreviewVideoActualFPS(Context context, int actual_fps) {
-  std::string context_metric_id;
-  switch (context.ui_location) {
-    case media_preview_metrics::UiLocation::kPermissionPrompt:
-      context_metric_id =
-          "MediaPreviews.UI.Preview.Permissions.Video.ActualFPS";
-      break;
-    case media_preview_metrics::UiLocation::kPageInfo:
-      context_metric_id = "MediaPreviews.UI.Preview.PageInfo.Video.ActualFPS";
-      break;
-    default:
-#if DCHECK_IS_ON()
-      NOTREACHED_NORETURN() << "Context ui_location is unknown";
-#else
-      LOG(ERROR) << "Context ui_location is unknown";
-      return;
-#endif
-  }
-  base::UmaHistogramExactLinear(context_metric_id, actual_fps,
-                                /*exclusive_max=*/61);
-}
-
-void RecordMediaPreviewDuration(Context context, const base::TimeDelta& delta) {
-  std::string metric_name;
-  if (context.preview_type == PreviewType::kCameraAndMic) {
-    if (context.ui_location == UiLocation::kPageInfo) {
-      return;
-    }
-    metric_name = "MediaPreviews.UI.Permissions.CameraAndMic.Duration";
-  } else {
-    std::optional<std::string> context_metric_id = MapContextToString(context);
-    if (!context_metric_id) {
-      return;
-    }
-    metric_name = "MediaPreviews.UI." + context_metric_id.value() + ".Duration";
-  }
-
+void RecordMediaPreviewDuration(const Context& context,
+                                const base::TimeDelta& delta) {
+  std::string location_plus_type =
+      GetUiLocationAndPreviewTypeStringAllowingBoth(context);
+  std::string metric_name = kUiPrefix + location_plus_type + ".Duration";
   GetMediaPreviewDurationHistogram(metric_name)->Add(delta.InSeconds());
 }
 
-void RecordPreviewVideoFramesRenderedPercent(Context context, float percent) {
-  std::string context_metric_id;
-  switch (context.ui_location) {
-    case media_preview_metrics::UiLocation::kPermissionPrompt:
-      context_metric_id =
-          "MediaPreviews.UI.Preview.Permissions.Video.RenderedPercent";
-      break;
-    case media_preview_metrics::UiLocation::kPageInfo:
-      context_metric_id =
-          "MediaPreviews.UI.Preview.PageInfo.Video.RenderedPercent";
-      break;
-    default:
-#if DCHECK_IS_ON()
-      NOTREACHED_NORETURN() << "Context ui_location is unknown";
-#else
-      LOG(ERROR) << "Context ui_location is unknown";
-      return;
-#endif
-  }
+void RecordDeviceSelectionTotalDevices(const Context& context, int devices) {
+  std::string location_plus_type = GetUiLocationAndPreviewTypeString(context);
+  std::string metric_name =
+      kDeviceSelectionPrefix + location_plus_type + ".NumDevices";
+  base::UmaHistogramExactLinear(metric_name, devices, /*exclusive_max=*/5);
+}
 
+void RecordDeviceSelectionAction(
+    const Context& context,
+    MediaPreviewDeviceSelectionUserAction user_action) {
+  std::string location_plus_type = GetUiLocationAndPreviewTypeString(context);
+  std::string metric_name =
+      kDeviceSelectionPrefix + location_plus_type + ".Action";
+  base::UmaHistogramEnumeration(metric_name, user_action);
+}
+
+void RecordPreviewCameraPixelHeight(const Context& context, int pixel_height) {
+  CHECK_EQ(context.preview_type, PreviewType::kCamera);
+  std::string metric_name =
+      kUiPrefix + GetUiLocationString(context) + ".Camera.PixelHeight";
+  // This really has 8 buckets for 1-1080, but we have to add 2 for underflow
+  // and overflow.
+  UmaHistogramLinearCounts(metric_name, pixel_height, /*minimum=*/1,
+                           /*maximum=*/1080, /*bucket_count=*/10);
+}
+
+void RecordPreviewVideoExpectedFPS(const Context& context, int expected_fps) {
+  CHECK_EQ(context.preview_type, PreviewType::kCamera);
+  std::string metric_name =
+      kVideoPrefix + GetUiLocationString(context) + ".Video.ExpectedFPS";
+  base::UmaHistogramExactLinear(metric_name, expected_fps,
+                                /*exclusive_max=*/61);
+}
+
+void RecordPreviewVideoActualFPS(const Context& context, int actual_fps) {
+  CHECK_EQ(context.preview_type, PreviewType::kCamera);
+  std::string metric_name =
+      kVideoPrefix + GetUiLocationString(context) + ".Video.ActualFPS";
+  base::UmaHistogramExactLinear(metric_name, actual_fps,
+                                /*exclusive_max=*/61);
+}
+
+void RecordPreviewVideoFramesRenderedPercent(const Context& context,
+                                             float percent) {
+  CHECK_EQ(context.preview_type, PreviewType::kCamera);
+  std::string metric_name =
+      kVideoPrefix + GetUiLocationString(context) + ".Video.RenderedPercent";
   // Convert percentage to 0-100 integer.
-  int integer_percent = std::clamp(percent, /*__lo=*/0.0f, /*__hi=*/1.0f) * 100;
-  base::UmaHistogramPercentage(context_metric_id, integer_percent);
+  int integer_percent = std::clamp(percent, /*lo=*/0.0f, /*hi=*/1.0f) * 100;
+  base::UmaHistogramPercentage(metric_name, integer_percent);
 }
 
 }  // namespace media_preview_metrics
diff --git a/chrome/browser/ui/views/media_preview/media_preview_metrics.h b/chrome/browser/ui/views/media_preview/media_preview_metrics.h
index 79f3d60..fc9618a 100644
--- a/chrome/browser/ui/views/media_preview/media_preview_metrics.h
+++ b/chrome/browser/ui/views/media_preview/media_preview_metrics.h
@@ -10,15 +10,14 @@
 namespace media_preview_metrics {
 
 enum class UiLocation { kPermissionPrompt, kPageInfo };
-enum class PreviewType { kUnknown, kCamera, kMic, kCameraAndMic };
+enum class PreviewType { kCamera, kMic, kCameraAndMic };
 
 struct Context {
-  explicit Context(UiLocation ui_location);
   Context(UiLocation ui_location, PreviewType preview_type);
   ~Context();
 
   const UiLocation ui_location;
-  PreviewType preview_type = PreviewType::kUnknown;
+  const PreviewType preview_type;
 };
 
 // These values are persisted to logs. Entries should not be renumbered and
@@ -32,17 +31,20 @@
   kMaxValue = kSelection,
 };
 
-void RecordPageInfoCameraNumInUseDevices(int devices);
-void RecordPageInfoMicNumInUseDevices(int devices);
-void RecordDeviceSelectionTotalDevices(Context context, int devices);
+void RecordPageInfoNumInUseDevices(const Context& context, int devices);
+void RecordMediaPreviewDuration(const Context& context,
+                                const base::TimeDelta& delta);
+
+void RecordDeviceSelectionTotalDevices(const Context& context, int devices);
 void RecordDeviceSelectionAction(
-    Context context,
+    const Context& context,
     MediaPreviewDeviceSelectionUserAction user_action);
-void RecordPreviewCameraPixelHeight(Context context, int pixel_height);
-void RecordPreviewVideoExpectedFPS(Context context, int expected_fps);
-void RecordPreviewVideoActualFPS(Context context, int actual_fps);
-void RecordMediaPreviewDuration(Context context, const base::TimeDelta& delta);
-void RecordPreviewVideoFramesRenderedPercent(Context context, float percent);
+
+void RecordPreviewCameraPixelHeight(const Context& context, int pixel_height);
+void RecordPreviewVideoExpectedFPS(const Context& context, int expected_fps);
+void RecordPreviewVideoActualFPS(const Context& context, int actual_fps);
+void RecordPreviewVideoFramesRenderedPercent(const Context& context,
+                                             float percent);
 
 }  // namespace media_preview_metrics
 
diff --git a/chrome/browser/ui/views/media_preview/media_view_controller_base_unittest.cc b/chrome/browser/ui/views/media_preview/media_view_controller_base_unittest.cc
index d1035a3..ac45fc57 100644
--- a/chrome/browser/ui/views/media_preview/media_view_controller_base_unittest.cc
+++ b/chrome/browser/ui/views/media_preview/media_view_controller_base_unittest.cc
@@ -38,10 +38,8 @@
 }
 
 media_preview_metrics::Context GetMetricsContext() {
-  media_preview_metrics::Context metrics_context(
-      media_preview_metrics::UiLocation::kPermissionPrompt);
-  metrics_context.preview_type = media_preview_metrics::PreviewType::kCamera;
-  return metrics_context;
+  return {media_preview_metrics::UiLocation::kPermissionPrompt,
+          media_preview_metrics::PreviewType::kCamera};
 }
 
 #if !BUILDFLAG(IS_MAC)
diff --git a/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.cc b/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.cc
index 5deb007..01400ac 100644
--- a/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.cc
+++ b/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.cc
@@ -18,12 +18,13 @@
 #include "media/base/audio_parameters.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 
-MicCoordinator::MicCoordinator(views::View& parent_view,
-                               bool needs_borders,
-                               const std::vector<std::string>& eligible_mic_ids,
-                               PrefService& prefs,
-                               bool allow_device_selection,
-                               media_preview_metrics::Context metrics_context)
+MicCoordinator::MicCoordinator(
+    views::View& parent_view,
+    bool needs_borders,
+    const std::vector<std::string>& eligible_mic_ids,
+    PrefService& prefs,
+    bool allow_device_selection,
+    const media_preview_metrics::Context& metrics_context)
     : mic_mediator_(
           prefs,
           base::BindRepeating(&MicCoordinator::OnAudioSourceInfosReceived,
@@ -32,7 +33,8 @@
       eligible_mic_ids_(eligible_mic_ids),
       prefs_(&prefs),
       allow_device_selection_(allow_device_selection),
-      metrics_context_(metrics_context) {
+      metrics_context_(metrics_context.ui_location,
+                       media_preview_metrics::PreviewType::kMic) {
   auto* mic_view = parent_view.AddChildView(std::make_unique<MediaView>());
   mic_view_tracker_.SetView(mic_view);
   // Safe to use base::Unretained() because `this` owns / outlives
@@ -40,8 +42,6 @@
   mic_view_tracker_.SetIsDeletingCallback(base::BindOnce(
       &MicCoordinator::ResetViewController, base::Unretained(this)));
 
-  metrics_context_.preview_type = media_preview_metrics::PreviewType::kMic;
-
   // Safe to use base::Unretained() because `this` owns / outlives
   // `mic_view_controller_`.
   mic_view_controller_.emplace(
diff --git a/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.h b/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.h
index 088de1e..177018a0 100644
--- a/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.h
+++ b/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.h
@@ -30,7 +30,7 @@
                  const std::vector<std::string>& eligible_mic_ids,
                  PrefService& prefs,
                  bool allow_device_selection,
-                 media_preview_metrics::Context metrics_context);
+                 const media_preview_metrics::Context& metrics_context);
   MicCoordinator(const MicCoordinator&) = delete;
   MicCoordinator& operator=(const MicCoordinator&) = delete;
   ~MicCoordinator();
@@ -67,7 +67,7 @@
   std::vector<media::AudioDeviceDescription> eligible_device_infos_;
   raw_ptr<PrefService> prefs_;
   const bool allow_device_selection_;
-  media_preview_metrics::Context metrics_context_;
+  const media_preview_metrics::Context metrics_context_;
   std::optional<MicViewController> mic_view_controller_;
   std::optional<AudioStreamCoordinator> audio_stream_coordinator_;
 };
diff --git a/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator_unittest.cc b/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator_unittest.cc
index 33be697..208e7fb 100644
--- a/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator_unittest.cc
+++ b/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator_unittest.cc
@@ -36,6 +36,13 @@
 constexpr char kDeviceName2[] = "device_name_2";
 constexpr char kGroupId2[] = "group_id2";
 
+media_preview_metrics::Context GetMetricsContext() {
+  // Mic coordinator is expected to narrow preview type to kMic.
+  // This is verified in ExpectHistogramTotalDevices() below.
+  return {media_preview_metrics::UiLocation::kPermissionPrompt,
+          media_preview_metrics::PreviewType::kCameraAndMic};
+}
+
 }  // namespace
 
 class MicCoordinatorTest : public TestWithBrowserView {
@@ -65,12 +72,10 @@
         replied_with_device_descriptions_future.GetCallback());
 
     CHECK(profile()->GetPrefs());
-    coordinator_.emplace(
-        *parent_view_,
-        /*needs_borders=*/true, eligible_mic_ids, *profile()->GetPrefs(),
-        /*allow_device_selection=*/true,
-        media_preview_metrics::Context(
-            media_preview_metrics::UiLocation::kPermissionPrompt));
+    coordinator_.emplace(*parent_view_,
+                         /*needs_borders=*/true, eligible_mic_ids,
+                         *profile()->GetPrefs(),
+                         /*allow_device_selection=*/true, GetMetricsContext());
 
     ASSERT_TRUE(replied_with_device_descriptions_future.WaitAndClear());
   }
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_model_unittest.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_model_unittest.cc
index 7652110..6982ade 100644
--- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_model_unittest.cc
+++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_model_unittest.cc
@@ -13,7 +13,7 @@
 #include "chrome/common/accessibility/read_anything_constants.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/accessibility/accessibility_features.h"
-#include "ui/accessibility/ax_event_notification_details.h"
+#include "ui/accessibility/ax_updates_and_events.h"
 
 using testing::_;
 using testing::FloatNear;
diff --git a/chrome/browser/ui/views/web_apps/app_shim_metrics_browsertest.cc b/chrome/browser/ui/views/web_apps/app_shim_metrics_browsertest.cc
new file mode 100644
index 0000000..a25266c
--- /dev/null
+++ b/chrome/browser/ui/views/web_apps/app_shim_metrics_browsertest.cc
@@ -0,0 +1,37 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/metrics/histogram_tester.h"
+#include "chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+
+namespace web_app::integration_tests {
+namespace {
+
+using AppShimMetricsTest = WebAppIntegrationTest;
+
+IN_PROC_BROWSER_TEST_F(AppShimMetricsTest, Basics) {
+  base::HistogramTester histogram_tester;
+  helper_.CreateShortcut(Site::kStandalone, WindowOptions::kWindowed);
+  helper_.CheckWindowCreated();
+
+  content::FetchHistogramsFromChildProcesses();
+  histogram_tester.ExpectTotalCount("AppShim.Launched",
+                                    /*expected_count=*/1);
+  histogram_tester.ExpectTotalCount("AppShim.WillTerminate",
+                                    /*expected_count=*/0);
+
+  helper_.QuitAppShim(Site::kStandalone);
+  helper_.CheckWindowClosed();
+
+  // After quitting we should have metrics from it.
+  histogram_tester.ExpectTotalCount("AppShim.Launched",
+                                    /*expected_count=*/1);
+  histogram_tester.ExpectTotalCount("AppShim.WillTerminate",
+                                    /*expected_count=*/1);
+}
+
+}  // namespace
+}  // namespace web_app::integration_tests
diff --git a/chrome/browser/ui/web_applications/web_app_title_browsertest.cc b/chrome/browser/ui/web_applications/web_app_title_browsertest.cc
index 9ecbaa5..4da10b78 100644
--- a/chrome/browser/ui/web_applications/web_app_title_browsertest.cc
+++ b/chrome/browser/ui/web_applications/web_app_title_browsertest.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/ui/web_applications/web_app_browsertest_base.h"
 #include "chrome/browser/web_applications/web_app_helpers.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "chrome/test/base/web_feature_histogram_tester.h"
 #include "components/metrics/content/subprocess_metrics_provider.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
@@ -26,17 +27,12 @@
   }
 };
 
-// TODO(b/330201484): Deflake and re-enable.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_ValidAppTitle DISABLED_ValidAppTitle
-#else
-#define MAYBE_ValidAppTitle ValidAppTitle
-#endif
-IN_PROC_BROWSER_TEST_F(WebAppTitleBrowserTest, MAYBE_ValidAppTitle) {
+// Test app title with valid app title.
+IN_PROC_BROWSER_TEST_F(WebAppTitleBrowserTest, ValidAppTitle) {
   const GURL app_url =
       https_server()->GetURL("/web_apps/page_with_app_title.html");
   const std::u16string app_title = u"A Web App";
-  base::HistogramTester histogram_tester;
+  WebFeatureHistogramTester histogram_tester;
 
   auto web_app_info = std::make_unique<WebAppInstallInfo>(
       GenerateManifestIdFromStartUrlOnly(app_url));
@@ -56,9 +52,8 @@
   // Navigate away to flush use counters.
   ASSERT_TRUE(
       ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("Blink.UseCounter.Features"),
-      BucketsInclude(base::Bucket(blink::mojom::WebFeature::kWebAppTitle, 1)));
+  // Log histogram map.
+  histogram_tester.ExpectCounts({{blink::mojom::WebFeature::kWebAppTitle, 1}});
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppTitleBrowserTest, WithoutAppTitle) {
@@ -154,17 +149,11 @@
 }
 
 // Navigate to page with and without app title to validate app title is updated.
-#if BUILDFLAG(IS_LINUX)
-// TODO(b/328563549): Re-enable after the bug is fixed.
-#define MAYBE_AppTitleNavigation DISABLED_AppTitleNavigation
-#else
-#define MAYBE_AppTitleNavigation AppTitleNavigation
-#endif
-IN_PROC_BROWSER_TEST_F(WebAppTitleBrowserTest, MAYBE_AppTitleNavigation) {
+IN_PROC_BROWSER_TEST_F(WebAppTitleBrowserTest, AppTitleNavigation) {
   const GURL app_url =
       https_server()->GetURL("/web_apps/page_with_app_title.html");
   const std::u16string app_title = u"A Web App";
-  base::HistogramTester histogram_tester;
+  WebFeatureHistogramTester histogram_tester;
 
   auto web_app_info = std::make_unique<WebAppInstallInfo>(
       GenerateManifestIdFromStartUrlOnly(app_url));
@@ -204,8 +193,6 @@
   // Explicitly fetch the metrics from the child processes and merge them.
   content::FetchHistogramsFromChildProcesses();
   metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("Blink.UseCounter.Features"),
-      BucketsInclude(base::Bucket(blink::mojom::WebFeature::kWebAppTitle, 1)));
+  histogram_tester.ExpectCounts({{blink::mojom::WebFeature::kWebAppTitle, 1}});
 }
 }  // namespace web_app
diff --git a/chrome/browser/ui/webui/accessibility/accessibility_ui.cc b/chrome/browser/ui/webui/accessibility/accessibility_ui.cc
index e24745e..aff8a18 100644
--- a/chrome/browser/ui/webui/accessibility/accessibility_ui.cc
+++ b/chrome/browser/ui/webui/accessibility/accessibility_ui.cc
@@ -44,7 +44,7 @@
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "ui/accessibility/accessibility_features.h"
-#include "ui/accessibility/ax_event_notification_details.h"
+#include "ui/accessibility/ax_updates_and_events.h"
 #include "ui/accessibility/platform/ax_platform_node.h"
 #include "ui/accessibility/platform/ax_platform_node_delegate.h"
 #include "ui/accessibility/platform/inspect/ax_tree_formatter.h"
@@ -427,7 +427,7 @@
 AccessibilityUIObserver::~AccessibilityUIObserver() = default;
 
 void AccessibilityUIObserver::AccessibilityEventReceived(
-    const ui::AXEventNotificationDetails& details) {
+    const ui::AXUpdatesAndEvents& details) {
   for (const ui::AXEvent& event : details.events) {
     event_logs_->push_back(event.ToString());
   }
diff --git a/chrome/browser/ui/webui/accessibility/accessibility_ui.h b/chrome/browser/ui/webui/accessibility/accessibility_ui.h
index 8fae106..45dead3 100644
--- a/chrome/browser/ui/webui/accessibility/accessibility_ui.h
+++ b/chrome/browser/ui/webui/accessibility/accessibility_ui.h
@@ -22,7 +22,7 @@
 #include "ui/accessibility/platform/inspect/ax_api_type.h"
 
 namespace ui {
-struct AXEventNotificationDetails;
+struct AXUpdatesAndEvents;
 }
 
 namespace content {
@@ -60,7 +60,7 @@
   ~AccessibilityUIObserver() override;
 
   void AccessibilityEventReceived(
-      const ui::AXEventNotificationDetails& details) override;
+      const ui::AXUpdatesAndEvents& details) override;
 
  private:
   raw_ptr<std::vector<std::string>> event_logs_;
diff --git a/chrome/browser/ui/webui/ash/app_install/app_install_dialog.cc b/chrome/browser/ui/webui/ash/app_install/app_install_dialog.cc
index 5951428..4b9db7ea 100644
--- a/chrome/browser/ui/webui/ash/app_install/app_install_dialog.cc
+++ b/chrome/browser/ui/webui/ash/app_install/app_install_dialog.cc
@@ -122,8 +122,10 @@
   icon_value->uncompressed = icon.AsImageSkia();
 
   apps::ApplyIconEffects(profile_.get(), /*app_id=*/std::nullopt,
-                         apps::IconEffects::kCrOsStandardIcon, icon_width,
-                         std::move(icon_value),
+                         is_icon_maskable
+                             ? apps::IconEffects::kCrOsStandardMask
+                             : apps::IconEffects::kCrOsStandardIcon,
+                         icon_width, std::move(icon_value),
                          base::BindOnce(&AppInstallDialog::OnLoadIcon,
                                         weak_factory_.GetWeakPtr()));
 }
diff --git a/chrome/browser/ui/webui/ash/mako/mako_bubble_event_handler.cc b/chrome/browser/ui/webui/ash/mako/mako_bubble_event_handler.cc
index f0cc94f..29ddbd44 100644
--- a/chrome/browser/ui/webui/ash/mako/mako_bubble_event_handler.cc
+++ b/chrome/browser/ui/webui/ash/mako/mako_bubble_event_handler.cc
@@ -12,6 +12,99 @@
 
 namespace ash {
 
+namespace {
+
+using State = MakoBubbleEventHandler::State;
+using InitialState = MakoBubbleEventHandler::InitialState;
+using DraggingState = MakoBubbleEventHandler::DraggingState;
+
+bool IsInSameDisplay(const gfx::Rect& original_bounds,
+                     const gfx::Rect& new_bounds) {
+  display::Screen* screen = display::Screen::GetScreen();
+  if (screen == nullptr) {
+    return false;
+  }
+  display::Display original_display =
+      screen->GetDisplayMatching(original_bounds);
+  display::Display new_display = screen->GetDisplayMatching(new_bounds);
+  return new_display.id() == original_display.id();
+}
+
+class StateProcessFunction {
+ public:
+  StateProcessFunction(ui::LocatedEvent* event,
+                       MakoBubbleEventHandler::Delegate* delegate)
+      : event_(event), delegate_(delegate) {}
+
+  State operator()(const InitialState& s) {
+    if (event_->type() == ui::ET_TOUCH_PRESSED ||
+        event_->type() == ui::ET_MOUSE_PRESSED) {
+      // Starts dragging.
+      if (InDraggableRegion()) {
+        MarkEventHandled();
+        return DraggingState{
+            .original_bounds_in_screen = GetBoundsInScreen(),
+            .original_pointer_pos =
+                GetBoundsInScreen().OffsetFromOrigin() + GetPointerPos(),
+        };
+      }
+    }
+
+    return InitialState{};
+  }
+
+  State operator()(const DraggingState& s) {
+    // Keeps dragging.
+    if (event_->type() == ui::ET_MOUSE_DRAGGED ||
+        event_->type() == ui::ET_TOUCH_MOVED) {
+      gfx::Rect new_bounds = s.original_bounds_in_screen +
+                             GetBoundsInScreen().OffsetFromOrigin() +
+                             GetPointerPos() - s.original_pointer_pos;
+
+      // If user moves mouse to another display while dragging, we see that
+      // as a completion of dragging.
+      if (!IsInSameDisplay(s.original_bounds_in_screen, new_bounds)) {
+        return InitialState{};
+      }
+
+      SetWidgetBoundsConstrained(new_bounds);
+      MarkEventHandled();
+
+      return s;
+    }
+
+    return InitialState{};
+  }
+
+ private:
+  gfx::Vector2d GetPointerPos() const {
+    return gfx::Vector2d(base::ClampFloor(event_->x()),
+                         base::ClampFloor(event_->y()));
+  }
+
+  gfx::Rect GetBoundsInScreen() const {
+    return delegate_->GetWidgetBoundsInScreen();
+  }
+
+  void SetWidgetBoundsConstrained(const gfx::Rect bounds) {
+    delegate_->SetWidgetBoundsConstrained(bounds);
+  }
+
+  void MarkEventHandled() { event_->SetHandled(); }
+
+  bool InDraggableRegion() {
+    std::optional<SkRegion> draggable_region = delegate_->GetDraggableRegion();
+    gfx::Vector2d pointer_pos = GetPointerPos();
+    return draggable_region.has_value() &&
+           draggable_region->contains(pointer_pos.x(), pointer_pos.y());
+  }
+
+  raw_ptr<ui::LocatedEvent> event_;
+  raw_ptr<MakoBubbleEventHandler::Delegate> delegate_;
+};
+
+}  // namespace
+
 MakoBubbleEventHandler::MakoBubbleEventHandler(Delegate* delegate)
     : delegate_(delegate) {}
 
@@ -23,81 +116,20 @@
   ProcessPointerEvent(*event);
 }
 
-bool MakoBubbleEventHandler::get_dragging_for_testing() {
-  return dragging_;
+MakoBubbleEventHandler::State MakoBubbleEventHandler::get_state_for_testing() {
+  return state_;
 }
 
-void MakoBubbleEventHandler::set_dragging_for_testing(bool dragging) {
-  dragging_ = dragging;
-}
-
-void MakoBubbleEventHandler::set_original_bounds_in_screen_for_testing(
-    gfx::Rect bounds) {
-  original_bounds_in_screen_ = bounds;
-}
-
-void MakoBubbleEventHandler::set_original_pointer_pos_for_testing(
-    gfx::Vector2d pos) {
-  original_pointer_pos_ = pos;
-}
-
-bool MakoBubbleEventHandler::IsInSameDisplay(const gfx::Rect& original_bounds,
-                                             const gfx::Rect& new_bounds) {
-  display::Screen* screen = display::Screen::GetScreen();
-  if (!screen) {
-    return false;
-  }
-  display::Display original_display =
-      screen->GetDisplayMatching(original_bounds);
-  display::Display new_display = screen->GetDisplayMatching(new_bounds);
-  return new_display.id() == original_display.id();
+void MakoBubbleEventHandler::set_state_for_testing(State s) {
+  state_ = s;
 }
 
 void MakoBubbleEventHandler::ProcessPointerEvent(ui::LocatedEvent& event) {
   if (!delegate_) {
     return;
   }
-
-  const gfx::Rect bounds_in_screen = delegate_->GetWidgetBoundsInScreen();
-  const std::optional<SkRegion> draggable_region =
-      delegate_->GetDraggableRegion();
-  const gfx::Vector2d pointer_pos(base::ClampFloor(event.x()),
-                                  base::ClampFloor(event.y()));
-
-  switch (event.type()) {
-    case ui::ET_TOUCH_PRESSED:
-    case ui::ET_MOUSE_PRESSED:
-      if (draggable_region.has_value() &&
-          draggable_region->contains(pointer_pos.x(), pointer_pos.y())) {
-        dragging_ = true;
-        original_bounds_in_screen_ = bounds_in_screen;
-        original_pointer_pos_ = gfx::Vector2d(
-            /*x=*/bounds_in_screen.x() + pointer_pos.x(),
-            /*y=*/bounds_in_screen.y() + pointer_pos.y());
-      }
-      break;
-    case ui::ET_MOUSE_DRAGGED:
-    case ui::ET_TOUCH_MOVED: {
-      if (!dragging_) {
-        break;
-      }
-      gfx::Rect new_bounds = original_bounds_in_screen_ +
-                             bounds_in_screen.OffsetFromOrigin() + pointer_pos -
-                             original_pointer_pos_;
-      // If user moves mouse to another display while dragging, we see that
-      // as a completion of dragging.
-      if (!IsInSameDisplay(original_bounds_in_screen_, new_bounds)) {
-        dragging_ = false;
-        break;
-      }
-      delegate_->SetWidgetBoundsConstrained(new_bounds);
-      event.SetHandled();
-    } break;
-
-    default:
-      dragging_ = false;
-      break;
-  }
+  state_ = absl::visit(
+      StateProcessFunction(/*event=*/&event, /*delegate=*/delegate_), state_);
 }
 
 }  // namespace ash
diff --git a/chrome/browser/ui/webui/ash/mako/mako_bubble_event_handler.h b/chrome/browser/ui/webui/ash/mako/mako_bubble_event_handler.h
index c48c1f32..c3c0e4d9 100644
--- a/chrome/browser/ui/webui/ash/mako/mako_bubble_event_handler.h
+++ b/chrome/browser/ui/webui/ash/mako/mako_bubble_event_handler.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_WEBUI_ASH_MAKO_MAKO_BUBBLE_EVENT_HANDLER_H_
 
 #include "base/memory/raw_ptr.h"
+#include "third_party/abseil-cpp/absl/types/variant.h"
 #include "third_party/skia/include/core/SkRegion.h"
 #include "ui/events/event.h"
 #include "ui/events/event_handler.h"
@@ -25,6 +26,13 @@
     virtual void SetWidgetBoundsConstrained(const gfx::Rect bounds) = 0;
   };
 
+  struct InitialState {};
+  struct DraggingState {
+    gfx::Rect original_bounds_in_screen;
+    gfx::Vector2d original_pointer_pos;
+  };
+  using State = absl::variant<InitialState, DraggingState>;
+
   explicit MakoBubbleEventHandler(Delegate* delegate);
 
   MakoBubbleEventHandler(const MakoBubbleEventHandler&) = delete;
@@ -37,20 +45,14 @@
   void OnMouseEvent(ui::MouseEvent* event) override;
 
   // Test only
-  bool get_dragging_for_testing();
-  void set_dragging_for_testing(bool dragging);
-  void set_original_bounds_in_screen_for_testing(gfx::Rect bounds);
-  void set_original_pointer_pos_for_testing(gfx::Vector2d pos);
+  State get_state_for_testing();
+  void set_state_for_testing(State s);
 
  private:
-  bool IsInSameDisplay(const gfx::Rect& original_bounds,
-                       const gfx::Rect& new_bounds);
   void ProcessPointerEvent(ui::LocatedEvent& event);
 
   raw_ptr<Delegate> delegate_;
-  bool dragging_ = false;
-  gfx::Rect original_bounds_in_screen_;
-  gfx::Vector2d original_pointer_pos_;
+  State state_;
 };
 
 }  // namespace ash
diff --git a/chrome/browser/ui/webui/ash/mako/mako_bubble_event_handler_unittest.cc b/chrome/browser/ui/webui/ash/mako/mako_bubble_event_handler_unittest.cc
index 23b2527..4da0bb2 100644
--- a/chrome/browser/ui/webui/ash/mako/mako_bubble_event_handler_unittest.cc
+++ b/chrome/browser/ui/webui/ash/mako/mako_bubble_event_handler_unittest.cc
@@ -5,6 +5,8 @@
 #include "chrome/browser/ui/webui/ash/mako/mako_bubble_event_handler.h"
 
 #include "chrome/test/views/chrome_views_test_base.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkRect.h"
 #include "third_party/skia/include/core/SkRegion.h"
 #include "ui/events/event.h"
@@ -14,6 +16,9 @@
 namespace ash {
 namespace {
 
+using testing::_;
+using testing::VariantWith;
+
 class DelegateForTest : public ash::MakoBubbleEventHandler::Delegate {
  public:
   virtual ~DelegateForTest() = default;
@@ -82,7 +87,8 @@
 
   handler_.OnTouchEvent(event.get());
 
-  EXPECT_TRUE(handler_.get_dragging_for_testing());
+  EXPECT_THAT(handler_.get_state_for_testing(),
+              VariantWith<ash::MakoBubbleEventHandler::DraggingState>(_));
 }
 
 TEST_F(MakoBubbleEventHandlerTest, TouchPressedEventIsIgnored) {
@@ -92,7 +98,8 @@
 
   handler_.OnTouchEvent(event.get());
 
-  EXPECT_FALSE(handler_.get_dragging_for_testing());
+  EXPECT_THAT(handler_.get_state_for_testing(),
+              VariantWith<ash::MakoBubbleEventHandler::InitialState>(_));
 }
 
 TEST_F(MakoBubbleEventHandlerTest, MousePressedEventStartsDragging) {
@@ -102,7 +109,8 @@
 
   handler_.OnMouseEvent(event.get());
 
-  EXPECT_TRUE(handler_.get_dragging_for_testing());
+  EXPECT_THAT(handler_.get_state_for_testing(),
+              VariantWith<ash::MakoBubbleEventHandler::DraggingState>(_));
 }
 
 TEST_F(MakoBubbleEventHandlerTest, MousePressedEventIsIgnored) {
@@ -112,22 +120,23 @@
 
   handler_.OnMouseEvent(event.get());
 
-  EXPECT_FALSE(handler_.get_dragging_for_testing());
+  EXPECT_THAT(handler_.get_state_for_testing(),
+              VariantWith<ash::MakoBubbleEventHandler::InitialState>(_));
 }
 
 TEST_F(MakoBubbleEventHandlerTest, TouchMovedEventProcceedsDragging) {
   // In this test, the widget was first positioned at (x=50,y=50,w=300,h=300).
   // Mouse drags from (140, 140) to (150, 150) and so the widget should be
   // moved to (x=60, y=60, w=300, h=300).
-  handler_.set_dragging_for_testing(true);
-  handler_.set_original_bounds_in_screen_for_testing(gfx::Rect(
-      /*x=*/50,
-      /*y=*/50,
-      /*width=*/300,
-      /*height=*/300));
-  // The original pointer position is relative to screen, so it's 140 + 50.
-  handler_.set_original_pointer_pos_for_testing(
-      gfx::Vector2d(/*x=*/140 + 50, /*y=*/140 + 50));
+  handler_.set_state_for_testing(MakoBubbleEventHandler::DraggingState{
+      .original_bounds_in_screen = gfx::Rect(
+          /*x=*/50,
+          /*y=*/50,
+          /*width=*/300,
+          /*height=*/300),
+      // The original pointer position is relative to screen, so it's 140 + 50.
+      .original_pointer_pos = gfx::Vector2d(/*x=*/140 + 50, /*y=*/140 + 50),
+  });
   std::unique_ptr<ui::TouchEvent> event = MakeTouchEvent(
       /*type=*/ui::ET_TOUCH_MOVED,
       /*in_draggable_region=*/true);
@@ -143,7 +152,7 @@
 }
 
 TEST_F(MakoBubbleEventHandlerTest, TouchMovedEventIsIgnored) {
-  handler_.set_dragging_for_testing(false);
+  handler_.set_state_for_testing(MakoBubbleEventHandler::InitialState{});
   std::unique_ptr<ui::TouchEvent> event = MakeTouchEvent(
       /*type=*/ui::ET_TOUCH_MOVED,
       /*in_draggable_region=*/true);
@@ -157,16 +166,14 @@
   // In this test, the widget was first positioned at (x=50,y=50,w=300,h=300).
   // Mouse drags from (140, 140) to (150, 150) and so the widget should be
   // moved to (x=60, y=60, w=300, h=300).
-  handler_.set_dragging_for_testing(true);
-  handler_.set_original_bounds_in_screen_for_testing(gfx::Rect(
-      /*x=*/50,
-      /*y=*/50,
-      /*width=*/300,
-      /*height=*/300));
-  // The original pointer position is relative to screen, so it's 140 + 50.
-  handler_.set_original_pointer_pos_for_testing(
-      gfx::Vector2d(/*x=*/140 + 50, /*y=*/140 + 50));
-  handler_.set_dragging_for_testing(true);
+  handler_.set_state_for_testing(MakoBubbleEventHandler::DraggingState{
+      .original_bounds_in_screen = gfx::Rect(
+          /*x=*/50,
+          /*y=*/50,
+          /*width=*/300,
+          /*height=*/300),
+      // The original pointer position is relative to screen, so it's 140 + 50.
+      .original_pointer_pos = gfx::Vector2d(/*x=*/140 + 50, /*y=*/140 + 50)});
   std::unique_ptr<ui::MouseEvent> event = makeMouseEvent(
       /*type=*/ui::ET_MOUSE_DRAGGED,
       /*in_draggable_region=*/true);
@@ -182,7 +189,7 @@
 }
 
 TEST_F(MakoBubbleEventHandlerTest, MouseDraggedEventIsIgnored) {
-  handler_.set_dragging_for_testing(false);
+  handler_.set_state_for_testing(MakoBubbleEventHandler::InitialState{});
   std::unique_ptr<ui::MouseEvent> event = makeMouseEvent(
       /*type=*/ui::ET_MOUSE_DRAGGED,
       /*in_draggable_region=*/true);
@@ -193,7 +200,7 @@
 }
 
 TEST_F(MakoBubbleEventHandlerTest, TouchReleasedEventStopsDragging) {
-  handler_.set_dragging_for_testing(true);
+  handler_.set_state_for_testing(MakoBubbleEventHandler::DraggingState{});
 
   std::unique_ptr<ui::TouchEvent> event = MakeTouchEvent(
       /*type=*/ui::ET_TOUCH_RELEASED,
@@ -201,11 +208,12 @@
 
   handler_.OnTouchEvent(event.get());
 
-  EXPECT_FALSE(handler_.get_dragging_for_testing());
+  EXPECT_THAT(handler_.get_state_for_testing(),
+              VariantWith<ash::MakoBubbleEventHandler::InitialState>(_));
 }
 
 TEST_F(MakoBubbleEventHandlerTest, MouseReleasedEventStopsDragging) {
-  handler_.set_dragging_for_testing(true);
+  handler_.set_state_for_testing(MakoBubbleEventHandler::DraggingState{});
 
   std::unique_ptr<ui::MouseEvent> event = makeMouseEvent(
       /*type=*/ui::ET_MOUSE_RELEASED,
@@ -213,7 +221,8 @@
 
   handler_.OnMouseEvent(event.get());
 
-  EXPECT_FALSE(handler_.get_dragging_for_testing());
+  EXPECT_THAT(handler_.get_state_for_testing(),
+              VariantWith<ash::MakoBubbleEventHandler::InitialState>(_));
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/webui/cr_components/history_embeddings/history_embeddings_handler.cc b/chrome/browser/ui/webui/cr_components/history_embeddings/history_embeddings_handler.cc
index cb2ec8e0..57425947 100644
--- a/chrome/browser/ui/webui/cr_components/history_embeddings/history_embeddings_handler.cc
+++ b/chrome/browser/ui/webui/cr_components/history_embeddings/history_embeddings_handler.cc
@@ -27,6 +27,8 @@
     item->relative_time = base::UTF16ToUTF8(ui::TimeFormat::Simple(
         ui::TimeFormat::FORMAT_ELAPSED, ui::TimeFormat::LENGTH_SHORT,
         base::Time::Now() - scored_url_row.row.last_visit()));
+    item->last_url_visit_timestamp =
+        scored_url_row.row.last_visit().InMillisecondsFSinceUnixEpoch();
 
     url_formatter::FormatUrlTypes format_types =
         url_formatter::kFormatUrlOmitDefaults |
diff --git a/chrome/browser/ui/webui/help/version_updater_mac.mm b/chrome/browser/ui/webui/help/version_updater_mac.mm
index 5ba26b8..343e16d 100644
--- a/chrome/browser/ui/webui/help/version_updater_mac.mm
+++ b/chrome/browser/ui/webui/help/version_updater_mac.mm
@@ -48,7 +48,7 @@
   VersionUpdater::Status status = VersionUpdater::Status::CHECKING;
   int progress = 0;
   std::string version;
-  std::string err_message;
+  std::u16string err_message;
 
   switch (update_state.state) {
     case updater::UpdateService::UpdateState::State::kCheckingForUpdates:
@@ -73,10 +73,13 @@
       break;
     case updater::UpdateService::UpdateState::State::kUpdateError:
       status = VersionUpdater::Status::FAILED;
-      // TODO(crbug.com/40729907): Localize error string.
-      err_message = base::StringPrintf(
-          "An error occurred. (Error code: %d) (Extra code: %d)",
-          update_state.error_code, update_state.extra_code1);
+      err_message = l10n_util::GetStringFUTF16(
+          IDS_ABOUT_BOX_ERROR_DURING_UPDATE_CHECK,
+          l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_GOOGLE_UPDATE_ERROR,
+                                     base::UTF8ToUTF16(base::StringPrintf(
+                                         "%d", update_state.error_code)),
+                                     base::UTF8ToUTF16(base::StringPrintf(
+                                         "%d", update_state.extra_code1))));
       break;
     case updater::UpdateService::UpdateState::State::kNotStarted:
       [[fallthrough]];
@@ -84,8 +87,7 @@
       return;
   }
 
-  status_callback.Run(status, progress, false, false, version, 0,
-                      base::UTF8ToUTF16(err_message));
+  status_callback.Run(status, progress, false, false, version, 0, err_message);
 }
 
 // macOS implementation of version update functionality, used by the WebUI
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
index 6095e93f..0df6819 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
@@ -459,7 +459,7 @@
       {"modulesDriveInfo", IDS_NTP_MODULES_DRIVE_INFO},
       {"modulesDummyTitle", IDS_NTP_MODULES_DUMMY_TITLE},
       {"modulesFeedTitle", IDS_NTP_MODULES_FEED_TITLE},
-      {"modulesGoogleCalendarTitle", IDS_NTP_MODULES_GOOGLE_CALENDAR_TITLE},
+      {"modulesTodayCalendarHeader", IDS_NTP_MODULES_TODAY_CALENDAR_HEADER},
       {"modulesKaleidoscopeTitle", IDS_NTP_MODULES_KALEIDOSCOPE_TITLE},
       {"modulesPhotosInfo", IDS_NTP_MODULES_PHOTOS_INFO},
       {"modulesPhotosSentence", IDS_NTP_MODULES_PHOTOS_MEMORIES_TITLE},
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc
index 78846464..e6078870 100644
--- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc
+++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc
@@ -94,7 +94,6 @@
       {"toolbarHeader", IDS_NTP_CUSTOMIZE_MENU_TOOLBAR_LABEL},
       // Appearance strings.
       {"changeTheme", IDS_NTP_CUSTOMIZE_CHROME_CHANGE_THEME_LABEL},
-      {"chromeColors", IDS_NTP_CUSTOMIZE_CHROME_COLORS_LABEL},
       {"chromeWebStore", IDS_EXTENSION_WEB_STORE_TITLE},
       {"classicChrome", IDS_NTP_CUSTOMIZE_NO_BACKGROUND_LABEL},
       {"colorsContainerLabel", IDS_NTP_THEMES_CONTAINER_LABEL},
diff --git a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.cc b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.cc
index 5438794d..03a7e38 100644
--- a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.cc
+++ b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.cc
@@ -191,7 +191,7 @@
 ReadAnythingWebContentsObserver::~ReadAnythingWebContentsObserver() = default;
 
 void ReadAnythingWebContentsObserver::AccessibilityEventReceived(
-    const ui::AXEventNotificationDetails& details) {
+    const ui::AXUpdatesAndEvents& details) {
   page_handler_->AccessibilityEventReceived(details);
 }
 
@@ -294,7 +294,7 @@
 }
 
 void ReadAnythingUntrustedPageHandler::AccessibilityEventReceived(
-    const ui::AXEventNotificationDetails& details) {
+    const ui::AXUpdatesAndEvents& details) {
   page_->AccessibilityEventReceived(details.ax_tree_id, details.updates,
                                     details.events);
 }
diff --git a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.h b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.h
index 5fc8ac5..293d309 100644
--- a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.h
+++ b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.h
@@ -25,7 +25,7 @@
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "ui/accessibility/ax_action_data.h"
-#include "ui/accessibility/ax_event_notification_details.h"
+#include "ui/accessibility/ax_updates_and_events.h"
 
 namespace content {
 class ScopedAccessibilityMode;
@@ -53,7 +53,7 @@
 
   // content::WebContentsObserver:
   void AccessibilityEventReceived(
-      const ui::AXEventNotificationDetails& details) override;
+      const ui::AXUpdatesAndEvents& details) override;
   void PrimaryPageChanged(content::Page& page) override;
 
   // base::SafeRef used since the lifetime of ReadAnythingWebContentsObserver is
@@ -95,8 +95,7 @@
       const ReadAnythingUntrustedPageHandler&) = delete;
   ~ReadAnythingUntrustedPageHandler() override;
 
-  void AccessibilityEventReceived(
-      const ui::AXEventNotificationDetails& details);
+  void AccessibilityEventReceived(const ui::AXUpdatesAndEvents& details);
   void PrimaryPageChanged();
 
  private:
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index aaf64cd..3fb85ec 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1713290309-627f91f945227784668eb64ad82353af809037d6-04f0cdd042e8b9f8c88e52502b1d4ffabe1adda4.profdata
+chrome-android32-main-1713311815-1889ff810d00b43baeb4d2c56f00396941e76a88-38a628064b77ab180a922d8340eac1b0353950af.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 1c42459..d07fc52f6 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1713211165-50cbdc4b747714b48d89b2c2a991b15af166fe53-fdfe7c40f5a970a48bba96757c08b1c7d63ada1a.profdata
+chrome-mac-arm-main-1713311815-8c91a8341ca73c4c2f761dce3c6e17b1dcff0900-38a628064b77ab180a922d8340eac1b0353950af.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 40767c3f..d233583 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1713290309-5f35a64ffd0ddfdab6284e80994c11d21783b1f4-04f0cdd042e8b9f8c88e52502b1d4ffabe1adda4.profdata
+chrome-win32-main-1713301186-e8dc77263a45f3391d276fd1e35724869831a992-00de2a9e298799fa923cf42cb85cad16cbf4466f.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 7460167..0e90da6 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1713290309-88c78a47cfe054ff6851c66ec78df8f24dae4836-04f0cdd042e8b9f8c88e52502b1d4ffabe1adda4.profdata
+chrome-win64-main-1713301186-7fa3433d41e49d4fe6158683f0676c0602f38a49-00de2a9e298799fa923cf42cb85cad16cbf4466f.profdata
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 164c034..709bd41 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -769,6 +769,8 @@
 
   if (is_mac) {
     sources += [ "mac/app_shim.mojom" ]
+    deps +=
+        [ "//components/metrics/public/mojom:histogram_fetcher_mojo_bindings" ]
     cpp_typemaps = [
       {
         types = [
diff --git a/chrome/common/mac/app_shim.mojom b/chrome/common/mac/app_shim.mojom
index 3598b2035..801d52c4 100644
--- a/chrome/common/mac/app_shim.mojom
+++ b/chrome/common/mac/app_shim.mojom
@@ -10,6 +10,7 @@
 import "mojo/public/mojom/base/string16.mojom";
 import "ui/gfx/image/mojom/image.mojom";
 import "url/mojom/url.mojom";
+import "components/metrics/public/mojom/histogram_fetcher.mojom";
 
 enum AppShimLaunchType {
   // Process the app shim's LaunchAppmessage and associate the shim with the
@@ -124,6 +125,11 @@
   // to accept permissions if not granted or denied already.
   RequestNotificationPermission()
       => (mac_notifications.mojom.RequestPermissionResult result);
+
+  // Called to connect to a ChildHistogramFetcherFactory, to allow chrome to
+  // fetch histogram data from the app shim.
+  BindChildHistogramFetcherFactory(
+      pending_receiver<metrics.mojom.ChildHistogramFetcherFactory> receiver);
 };
 
 // Interface through which the a process communicates to the browser process.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 070a8f3..a377cc1 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -851,6 +851,7 @@
       "//ash/webui/firmware_update_ui:url_constants",
       "//ash/webui/os_feedback_ui:url_constants",
       "//ash/webui/personalization_app:test_support",
+      "//ash/webui/print_management:url_constants",
       "//ash/webui/print_preview_cros:url_constants",
       "//ash/webui/scanning:url_constants",
       "//ash/webui/shortcut_customization_ui:url_constants",
@@ -3345,6 +3346,7 @@
         "../browser/ui/test/test_browser_dialog_mac.mm",
         "../browser/ui/views/frame/browser_non_client_frame_view_mac_browsertest.mm",
         "../browser/ui/views/fullscreen_mac_browsertest.cc",
+        "../browser/ui/views/web_apps/app_shim_metrics_browsertest.cc",
         "../browser/ui/views/web_apps/web_app_integration_browsertest_mac.cc",
         "../browser/webshare/mac/sharing_service_operation_browsertest.cc",
         "../common/mac/app_mode_chrome_locator_browsertest.mm",
@@ -9165,6 +9167,7 @@
       "../browser/extensions/permissions/permissions_manager_unittest.cc",
       "../browser/extensions/permissions/permissions_updater_unittest.cc",
       "../browser/extensions/permissions/scripting_permissions_modifier_unittest.cc",
+      "../browser/extensions/permissions/site_access_requests_helper_unittest.cc",
       "../browser/extensions/permissions/site_permissions_helper_unittest.cc",
       "../browser/extensions/permissions_based_management_policy_provider_unittest.cc",
       "../browser/extensions/policy_handlers_unittest.cc",
diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn
index 8b9c89f..b047c05 100644
--- a/chrome/test/android/BUILD.gn
+++ b/chrome/test/android/BUILD.gn
@@ -199,6 +199,7 @@
   resources_package = "org.chromium.chrome.test"
 
   sources = [
+    "javatests/src/org/chromium/chrome/test/transit/BlankCTATabInitialStatePublicTransitRule.java",
     "javatests/src/org/chromium/chrome/test/transit/ChromeTabbedActivityPublicTransitEntryPoints.java",
     "javatests/src/org/chromium/chrome/test/transit/HubBaseStation.java",
     "javatests/src/org/chromium/chrome/test/transit/HubIncognitoTabSwitcherStation.java",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/BlankCTATabInitialStatePublicTransitRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/BlankCTATabInitialStatePublicTransitRule.java
new file mode 100644
index 0000000..d216ca9f
--- /dev/null
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/BlankCTATabInitialStatePublicTransitRule.java
@@ -0,0 +1,59 @@
+// 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.test.transit;
+
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import org.chromium.base.test.transit.BatchedPublicTransitRule;
+import org.chromium.base.test.transit.Trip;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule;
+
+/** Wraps BlankCTATabInitialStateRule to be used in Public Transit batched tests. */
+public class BlankCTATabInitialStatePublicTransitRule implements TestRule {
+
+    private final ChromeTabbedActivityTestRule mActivityTestRule;
+
+    public final BatchedPublicTransitRule<PageStation> mBatchedRule;
+
+    public final BlankCTATabInitialStateRule mInitialStateRule;
+    private final RuleChain mChain;
+
+    public BlankCTATabInitialStatePublicTransitRule(ChromeTabbedActivityTestRule activityTestRule) {
+        mActivityTestRule = activityTestRule;
+        mBatchedRule =
+                new BatchedPublicTransitRule<>(PageStation.class, /* expectResetByTest= */ false);
+        mInitialStateRule = new BlankCTATabInitialStateRule(mActivityTestRule, true);
+        mChain = RuleChain.outerRule(mBatchedRule).around(mInitialStateRule);
+    }
+
+    @Override
+    public Statement apply(Statement statement, Description description) {
+        return mChain.apply(statement, description);
+    }
+
+    /**
+     * Start the batched test in a blank page.
+     *
+     * <p>From the second test onwards, state was reset by {@link BlankCTATabInitialStateRule}.
+     */
+    public PageStation startOnBlankPageBatched() {
+        PageStation entryPageStation =
+                PageStation.newPageStationBuilder()
+                        .withActivityTestRule(mActivityTestRule)
+                        .withIsOpeningTab(false)
+                        .withIsSelectingTab(false)
+                        .build();
+
+        // Null in the first test, non-null from the second test onwards.
+        PageStation homeStation = mBatchedRule.getHomeStation();
+
+        // Wait for the Conditions to be met to return an active PageStation.
+        return Trip.travelSync(/* origin= */ homeStation, entryPageStation, /* trigger= */ null);
+    }
+}
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc
index 4ad8c020..6f7c2db 100644
--- a/chrome/test/base/testing_browser_process.cc
+++ b/chrome/test/base/testing_browser_process.cc
@@ -43,12 +43,13 @@
 #include "extensions/buildflags/buildflags.h"
 #include "media/media_buildflags.h"
 #include "printing/buildflags/buildflags.h"
+#include "services/device/public/cpp/geolocation/buildflags.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/test/test_network_connection_tracker.h"
 #include "services/network/test/test_network_quality_tracker.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 #include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
 #include "services/device/public/cpp/test/fake_geolocation_system_permission_manager.h"
 #endif
@@ -109,14 +110,14 @@
   g_browser_process = process;
   process->Init();
 
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
   auto fake_geolocation_system_permission_manager =
       std::make_unique<device::FakeGeolocationSystemPermissionManager>();
   fake_geolocation_system_permission_manager->SetSystemPermission(
       device::LocationSystemPermissionStatus::kAllowed);
   device::GeolocationSystemPermissionManager::SetInstance(
       std::move(fake_geolocation_system_permission_manager));
-#endif
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 }
 
 // static
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 4fd73d1..8750a5a 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -111,6 +111,7 @@
       "chromeos/parent_access/parent_access_browsertest.cc",
       "chromeos/personalization_app/personalization_app_browsertest.cc",
       "chromeos/personalization_app/personalization_app_sea_pen_browsertest.cc",
+      "chromeos/print_management/print_management_browsertest.cc",
       "chromeos/print_preview_cros/print_preview_cros_browsertest.cc",
       "chromeos/scanning/scanning_app_browsertest.cc",
       "chromeos/shimless_rma/shimless_rma_browsertest.cc",
diff --git a/chrome/test/data/webui/chromeos/BUILD.gn b/chrome/test/data/webui/chromeos/BUILD.gn
index d1e096f..7d84fbd77 100644
--- a/chrome/test/data/webui/chromeos/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/BUILD.gn
@@ -96,7 +96,6 @@
       "../nearby_share/shared/nearby_shared_v3_browsertest.js",
       "diagnostics/diagnostics_browsertest.js",
       "manage_mirrorsync/manage_mirrorsync_browsertest.js",
-      "print_management/print_management_browsertest.js",
     ]
     defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
   }
diff --git a/chrome/test/data/webui/chromeos/print_management/print_management_browsertest.cc b/chrome/test/data/webui/chromeos/print_management/print_management_browsertest.cc
new file mode 100644
index 0000000..eedabba
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/print_management/print_management_browsertest.cc
@@ -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.
+
+#include <string>
+
+#include "ash/webui/print_management/url_constants.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/test/base/web_ui_mocha_browser_test.h"
+#include "content/public/test/browser_test.h"
+
+/**
+ * @fileoverview Test suite for chrome://print-management.
+ */
+
+namespace ash {
+
+namespace {
+
+class PrintManagementBrowserTest : public WebUIMochaBrowserTest {
+ public:
+  PrintManagementBrowserTest() {
+    set_test_loader_host(::ash::kChromeUIPrintManagementHost);
+  }
+
+ protected:
+  void RunTestAtPath(const std::string& testFilePath) {
+    auto testPath = base::StringPrintf("chromeos/print_management/%s",
+                                       testFilePath.c_str());
+    WebUIMochaBrowserTest::RunTest(testPath, "mocha.run()");
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(PrintManagementBrowserTest, PrintManagementTest) {
+  RunTestAtPath("print_management_test.js");
+}
+
+}  // namespace
+
+}  // namespace ash
diff --git a/chrome/test/data/webui/chromeos/print_management/print_management_browsertest.js b/chrome/test/data/webui/chromeos/print_management/print_management_browsertest.js
deleted file mode 100644
index c20641b..0000000
--- a/chrome/test/data/webui/chromeos/print_management/print_management_browsertest.js
+++ /dev/null
@@ -1,23 +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.
-
-/**
- * @fileoverview Test suite for chrome://print-management.
- */
-
-GEN_INCLUDE(['//chrome/test/data/webui/chromeos/polymer_browser_test_base.js']);
-
-GEN('#include "content/public/test/browser_test.h"');
-
-var PrintManagementBrowserTest = class extends PolymerTest {
-  get browsePreload() {
-    return 'chrome://print-management/test_loader.html' +
-        '?module=chromeos/print_management/' +
-        'print_management_test.js';
-  }
-};
-
-TEST_F('PrintManagementBrowserTest', 'All', function() {
-  mocha.run();
-});
diff --git a/chrome/test/data/webui/chromeos/print_preview_cros/print_ticket_manager_test.ts b/chrome/test/data/webui/chromeos/print_preview_cros/print_ticket_manager_test.ts
index fcc8f88..8be8e249 100644
--- a/chrome/test/data/webui/chromeos/print_preview_cros/print_ticket_manager_test.ts
+++ b/chrome/test/data/webui/chromeos/print_preview_cros/print_ticket_manager_test.ts
@@ -7,7 +7,8 @@
 import {PRINT_REQUEST_FINISHED_EVENT, PRINT_REQUEST_STARTED_EVENT, PRINT_TICKET_MANAGER_SESSION_INITIALIZED, PrintTicketManager} from 'chrome://os-print/js/data/print_ticket_manager.js';
 import {FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL, FakePrintPreviewPageHandler} from 'chrome://os-print/js/fakes/fake_print_preview_page_handler.js';
 import {setPrintPreviewPageHandlerForTesting} from 'chrome://os-print/js/utils/mojo_data_providers.js';
-import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js';
+import {PrintTicket} from 'chrome://os-print/js/utils/print_preview_cros_app_types.js';
+import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js';
 import {MockTimer} from 'chrome://webui-test/mock_timer.js';
 import {eventToPromise} from 'chrome://webui-test/test_util.js';
 
@@ -46,12 +47,13 @@
   test('sendPrintRequest calls PrintPreviewPageHandler.print', () => {
     const instance = PrintTicketManager.getInstance();
     assertEquals(0, printPreviewPageHandler.getCallCount('print'));
+    instance.initializeSession(FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL);
     instance.sendPrintRequest();
     assertEquals(1, printPreviewPageHandler.getCallCount('print'));
   });
 
   // Verify PrintPreviewPageHandler called when cancelPrintRequest triggered.
-  test('sendPrintRequest calls PrintPreviewPageHandler.print', () => {
+  test('sendPrintRequest calls PrintPreviewPageHandler.cancel', () => {
     const instance = PrintTicketManager.getInstance();
     const method = 'cancel';
     assertEquals(0, printPreviewPageHandler.getCallCount(method));
@@ -69,6 +71,7 @@
         const delay = 1;
         printPreviewPageHandler.setTestDelay(delay);
         const instance = PrintTicketManager.getInstance();
+        instance.initializeSession(FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL);
         let startCount = 0;
         instance.addEventListener(PRINT_REQUEST_STARTED_EVENT, () => {
           ++startCount;
@@ -112,6 +115,7 @@
             eventToPromise(PRINT_REQUEST_STARTED_EVENT, instance);
         const finishEvent =
             eventToPromise(PRINT_REQUEST_FINISHED_EVENT, instance);
+        instance.initializeSession(FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL);
 
         assertFalse(instance.isPrintRequestInProgress(), 'Request not started');
 
@@ -133,9 +137,9 @@
     const delay = 1;
     printPreviewPageHandler.setTestDelay(delay);
     const instance = PrintTicketManager.getInstance();
+    instance.initializeSession(FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL);
     const startEvent = eventToPromise(PRINT_REQUEST_STARTED_EVENT, instance);
     const finishEvent = eventToPromise(PRINT_REQUEST_FINISHED_EVENT, instance);
-
     const method = 'print';
     let expectedCallCount = 0;
     assertEquals(
@@ -194,4 +198,47 @@
             instance.isSessionInitialized(),
             'After initializeSession, instance should be initialized');
       });
+
+  // Verify print ticket created when session initialized using SessionContext.
+  test(
+      'initializeSession creates print ticket based on session context',
+      () => {
+        const instance = PrintTicketManager.getInstance();
+        let expectedTicket: PrintTicket|null = null;
+        assertEquals(expectedTicket, instance.getPrintTicketForTesting());
+
+        instance.initializeSession(FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL);
+
+        expectedTicket = {
+          printPreviewId: FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL.printPreviewId,
+        } as PrintTicket;
+        assertDeepEquals(expectedTicket, instance.getPrintTicketForTesting());
+      });
+
+  // Verify `sendPrintRequest` requires a valid print ticket.
+  test(
+      'sendPrintRequest returns early if the print ticket is not valid', () => {
+        const delay = 1;
+        printPreviewPageHandler.setTestDelay(delay);
+        const instance = PrintTicketManager.getInstance();
+        assertEquals(null, instance.getPrintTicketForTesting());
+
+        // Attempt sending while ticket is null to verify print is not called.
+        instance.sendPrintRequest();
+
+        let expectedPrintCallCount = 0;
+        assertEquals(
+            expectedPrintCallCount,
+            printPreviewPageHandler.getCallCount('print'));
+
+        // Initialize session will setup the print ticket.
+        instance.initializeSession(FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL);
+        instance.sendPrintRequest();
+        ++expectedPrintCallCount;
+
+        assertEquals(
+            expectedPrintCallCount,
+            printPreviewPageHandler.getCallCount('print'),
+            'Print request can be sent');
+      });
 });
diff --git a/chrome/test/data/webui/chromeos/print_preview_cros/summary_panel_test.ts b/chrome/test/data/webui/chromeos/print_preview_cros/summary_panel_test.ts
index 343aab5..7ea573a 100644
--- a/chrome/test/data/webui/chromeos/print_preview_cros/summary_panel_test.ts
+++ b/chrome/test/data/webui/chromeos/print_preview_cros/summary_panel_test.ts
@@ -5,7 +5,7 @@
 import 'chrome://os-print/js/summary_panel.js';
 
 import {PrintTicketManager} from 'chrome://os-print/js/data/print_ticket_manager.js';
-import {FakePrintPreviewPageHandler} from 'chrome://os-print/js/fakes/fake_print_preview_page_handler.js';
+import {FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL, FakePrintPreviewPageHandler} from 'chrome://os-print/js/fakes/fake_print_preview_page_handler.js';
 import {SummaryPanelElement} from 'chrome://os-print/js/summary_panel.js';
 import {PRINT_BUTTON_DISABLED_CHANGED_EVENT, SHEETS_USED_CHANGED_EVENT, SummaryPanelController} from 'chrome://os-print/js/summary_panel_controller.js';
 import {setPrintPreviewPageHandlerForTesting} from 'chrome://os-print/js/utils/mojo_data_providers.js';
@@ -179,10 +179,11 @@
     assertFalse(
         printButton.disabled, 'Print should be enabled before request sent');
 
+    const printTicketManger = PrintTicketManager.getInstance();
+    printTicketManger.initializeSession(FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL);
     printButton.click();
     await printDisabledEvent1;
 
-    const printTicketManger = PrintTicketManager.getInstance();
     assertTrue(
         printTicketManger.isPrintRequestInProgress(),
         'Print request in progress');
diff --git a/chrome/test/data/webui/cr_components/history_embeddings/history_embeddings_test.ts b/chrome/test/data/webui/cr_components/history_embeddings/history_embeddings_test.ts
index 9613127..3befe4f1 100644
--- a/chrome/test/data/webui/cr_components/history_embeddings/history_embeddings_test.ts
+++ b/chrome/test/data/webui/cr_components/history_embeddings/history_embeddings_test.ts
@@ -10,7 +10,7 @@
 import {PageHandlerRemote} from 'chrome://resources/cr_components/history_embeddings/history_embeddings.mojom-webui.js';
 import type {SearchResultItem} from 'chrome://resources/cr_components/history_embeddings/history_embeddings.mojom-webui.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
-import {assertEquals} from 'chrome://webui-test/chai_assert.js';
+import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
 import {TestMock} from 'chrome://webui-test/test_mock.js';
 import {eventToPromise} from 'chrome://webui-test/test_util.js';
@@ -26,6 +26,7 @@
       urlForDisplay: 'google.com',
       relativeTime: '2 hours ago',
       sourcePassage: 'Google description',
+      lastUrlVisitTimestamp: 1000,
     },
     {
       title: 'Youtube',
@@ -33,6 +34,7 @@
       urlForDisplay: 'youtube.com',
       relativeTime: '4 hours ago',
       sourcePassage: 'Youtube description',
+      lastUrlVisitTimestamp: 2000,
     },
   ];
 
@@ -43,7 +45,7 @@
     HistoryEmbeddingsBrowserProxyImpl.setInstance(
         new HistoryEmbeddingsBrowserProxyImpl(handler));
     handler.setResultFor(
-        'search', Promise.resolve({result: {items: mockResults}}));
+        'search', Promise.resolve({result: {items: [...mockResults]}}));
 
     element = document.createElement('cr-history-embeddings');
     document.body.appendChild(element);
@@ -93,10 +95,65 @@
     const moreActionsIconButtons =
         element.shadowRoot!.querySelectorAll<HTMLElement>(
             'cr-url-list-item cr-icon-button');
-    const moreActionsClickEventPromise =
-        eventToPromise('more-actions-click', element);
     moreActionsIconButtons[0]!.click();
-    const moreActionsClickEvent = await moreActionsClickEventPromise;
-    assertEquals(mockResults[0], moreActionsClickEvent.detail);
+    await flushTasks();
+
+    // Clicking on the more actions button for the first item should load
+    // the cr-action-menu and open it.
+    const moreActionsMenu = element.shadowRoot!.querySelector('cr-action-menu');
+    assertTrue(!!moreActionsMenu);
+    assertTrue(moreActionsMenu.open);
+
+    const actionMenuItems = moreActionsMenu.querySelectorAll('button');
+    assertEquals(2, actionMenuItems.length);
+
+    // Clicking on the first button should fire the 'more-from-site-click' event
+    // with the first item's model, and then close the menu.
+    const moreFromSiteEventPromise =
+        eventToPromise('more-from-site-click', element);
+    const moreFromSiteItem =
+        moreActionsMenu.querySelector<HTMLElement>('#moreFromSiteOption')!;
+    moreFromSiteItem.click();
+    const moreFromSiteEvent = await moreFromSiteEventPromise;
+    assertEquals(mockResults[0], moreFromSiteEvent.detail);
+    assertFalse(moreActionsMenu.open);
+
+    // Clicking on the second button should fire the 'remove-item-click' event
+    // with the second item's model, and then close the menu.
+    moreActionsIconButtons[1]!.click();
+    assertTrue(moreActionsMenu.open);
+    const removeItemEventPromise = eventToPromise('remove-item-click', element);
+    const removeItemItem =
+        moreActionsMenu.querySelector<HTMLElement>('#removeFromHistoryOption')!;
+    removeItemItem.click();
+    const removeItemEvent = await removeItemEventPromise;
+    assertEquals(mockResults[1], removeItemEvent.detail);
+    assertFalse(moreActionsMenu.open);
+  });
+
+  test('RemovesItemsFromFrontend', async () => {
+    const moreActionsIconButtons =
+        element.shadowRoot!.querySelectorAll<HTMLElement>(
+            'cr-url-list-item cr-icon-button');
+
+    // Open the 'more actions' menu for the first result and remove it.
+    moreActionsIconButtons[0]!.click();
+    element.shadowRoot!.querySelector<HTMLElement>(
+                           '#removeFromHistoryOption')!.click();
+    await flushTasks();
+
+    // There is still 1 result left so it should still be visible.
+    assertFalse(element.hidden);
+    assertEquals(
+        1, element.shadowRoot!.querySelectorAll('cr-url-list-item').length);
+
+    // Open the 'more actions' menu for the last result and remove it.
+    moreActionsIconButtons[0]!.click();
+    element.shadowRoot!.querySelector<HTMLElement>(
+                           '#removeFromHistoryOption')!.click();
+    await flushTasks();
+
+    // No results left.
+    assertTrue(element.hidden);
   });
 });
diff --git a/chrome/test/data/webui/cr_elements/BUILD.gn b/chrome/test/data/webui/cr_elements/BUILD.gn
index 57375d0..5cf9e3a 100644
--- a/chrome/test/data/webui/cr_elements/BUILD.gn
+++ b/chrome/test/data/webui/cr_elements/BUILD.gn
@@ -26,6 +26,7 @@
     "cr_grid_focus_test.ts",
     "cr_icon_button_test.ts",
     "cr_icon_test.ts",
+    "cr_iconset_test.ts",
     "cr_input_test.ts",
     "cr_lazy_render_test.ts",
     "cr_link_row_test.ts",
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_browsertest.cc b/chrome/test/data/webui/cr_elements/cr_elements_browsertest.cc
index f36f24e..3633aea0 100644
--- a/chrome/test/data/webui/cr_elements/cr_elements_browsertest.cc
+++ b/chrome/test/data/webui/cr_elements/cr_elements_browsertest.cc
@@ -53,6 +53,10 @@
   RunTest("cr_elements/cr_icon_test.js", "mocha.run()");
 }
 
+IN_PROC_BROWSER_TEST_F(CrElementsTest, CrIconset) {
+  RunTest("cr_elements/cr_iconset_test.js", "mocha.run()");
+}
+
 IN_PROC_BROWSER_TEST_F(CrElementsTest, FindShortcutMixin) {
   RunTest("cr_elements/find_shortcut_mixin_test.js", "mocha.run()");
 }
diff --git a/chrome/test/data/webui/cr_elements/cr_icon_test.ts b/chrome/test/data/webui/cr_elements/cr_icon_test.ts
index 44d2e605..6c736049 100644
--- a/chrome/test/data/webui/cr_elements/cr_icon_test.ts
+++ b/chrome/test/data/webui/cr_elements/cr_icon_test.ts
@@ -5,8 +5,10 @@
 // clang-format off
 import '//resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js';
 import {html} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {html as litHtml, render} from 'chrome://resources/lit/v3_0/lit.rollup.js';
 
 import 'chrome://resources/cr_elements/cr_icon/cr_icon.js';
+import 'chrome://resources/cr_elements/cr_icon/cr_iconset.js';
 import 'chrome://resources/cr_elements/icons.html.js';
 
 import type {CrIconElement} from 'chrome://resources/cr_elements/cr_icon/cr_icon.js';
@@ -18,6 +20,25 @@
 suite('cr-icon', function() {
   let icon: CrIconElement;
 
+  suiteSetup(function() {
+    // Add a test cr-iconset to the page. Necessary since there are not yet
+    // any cr-iconsets in prod that can be imported instead.
+    const iconsetHtml = litHtml`
+      <cr-iconset name="cr-test" size="24">
+        <svg>
+          <defs>
+            <g id="arrow-drop-up">
+              <path d="M7 14l5-5 5 5z"></path>
+            </g>
+            <g id="arrow-drop-down">
+              <path d="M7 10l5 5 5-5z"></path>
+            </g>
+          </defs>
+        </svg>
+      </cr-iconset>`;
+    render(iconsetHtml, document.head);
+  });
+
   setup(async () => {
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
     icon = document.createElement('cr-icon');
@@ -70,4 +91,39 @@
     svg = icon.shadowRoot!.querySelector('svg');
     assertTrue(!!svg);
   });
+
+  test('cr-iconset', async () => {
+    icon.icon = 'cr-test:arrow-drop-up';
+    await microtasksFinished();
+    let svgs = icon.shadowRoot!.querySelectorAll('svg');
+    assertEquals(1, svgs.length);
+    assertSvgPath(svgs[0]!, 'M7 14l5-5 5 5z');
+
+    icon.icon = 'cr-test:arrow-drop-down';
+    await microtasksFinished();
+    svgs = icon.shadowRoot!.querySelectorAll('svg');
+    assertEquals(1, svgs.length);
+    assertSvgPath(svgs[0]!, 'M7 10l5 5 5-5z');
+  });
+
+  test('cr-iconset added later', async () => {
+    icon.icon = 'cr-test-late:print';
+    await microtasksFinished();
+    let svg = icon.shadowRoot!.querySelector('svg');
+    assertFalse(!!svg);
+
+    const iconsetHtml = litHtml`
+      <cr-iconset name="cr-test-late" size="24">
+        <svg>
+          <defs>
+            <g id="print"><path d="M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z"></path></g>
+          </defs>
+        </svg>
+      </cr-iconset>`;
+    render(iconsetHtml, document.head);
+
+    await microtasksFinished();
+    svg = icon.shadowRoot!.querySelector('svg');
+    assertTrue(!!svg);
+  });
 });
diff --git a/chrome/test/data/webui/cr_elements/cr_iconset_test.ts b/chrome/test/data/webui/cr_elements/cr_iconset_test.ts
new file mode 100644
index 0000000..08798d1
--- /dev/null
+++ b/chrome/test/data/webui/cr_elements/cr_iconset_test.ts
@@ -0,0 +1,103 @@
+// 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.
+
+// clang-format off
+import {html, render, CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
+
+import 'chrome://resources/cr_elements/cr_icon/cr_iconset.js';
+import {IconsetMap} from 'chrome://resources/cr_elements/cr_icon/iconset_map.js';
+
+import type {CrIconsetElement} from 'chrome://resources/cr_elements/cr_icon/cr_iconset.js';
+import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {microtasksFinished} from 'chrome://webui-test/test_util.js';
+
+// clang-format on
+
+suite('cr-iconset', function() {
+  let iconset: CrIconsetElement;
+
+  // Super simple test element to render icons into.
+  class TestElement extends CrLitElement {
+    static get is() {
+      return 'test-element';
+    }
+  }
+
+  customElements.define(TestElement.is, TestElement);
+
+  suiteSetup(function() {
+    const iconsetHtml = html`
+      <cr-iconset name="cr-test" size="24">
+        <svg>
+          <defs>
+            <g id="arrow-drop-up">
+              <path d="M7 14l5-5 5 5z"></path>
+            </g>
+            <g id="arrow-drop-down">
+              <path d="M7 10l5 5 5-5z"></path>
+            </g>
+          </defs>
+        </svg>
+      </cr-iconset>`;
+    render(iconsetHtml, document.head);
+  });
+
+  setup(async () => {
+    document.body.innerHTML = window.trustedTypes!.emptyHTML;
+    iconset = document.head.querySelector('cr-iconset')!;
+    await microtasksFinished();
+  });
+
+  function assertSvgPath(svg: SVGElement, expectedPath: string) {
+    const iconInternal = svg.querySelector('g');
+    assertTrue(!!iconInternal);
+    const path = iconInternal.querySelector('path');
+    assertTrue(!!path);
+    assertEquals(expectedPath, path.getAttribute('d'));
+  }
+
+  test('initial state', () => {
+    assertEquals(iconset, IconsetMap.getInstance().get('cr-test'));
+    assertEquals('none', window.getComputedStyle(iconset).display);
+    const icons = iconset.querySelectorAll('g[id]');
+    assertEquals(2, icons.length);
+    assertEquals('arrow-drop-up', icons[0]!.id);
+    assertEquals('arrow-drop-down', icons[1]!.id);
+  });
+
+  test('creates icons', () => {
+    const arrowUpIcon = iconset.createIcon('arrow-drop-up');
+    assertTrue(!!arrowUpIcon);
+    assertSvgPath(arrowUpIcon, 'M7 14l5-5 5 5z');
+
+    const arrowDownIcon = iconset.createIcon('arrow-drop-down');
+    assertTrue(!!arrowDownIcon);
+    assertSvgPath(arrowDownIcon, 'M7 10l5 5 5-5z');
+
+    // Should return null for an icon not in the iconset
+    const invalidIcon = iconset.createIcon('not-in-iconset');
+    assertEquals(null, invalidIcon);
+  });
+
+  test('icon add/remove', () => {
+    const icon = document.createElement('test-element');
+    document.body.appendChild(icon);
+
+    iconset.applyIcon(icon, 'arrow-drop-up');
+    let svgs = icon.shadowRoot!.querySelectorAll('svg');
+    assertEquals(1, svgs.length);
+    assertSvgPath(svgs[0]!, 'M7 14l5-5 5 5z');
+
+    // Applying a new icon removes the old one.
+    iconset.applyIcon(icon, 'arrow-drop-down');
+    svgs = icon.shadowRoot!.querySelectorAll('svg');
+    assertEquals(1, svgs.length);
+    assertSvgPath(svgs[0]!, 'M7 10l5 5 5-5z');
+
+    // Removing the icon works.
+    iconset.removeIcon(icon);
+    svgs = icon.shadowRoot!.querySelectorAll('svg');
+    assertEquals(0, svgs.length);
+  });
+});
diff --git a/chrome/test/data/webui/history/history_app_test.ts b/chrome/test/data/webui/history/history_app_test.ts
index 4456806..a8e9b9b 100644
--- a/chrome/test/data/webui/history/history_app_test.ts
+++ b/chrome/test/data/webui/history/history_app_test.ts
@@ -8,15 +8,18 @@
 import {BrowserServiceImpl} from 'chrome://history/history.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
+import {eventToPromise} from 'chrome://webui-test/test_util.js';
 
 import {TestBrowserService} from './test_browser_service.js';
 
 suite('HistoryAppTest', function() {
   let element: HistoryAppElement;
+  let browserService: TestBrowserService;
 
   setup(() => {
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
-    BrowserServiceImpl.setInstance(new TestBrowserService());
+    browserService = new TestBrowserService();
+    BrowserServiceImpl.setInstance(browserService);
     element = document.createElement('history-app');
     document.body.appendChild(element);
     return flushTasks();
@@ -60,4 +63,54 @@
     await flushTasks();
     assertFalse(!!element.shadowRoot!.querySelector('cr-history-embeddings'));
   });
+
+  test('QueriesMoreFromSiteFromHistoryEmbeddings', async () => {
+    element.dispatchEvent(new CustomEvent(
+        'change-query',
+        {bubbles: true, composed: true, detail: {search: 'two words'}}));
+    await flushTasks();
+    const historyEmbeddings =
+        element.shadowRoot!.querySelector('cr-history-embeddings');
+    assertTrue(!!historyEmbeddings);
+
+    const changeQueryEventPromise = eventToPromise('change-query', element);
+    historyEmbeddings.dispatchEvent(new CustomEvent('more-from-site-click', {
+      detail: {
+        title: 'Google',
+        url: {url: 'http://google.com'},
+        urlForDisplay: 'google.com',
+        relativeTime: '2 hours ago',
+        sourcePassage: 'Google description',
+        lastUrlVisitTimestamp: 1000,
+      },
+    }));
+    const changeQueryEvent = await changeQueryEventPromise;
+    assertEquals('host:google.com', changeQueryEvent.detail.search);
+  });
+
+  test('RemovesItemFromHistoryEmbeddings', async () => {
+    element.dispatchEvent(new CustomEvent(
+        'change-query',
+        {bubbles: true, composed: true, detail: {search: 'two words'}}));
+    await flushTasks();
+    const historyEmbeddings =
+        element.shadowRoot!.querySelector('cr-history-embeddings');
+    assertTrue(!!historyEmbeddings);
+
+    historyEmbeddings.dispatchEvent(new CustomEvent('remove-item-click', {
+      detail: {
+        title: 'Google',
+        url: {url: 'http://google.com'},
+        urlForDisplay: 'google.com',
+        relativeTime: '2 hours ago',
+        sourcePassage: 'Google description',
+        lastUrlVisitTimestamp: 1000,
+      },
+    }));
+    const removeVisitsArg = await browserService.whenCalled('removeVisits');
+    assertEquals(1, removeVisitsArg.length);
+    assertEquals('http://google.com', removeVisitsArg[0].url);
+    assertEquals(1, removeVisitsArg[0].timestamps.length);
+    assertEquals(1000, removeVisitsArg[0].timestamps[0]);
+  });
 });
diff --git a/chrome/test/data/webui/new_tab_page/modules/v2/calendar/module_test.ts b/chrome/test/data/webui/new_tab_page/modules/v2/calendar/module_test.ts
index 7c520a8..c9eea30 100644
--- a/chrome/test/data/webui/new_tab_page/modules/v2/calendar/module_test.ts
+++ b/chrome/test/data/webui/new_tab_page/modules/v2/calendar/module_test.ts
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 import type {CalendarModuleElement} from 'chrome://new-tab-page/lazy_load.js';
-import {googleCalendarDescriptor} from 'chrome://new-tab-page/lazy_load.js';
-import {assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {googleCalendarDescriptor, outlookCalendarDescriptor} from 'chrome://new-tab-page/lazy_load.js';
+import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
 import {isVisible} from 'chrome://webui-test/test_util.js';
 
@@ -13,7 +13,7 @@
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
   });
 
-  test('creates module', async () => {
+  test('creates google calendar module', async () => {
     const module =
         await googleCalendarDescriptor.initialize(0) as CalendarModuleElement;
     assertTrue(!!module);
@@ -23,5 +23,19 @@
     // Assert.
     assertTrue(
         isVisible(module.shadowRoot!.querySelector('ntp-module-header-v2')));
+    assertEquals(module.shadowRoot!.querySelector('p')!.innerText, '0');
+  });
+
+  test('creates outlook calendar module', async () => {
+    const module =
+        await outlookCalendarDescriptor.initialize(0) as CalendarModuleElement;
+    assertTrue(!!module);
+    document.body.append(module);
+    await waitAfterNextRender(module);
+
+    // Assert.
+    assertTrue(
+        isVisible(module.shadowRoot!.querySelector('ntp-module-header-v2')));
+    assertEquals(module.shadowRoot!.querySelector('p')!.innerText, '1');
   });
 });
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.cc b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.cc
index f965e73..b8cd2c4 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.cc
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.cc
@@ -97,9 +97,9 @@
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-class OSSettingsMochaTestApnRevampEnabled : public OSSettingsMochaTest {
+class OSSettingsMochaTestApnRevamp : public OSSettingsRevampMochaTest {
  protected:
-  OSSettingsMochaTestApnRevampEnabled() {
+  OSSettingsMochaTestApnRevamp() {
     scoped_feature_list_.InitAndEnableFeature(ash::features::kApnRevamp);
   }
 
@@ -107,6 +107,35 @@
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
+INSTANTIATE_TEST_SUITE_P(RevampParameterized,
+                         OSSettingsMochaTestApnRevamp,
+                         testing::Bool(),
+                         OSSettingsMochaTestApnRevamp::DescribeParams);
+
+class OSSettingsCrostiniTestRevamp : public OSSettingsRevampMochaTest {
+ protected:
+  OSSettingsCrostiniTestRevamp() { fake_crostini_features_.SetAll(true); }
+
+ private:
+  crostini::FakeCrostiniFeatures fake_crostini_features_;
+};
+
+INSTANTIATE_TEST_SUITE_P(RevampParameterized,
+                         OSSettingsCrostiniTestRevamp,
+                         testing::Bool(),
+                         OSSettingsCrostiniTestRevamp::DescribeParams);
+
+class OSSettingsCrostiniTestRevampDisabled
+    : public OSSettingsMochaTestRevampDisabled {
+ protected:
+  OSSettingsCrostiniTestRevampDisabled() {
+    fake_crostini_features_.SetAll(true);
+  }
+
+ private:
+  crostini::FakeCrostiniFeatures fake_crostini_features_;
+};
+
 class OSSettingsMochaTestReducedAnimationsEnabled : public OSSettingsMochaTest {
  protected:
   OSSettingsMochaTestReducedAnimationsEnabled() {
@@ -225,113 +254,51 @@
   RunSettingsTest("controls/v2/pref_control_mixin_internal_test.js");
 }
 
-class OSSettingsCrostiniTestRevampEnabled
-    : public OSSettingsMochaTestRevampEnabled {
- protected:
-  OSSettingsCrostiniTestRevampEnabled() {
-    fake_crostini_features_.SetAll(true);
-  }
-
- private:
-  crostini::FakeCrostiniFeatures fake_crostini_features_;
-};
-
-class OSSettingsCrostiniTestRevampDisabled
-    : public OSSettingsMochaTestRevampDisabled {
- protected:
-  OSSettingsCrostiniTestRevampDisabled() {
-    fake_crostini_features_.SetAll(true);
-  }
-
- private:
-  crostini::FakeCrostiniFeatures fake_crostini_features_;
-};
-
-IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampDisabled,
+IN_PROC_BROWSER_TEST_P(OSSettingsCrostiniTestRevamp,
                        CrostiniPageBruschettaSubpage) {
   RunSettingsTest("crostini_page/bruschetta_subpage_test.js");
 }
 
-IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampEnabled,
-                       CrostiniPageBruschettaSubpageRevamp) {
-  RunSettingsTest("crostini_page/bruschetta_subpage_test.js");
-}
-
-IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampDisabled,
+IN_PROC_BROWSER_TEST_P(OSSettingsCrostiniTestRevamp,
                        CrostiniPageCrostiniArcAdb) {
   RunSettingsTest("crostini_page/crostini_arc_adb_test.js");
 }
 
-IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampEnabled,
-                       CrostiniPageCrostiniArcAdbRevamp) {
-  RunSettingsTest("crostini_page/crostini_arc_adb_test.js");
-}
-
-IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampDisabled,
+IN_PROC_BROWSER_TEST_P(OSSettingsCrostiniTestRevamp,
                        CrostiniPageCrostiniExportImport) {
   RunSettingsTest("crostini_page/crostini_export_import_test.js");
 }
 
-IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampEnabled,
-                       CrostiniPageCrostiniExportImportRevamp) {
-  RunSettingsTest("crostini_page/crostini_export_import_test.js");
-}
-
-IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampDisabled,
+IN_PROC_BROWSER_TEST_P(OSSettingsCrostiniTestRevamp,
                        CrostiniPageCrostiniExtraContainersSubpage) {
   RunSettingsTest("crostini_page/crostini_extra_containers_subpage_test.js");
 }
 
-IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampEnabled,
-                       CrostiniPageCrostiniExtraContainersSubpageRevamp) {
-  RunSettingsTest("crostini_page/crostini_extra_containers_subpage_test.js");
-}
-
 IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampDisabled, CrostiniPage) {
   RunSettingsTest("crostini_page/crostini_page_test.js");
 }
 
-IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampDisabled,
+IN_PROC_BROWSER_TEST_P(OSSettingsCrostiniTestRevamp,
                        CrostiniPageCrostiniPortForwarding) {
   RunSettingsTest("crostini_page/crostini_port_forwarding_test.js");
 }
 
-IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampEnabled,
-                       CrostiniPageCrostiniPortForwardingRevamp) {
-  RunSettingsTest("crostini_page/crostini_port_forwarding_test.js");
-}
-
-IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampDisabled,
+IN_PROC_BROWSER_TEST_P(OSSettingsCrostiniTestRevamp,
                        CrostiniPageCrostiniSettingsCard) {
   RunSettingsTest("crostini_page/crostini_settings_card_test.js");
 }
 
-IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampEnabled,
-                       AboutPageCrostiniSettingsCardRevamp) {
-  RunSettingsTest("crostini_page/crostini_settings_card_test.js");
-}
-
-IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampDisabled,
+IN_PROC_BROWSER_TEST_P(OSSettingsCrostiniTestRevamp,
                        CrostiniPageCrostiniSharedUsbDevices) {
   RunSettingsTest("crostini_page/crostini_shared_usb_devices_test.js");
 }
 
-IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampEnabled,
-                       CrostiniPageCrostiniSharedUsbDevicesRevamp) {
-  RunSettingsTest("crostini_page/crostini_shared_usb_devices_test.js");
-}
-
-IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampDisabled,
+IN_PROC_BROWSER_TEST_P(OSSettingsCrostiniTestRevamp,
                        CrostiniPageCrostiniSubpage) {
   RunSettingsTest("crostini_page/crostini_subpage_test.js");
 }
 
-IN_PROC_BROWSER_TEST_F(OSSettingsCrostiniTestRevampEnabled,
-                       CrostiniPageCrostiniSubpageRevamp) {
-  RunSettingsTest("crostini_page/crostini_subpage_test.js");
-}
-
-IN_PROC_BROWSER_TEST_F(OSSettingsMochaTest, DateTimePage) {
+IN_PROC_BROWSER_TEST_P(OSSettingsRevampMochaTest, DateTimePage) {
   RunSettingsTest("date_time_page/date_time_page_test.js");
 }
 
@@ -340,11 +307,12 @@
   RunSettingsTest("date_time_page/date_time_settings_card_test.js");
 }
 
-IN_PROC_BROWSER_TEST_F(OSSettingsMochaTest, DateTimePageTimezoneSelector) {
+IN_PROC_BROWSER_TEST_P(OSSettingsRevampMochaTest,
+                       DateTimePageTimezoneSelector) {
   RunSettingsTest("date_time_page/timezone_selector_test.js");
 }
 
-IN_PROC_BROWSER_TEST_F(OSSettingsMochaTest, DateTimePageTimezoneSubpage) {
+IN_PROC_BROWSER_TEST_P(OSSettingsRevampMochaTest, DateTimePageTimezoneSubpage) {
   RunSettingsTest("date_time_page/timezone_subpage_test.js");
 }
 
@@ -699,8 +667,7 @@
   RunSettingsTest("device_page/stylus_test.js");
 }
 
-IN_PROC_BROWSER_TEST_F(OSSettingsMochaTestApnRevampEnabled,
-                       InternetPageApnSubpage) {
+IN_PROC_BROWSER_TEST_P(OSSettingsMochaTestApnRevamp, InternetPageApnSubpage) {
   RunSettingsTest("internet_page/apn_subpage_test.js");
 }
 
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/BUILD.gn b/chrome/test/data/webui/side_panel/customize_chrome/BUILD.gn
index 8900f94..ef005a3 100644
--- a/chrome/test/data/webui/side_panel/customize_chrome/BUILD.gn
+++ b/chrome/test/data/webui/side_panel/customize_chrome/BUILD.gn
@@ -12,7 +12,6 @@
     "cards_test.ts",
     "categories_test.ts",
     "check_mark_wrapper_test.ts",
-    "chrome_colors_test.ts",
     "wallpaper_search/combobox_test.ts",
     "hover_button_test.ts",
     "shortcuts_test.ts",
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/app_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/app_test.ts
index c9bb1d0..2c74da1a 100644
--- a/chrome/test/data/webui/side_panel/customize_chrome/app_test.ts
+++ b/chrome/test/data/webui/side_panel/customize_chrome/app_test.ts
@@ -83,22 +83,6 @@
         new Event('edit-theme-click'));
     assertEquals(customizeChromeApp, document.activeElement);
 
-    // Send event for chrome colors select.
-    customizeChromeApp.$.categoriesPage.dispatchEvent(
-        new Event('chrome-colors-select'));
-    // Current page should now be chrome colors.
-    assertTrue(customizeChromeApp.$.chromeColorsPage.classList.contains(
-        'iron-selected'));
-    assertEquals(customizeChromeApp, document.activeElement);
-
-    // Send event for back click.
-    customizeChromeApp.$.chromeColorsPage.dispatchEvent(
-        new Event('back-click'));
-    // Current page should now be categories.
-    assertTrue(customizeChromeApp.$.categoriesPage.classList.contains(
-        'iron-selected'));
-    assertEquals(customizeChromeApp, document.activeElement);
-
     // Send event for back click.
     customizeChromeApp.$.categoriesPage.dispatchEvent(new Event('back-click'));
     // Current page should now be overview.
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/appearance_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/appearance_test.ts
index dbc43eb..3697f728 100644
--- a/chrome/test/data/webui/side_panel/customize_chrome/appearance_test.ts
+++ b/chrome/test/data/webui/side_panel/customize_chrome/appearance_test.ts
@@ -271,72 +271,60 @@
     });
   });
 
-  suite('GM3', async () => {
-    suiteSetup(() => {
-      document.documentElement.toggleAttribute('chrome-refresh-2023', true);
-    });
+  test('uploaded image shows button and no snapshot', async () => {
+    const theme = createTheme();
+    theme.backgroundImage = createBackgroundImage('local');
+    theme.backgroundImage.isUploadedImage = true;
 
-    test('uploaded image shows button and no snapshot', async () => {
-      const theme = createTheme();
-      theme.backgroundImage = createBackgroundImage('local');
-      theme.backgroundImage.isUploadedImage = true;
+    callbackRouterRemote.setTheme(theme);
+    await callbackRouterRemote.$.flushForTesting();
 
-      callbackRouterRemote.setTheme(theme);
-      await callbackRouterRemote.$.flushForTesting();
+    assertStyle(appearanceElement.$.thirdPartyLinkButton, 'display', 'none');
+    assertNotStyle(appearanceElement.$.uploadedImageButton, 'display', 'none');
+    assertStyle(appearanceElement.$.searchedImageButton, 'display', 'none');
+    assertNotStyle(
+        appearanceElement.$.setClassicChromeButton, 'display', 'none');
+    assertStyle(appearanceElement.$.themeSnapshot, 'display', 'none');
+    assertNotStyle(appearanceElement.$.chromeColors, 'display', 'none');
+  });
 
-      assertStyle(appearanceElement.$.thirdPartyLinkButton, 'display', 'none');
-      assertNotStyle(
-          appearanceElement.$.uploadedImageButton, 'display', 'none');
-      assertStyle(appearanceElement.$.searchedImageButton, 'display', 'none');
-      assertNotStyle(
-          appearanceElement.$.setClassicChromeButton, 'display', 'none');
-      assertStyle(appearanceElement.$.themeSnapshot, 'display', 'none');
-      assertNotStyle(appearanceElement.$.chromeColors, 'display', 'none');
-    });
+  test('uploadedImageButton opens upload image dialog', async () => {
+    const theme = createTheme();
+    theme.backgroundImage = createBackgroundImage('local');
+    theme.backgroundImage.isUploadedImage = true;
 
-    test('uploadedImageButton opens upload image dialog', async () => {
-      const theme = createTheme();
-      theme.backgroundImage = createBackgroundImage('local');
-      theme.backgroundImage.isUploadedImage = true;
+    callbackRouterRemote.setTheme(theme);
+    await callbackRouterRemote.$.flushForTesting();
 
-      callbackRouterRemote.setTheme(theme);
-      await callbackRouterRemote.$.flushForTesting();
+    assertNotStyle(appearanceElement.$.uploadedImageButton, 'display', 'none');
+    appearanceElement.$.uploadedImageButton.click();
+    assertEquals(1, handler.getCallCount('chooseLocalCustomBackground'));
+  });
 
-      assertNotStyle(
-          appearanceElement.$.uploadedImageButton, 'display', 'none');
-      appearanceElement.$.uploadedImageButton.click();
-      assertEquals(1, handler.getCallCount('chooseLocalCustomBackground'));
-    });
+  test('searched image shows button', async () => {
+    const theme = createTheme();
+    theme.backgroundImage = createBackgroundImage('searched');
+    theme.backgroundImage.isUploadedImage = true;
+    theme.backgroundImage.localBackgroundId = {
+      low: BigInt(10),
+      high: BigInt(20),
+    };
+    callbackRouterRemote.setTheme(theme);
+    await callbackRouterRemote.$.flushForTesting();
 
-    test('searched image shows button', async () => {
-      const theme = createTheme();
-      theme.backgroundImage = createBackgroundImage('searched');
-      theme.backgroundImage.isUploadedImage = true;
-      theme.backgroundImage.localBackgroundId = {
-        low: BigInt(10),
-        high: BigInt(20),
-      };
-      callbackRouterRemote.setTheme(theme);
-      await callbackRouterRemote.$.flushForTesting();
+    assertStyle(appearanceElement.$.thirdPartyLinkButton, 'display', 'none');
+    assertStyle(appearanceElement.$.uploadedImageButton, 'display', 'none');
+    assertNotStyle(appearanceElement.$.searchedImageButton, 'display', 'none');
+    assertNotStyle(
+        appearanceElement.$.setClassicChromeButton, 'display', 'none');
+    assertStyle(appearanceElement.$.themeSnapshot, 'display', 'none');
+    assertNotStyle(appearanceElement.$.chromeColors, 'display', 'none');
+  });
 
-      assertStyle(appearanceElement.$.thirdPartyLinkButton, 'display', 'none');
-      assertStyle(appearanceElement.$.uploadedImageButton, 'display', 'none');
-      assertNotStyle(
-          appearanceElement.$.searchedImageButton, 'display', 'none');
-      assertNotStyle(
-          appearanceElement.$.setClassicChromeButton, 'display', 'none');
-      assertStyle(appearanceElement.$.themeSnapshot, 'display', 'none');
-      assertNotStyle(appearanceElement.$.chromeColors, 'display', 'none');
-    });
-
-    test(
-        'searched image button opens themes when feature disabled',
-        async () => {
-          const clickEvent =
-              eventToPromise('edit-theme-click', appearanceElement);
-          appearanceElement.$.searchedImageButton.click();
-          await clickEvent;
-        });
+  test('searched image button opens themes when feature disabled', async () => {
+    const clickEvent = eventToPromise('edit-theme-click', appearanceElement);
+    appearanceElement.$.searchedImageButton.click();
+    await clickEvent;
   });
 
   suite('WallpaperSearch', async () => {
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/categories_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/categories_test.ts
index f63c3ea3..c7488fd 100644
--- a/chrome/test/data/webui/side_panel/customize_chrome/categories_test.ts
+++ b/chrome/test/data/webui/side_panel/customize_chrome/categories_test.ts
@@ -152,20 +152,6 @@
     assertEquals(1, handler.getCallCount('openChromeWebStore'));
   });
 
-  test('clicking chrome colors sends event', async () => {
-    document.documentElement.toggleAttribute('chrome-refresh-2023', false);
-    await setInitialSettings(1);
-    const eventPromise =
-        eventToPromise('chrome-colors-select', categoriesElement);
-    const chromeColorsTile =
-        categoriesElement.shadowRoot!.querySelector('#chromeColorsTile');
-    assertTrue(!!chromeColorsTile);
-
-    (chromeColorsTile as HTMLElement).click();
-    const event = await eventPromise;
-    assertTrue(!!event);
-  });
-
   test('checks selected category', async () => {
     await setInitialSettings(2);
 
@@ -184,21 +170,6 @@
         checkedCategories[0]!.parentElement!.getAttribute('aria-current'),
         'true');
 
-    // Set a theme with a color.
-    theme.foregroundColor = {value: 0xffff0000};
-    callbackRouterRemote.setTheme(theme);
-    await callbackRouterRemote.$.flushForTesting();
-    await waitAfterNextRender(categoriesElement);
-
-    // Check that chrome colors is selected.
-    checkedCategories =
-        categoriesElement.shadowRoot!.querySelectorAll('[checked]');
-    assertEquals(1, checkedCategories.length);
-    assertEquals(checkedCategories[0]!.parentElement!.id, 'chromeColorsTile');
-    assertEquals(
-        checkedCategories[0]!.parentElement!.getAttribute('aria-current'),
-        'true');
-
     // Set a theme with local background.
     const backgroundImage = createBackgroundImage('https://test.jpg');
     backgroundImage.isUploadedImage = true;
@@ -260,22 +231,7 @@
     );
   });
 
-  test('non-gm3 classic chrome tile shows correct image', async () => {
-    document.documentElement.toggleAttribute('chrome-refresh-2023', false);
-
-    await setInitialSettings(0);
-
-    assertEquals(
-        $$<HTMLImageElement>(
-            categoriesElement,
-            '#classicChromeTile #cornerNewTabPageTile #cornerNewTabPage')!.src,
-        'chrome://customize-chrome-side-panel.top-chrome/icons/' +
-            'corner_new_tab_page.svg');
-  });
-
-  test('gm3 classic chrome tile shows correct image', async () => {
-    document.documentElement.toggleAttribute('chrome-refresh-2023', true);
-
+  test('classic chrome tile shows correct image', async () => {
     await setInitialSettings(0);
 
     assertEquals(
@@ -286,15 +242,6 @@
             'gm3_corner_new_tab_page.svg');
   });
 
-  test('Hide chrome colors collection when GM3', async () => {
-    document.documentElement.toggleAttribute('chrome-refresh-2023', true);
-
-    await setInitialSettings(0);
-
-    assertTrue(
-        !categoriesElement.shadowRoot!.querySelector('#chromeColorsTile'));
-  });
-
   [true, false].forEach((flagEnabled) => {
     suite(`WallpaperSearchEnabled_${flagEnabled}`, () => {
       suiteSetup(() => {
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/chrome_colors_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/chrome_colors_test.ts
deleted file mode 100644
index 9a655dc9..0000000
--- a/chrome/test/data/webui/side_panel/customize_chrome/chrome_colors_test.ts
+++ /dev/null
@@ -1,249 +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.
-
-import 'chrome://customize-chrome-side-panel.top-chrome/chrome_colors.js';
-
-import type {ChromeColorsElement} from 'chrome://customize-chrome-side-panel.top-chrome/chrome_colors.js';
-import {CustomizeChromeAction} from 'chrome://customize-chrome-side-panel.top-chrome/common.js';
-import {ThemeColorPickerBrowserProxy} from 'chrome://resources/cr_components/theme_color_picker/browser_proxy.js';
-import type {ThemeColorElement} from 'chrome://resources/cr_components/theme_color_picker/theme_color.js';
-import type {ChromeColor, Theme, ThemeColorPickerClientRemote} from 'chrome://resources/cr_components/theme_color_picker/theme_color_picker.mojom-webui.js';
-import {ThemeColorPickerClientCallbackRouter, ThemeColorPickerHandlerRemote} from 'chrome://resources/cr_components/theme_color_picker/theme_color_picker.mojom-webui.js';
-import {BrowserColorVariant} from 'chrome://resources/mojo/ui/base/mojom/themes.mojom-webui.js';
-import {assertDeepEquals, assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
-import type {MetricsTracker} from 'chrome://webui-test/metrics_test_support.js';
-import {fakeMetricsPrivate} from 'chrome://webui-test/metrics_test_support.js';
-import {waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
-import type {TestMock} from 'chrome://webui-test/test_mock.js';
-import {eventToPromise} from 'chrome://webui-test/test_util.js';
-
-import {installMock} from './test_support.js';
-
-function createTheme(): Theme {
-  return {
-    hasBackgroundImage: false,
-    hasThirdPartyTheme: false,
-    backgroundImageMainColor: null,
-    isDarkMode: false,
-    seedColor: {value: 0xff0000ff},
-    seedColorHue: 0,
-    backgroundColor: {value: 0xffff0000},
-    foregroundColor: null,
-    colorPickerIconColor: {value: 0xffff0000},
-    colorsManagedByPolicy: false,
-    isGreyBaseline: false,
-    browserColorVariant: BrowserColorVariant.kTonalSpot,
-    followDeviceTheme: false,
-  };
-}
-
-suite('ChromeColorsTest', () => {
-  let chromeColorsElement: ChromeColorsElement;
-  let handler: TestMock<ThemeColorPickerHandlerRemote>;
-  let callbackRouter: ThemeColorPickerClientRemote;
-  let metrics: MetricsTracker;
-
-  setup(async () => {
-    document.body.innerHTML = window.trustedTypes!.emptyHTML;
-    handler = installMock(
-        ThemeColorPickerHandlerRemote,
-        (mock: ThemeColorPickerHandlerRemote) =>
-            ThemeColorPickerBrowserProxy.setInstance(
-                mock, new ThemeColorPickerClientCallbackRouter()));
-    callbackRouter = ThemeColorPickerBrowserProxy.getInstance()
-                         .callbackRouter.$.bindNewPipeAndPassRemote();
-    metrics = fakeMetricsPrivate();
-  });
-
-  async function setInitialSettings(numColors: number): Promise<void> {
-    const colors: ChromeColor[] = [];
-    for (let i = 0; i < numColors; i++) {
-      colors.push({
-        name: `color_${i}`,
-        seed: {value: i},
-        background: {value: i + 1},
-        foreground: {value: i + 2},
-        base: {value: i + 3},
-        variant: BrowserColorVariant.kTonalSpot,
-      });
-    }
-    handler.setResultFor('getChromeColors', Promise.resolve({colors}));
-    chromeColorsElement =
-        document.createElement('customize-chrome-chrome-colors');
-    document.body.appendChild(chromeColorsElement);
-    await handler.whenCalled('getChromeColors');
-  }
-
-  test('back button create event', async () => {
-    await setInitialSettings(0);
-
-    const eventPromise = eventToPromise('back-click', chromeColorsElement);
-    chromeColorsElement.$.heading.getBackButton().click();
-    const event = await eventPromise;
-    assertTrue(!!event);
-  });
-
-  test('get chrome colors', async () => {
-    await setInitialSettings(2);
-
-    const colors =
-        chromeColorsElement.shadowRoot!.querySelectorAll<ThemeColorElement>(
-            '.chrome-color');
-    assertEquals(colors.length, 2);
-    assertDeepEquals({value: 1}, colors[0]!.backgroundColor);
-    assertDeepEquals({value: 2}, colors[0]!.foregroundColor);
-    assertEquals('color_0', colors[0]!.title);
-    assertDeepEquals({value: 2}, colors[1]!.backgroundColor);
-    assertDeepEquals({value: 3}, colors[1]!.foregroundColor);
-    assertEquals('color_1', colors[1]!.title);
-  });
-
-  test('sets chrome color', async () => {
-    await setInitialSettings(1);
-
-    chromeColorsElement.shadowRoot!
-        .querySelector<ThemeColorElement>('.chrome-color')!.click();
-
-    // Should remove background image if there is one.
-    assertEquals(1, handler.getCallCount('removeBackgroundImage'));
-    const args = handler.getArgs('setSeedColor')[0];
-    assertEquals(1, handler.getCallCount('setSeedColor'));
-    assertEquals(0, args[0].value);
-    assertEquals(BrowserColorVariant.kTonalSpot, args[1]);
-  });
-
-  test('sets default color', async () => {
-    await setInitialSettings(1);
-
-    chromeColorsElement.$.defaultColor.click();
-
-    // Should remove background image if there is one.
-    assertEquals(1, handler.getCallCount('removeBackgroundImage'));
-    assertEquals(1, handler.getCallCount('setDefaultColor'));
-  });
-
-  test('sets custom color', async () => {
-    await setInitialSettings(0);
-    chromeColorsElement.$.colorPicker.value = '#ff0000';
-    chromeColorsElement.$.colorPicker.dispatchEvent(new Event('change'));
-
-    assertEquals(1, handler.getCallCount('removeBackgroundImage'));
-    const args = handler.getArgs('setSeedColor')[0];
-    assertEquals(2, args.length);
-    assertEquals(0xffff0000, args[0].value);
-    assertEquals(BrowserColorVariant.kTonalSpot, args[1]);
-  });
-
-  test('checks selected color', async () => {
-    await setInitialSettings(2);
-    const theme = createTheme();
-
-    // Set default color.
-    theme.foregroundColor = null;
-    callbackRouter.setTheme(theme);
-    await callbackRouter.$.flushForTesting();
-    await waitAfterNextRender(chromeColorsElement);
-
-    // Check default color selected.
-    const defaultColorElement = chromeColorsElement.$.defaultColor;
-    let checkedColors =
-        chromeColorsElement.shadowRoot!.querySelectorAll('[checked]');
-    assertEquals(1, checkedColors.length);
-    assertEquals(defaultColorElement, checkedColors[0]);
-    assertEquals('true', checkedColors[0]!.getAttribute('aria-current'));
-
-    // Set Chrome color.
-    theme.seedColor = {value: 1};
-    theme.foregroundColor = {value: 3};
-    callbackRouter.setTheme(theme);
-    await callbackRouter.$.flushForTesting();
-    await waitAfterNextRender(chromeColorsElement);
-
-    // Check Chrome color selected.
-    checkedColors =
-        chromeColorsElement.shadowRoot!.querySelectorAll('[checked]');
-    assertEquals(1, checkedColors.length);
-    assertEquals('chrome-color tile', checkedColors[0]!.className);
-    assertEquals(
-        3, (checkedColors[0]! as ThemeColorElement).foregroundColor.value);
-    assertEquals('true', checkedColors[0]!.getAttribute('aria-current'));
-
-    // Set custom color.
-    theme.seedColor = {value: 10};
-    theme.foregroundColor = {value: 5};
-    callbackRouter.setTheme(theme);
-    await callbackRouter.$.flushForTesting();
-    await waitAfterNextRender(chromeColorsElement);
-
-    // Check custom color selected.
-    checkedColors =
-        chromeColorsElement.shadowRoot!.querySelectorAll('[checked]');
-    assertEquals(1, checkedColors.length);
-    assertEquals(chromeColorsElement.$.customColor, checkedColors[0]);
-    assertEquals(
-        'true', checkedColors[0]!.parentElement!.getAttribute('aria-current'));
-
-    // Set a CWS theme.
-    theme.hasThirdPartyTheme = true;
-    callbackRouter.setTheme(theme);
-    await callbackRouter.$.flushForTesting();
-    await waitAfterNextRender(chromeColorsElement);
-
-    // Check that no color is selected.
-    checkedColors =
-        chromeColorsElement.shadowRoot!.querySelectorAll('[checked]');
-    assertEquals(0, checkedColors.length);
-  });
-
-  suite('Metrics', () => {
-    test('Clicking default color sets metric', async () => {
-      await setInitialSettings(1);
-
-      chromeColorsElement.$.defaultColor.click();
-      await callbackRouter.$.flushForTesting();
-      await waitAfterNextRender(chromeColorsElement);
-
-      assertEquals(
-          1, metrics.count('NewTabPage.CustomizeChromeSidePanelAction'));
-      assertEquals(
-          1,
-          metrics.count(
-              'NewTabPage.CustomizeChromeSidePanelAction',
-              CustomizeChromeAction.DEFAULT_COLOR_CLICKED));
-    });
-
-    test('Clicking Chrome color sets metric', async () => {
-      await setInitialSettings(1);
-
-      chromeColorsElement.shadowRoot!
-          .querySelector<ThemeColorElement>('.chrome-color')!.click();
-      await callbackRouter.$.flushForTesting();
-      await waitAfterNextRender(chromeColorsElement);
-
-      assertEquals(
-          1, metrics.count('NewTabPage.CustomizeChromeSidePanelAction'));
-      assertEquals(
-          1,
-          metrics.count(
-              'NewTabPage.CustomizeChromeSidePanelAction',
-              CustomizeChromeAction.CHROME_COLOR_CLICKED));
-    });
-
-    test('Clicking custom color sets metric', async () => {
-      await setInitialSettings(1);
-
-      chromeColorsElement.$.customColor.click();
-      await callbackRouter.$.flushForTesting();
-      await waitAfterNextRender(chromeColorsElement);
-
-      assertEquals(
-          1, metrics.count('NewTabPage.CustomizeChromeSidePanelAction'));
-      assertEquals(
-          1,
-          metrics.count(
-              'NewTabPage.CustomizeChromeSidePanelAction',
-              CustomizeChromeAction.CUSTOM_COLOR_CLICKED));
-    });
-  });
-});
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/customize_chrome_browsertest.cc b/chrome/test/data/webui/side_panel/customize_chrome/customize_chrome_browsertest.cc
index 17b3433..0bdd209 100644
--- a/chrome/test/data/webui/side_panel/customize_chrome/customize_chrome_browsertest.cc
+++ b/chrome/test/data/webui/side_panel/customize_chrome/customize_chrome_browsertest.cc
@@ -71,16 +71,6 @@
   RunTest("side_panel/customize_chrome/theme_snapshot_test.js", "mocha.run()");
 }
 
-#if BUILDFLAG(USE_JAVASCRIPT_COVERAGE)
-// TODO(b/327036381): Fails on JS coverage bot.
-#define MAYBE_ChromeColors DISABLED_ChromeColors
-#else
-#define MAYBE_ChromeColors ChromeColors
-#endif
-IN_PROC_BROWSER_TEST_F(SidePanelCustomizeChromeTest, MAYBE_ChromeColors) {
-  RunTest("side_panel/customize_chrome/chrome_colors_test.js", "mocha.run()");
-}
-
 using CustomizeChromeWallpaperSearchTest = SidePanelCustomizeChromeTest;
 
 IN_PROC_BROWSER_TEST_F(CustomizeChromeWallpaperSearchTest, Misc) {
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/theme_snapshot_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/theme_snapshot_test.ts
index 0d6db12..5a884ac 100644
--- a/chrome/test/data/webui/side_panel/customize_chrome/theme_snapshot_test.ts
+++ b/chrome/test/data/webui/side_panel/customize_chrome/theme_snapshot_test.ts
@@ -9,7 +9,7 @@
 import {CustomizeChromeApiProxy} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome_api_proxy.js';
 import type {ThemeSnapshotElement} from 'chrome://customize-chrome-side-panel.top-chrome/theme_snapshot.js';
 import {CustomizeThemeType} from 'chrome://customize-chrome-side-panel.top-chrome/theme_snapshot.js';
-import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import type {TestMock} from 'chrome://webui-test/test_mock.js';
 
 import {$$, createBackgroundImage, createTheme, installMock} from './test_support.js';
@@ -96,13 +96,8 @@
         CustomizeThemeType.CLASSIC_CHROME);
     assertEquals(
         $$<HTMLImageElement>(
-            themeSnapshotElement, '#classicChromeBackground img')!.src,
-        'chrome://customize-chrome-side-panel.top-chrome/icons/' +
-            'mini_new_tab_page.svg');
-    assertEquals(
-        $$<HTMLImageElement>(
             themeSnapshotElement,
-            '#classicChromeBackground img')!.getAttribute('aria-labelledby'),
+            '#classicChromeBackground svg')!.getAttribute('aria-labelledby'),
         'classicChromeThemeTitle');
     assertEquals(
         'Default Chrome',
@@ -141,12 +136,35 @@
            '.snapshot-container #uploadedThemeTitle')!.textContent!.trim());
   });
 
+  test('classic chrome snapshot shows correct image', async () => {
+    // Arrange.
+    createThemeSnapshotElement();
+    const theme = createTheme();
+
+    // Act.
+    callbackRouterRemote.setTheme(theme);
+    await callbackRouterRemote.$.flushForTesting();
+
+    // Assert.
+    assertEquals(1, handler.getCallCount('updateTheme'));
+    const shownPages =
+        themeSnapshotElement.shadowRoot!.querySelectorAll('.iron-selected');
+    assertTrue(!!shownPages);
+    assertEquals(shownPages.length, 1);
+    assertEquals(
+        shownPages[0]!.getAttribute('theme-type'),
+        CustomizeThemeType.CLASSIC_CHROME);
+    assertEquals(
+        $$<SVGUseElement>(
+            themeSnapshotElement,
+            '#classicChromeBackground svg use')!.href.baseVal,
+        'icons/gm3_mini_new_tab_page.svg#miniNewTabPage');
+  });
+
   test(
-      'clicking snapshot with chrome-refresh-2023 toggled off ' +
-          'does not create an edit-theme-click event',
+      'clicking classic chrome snapshot creates edit-theme-click event',
       async () => {
         // Arrange.
-        document.documentElement.toggleAttribute('chrome-refresh-2023', false);
         createThemeSnapshotElement();
         let clicked = false;
         themeSnapshotElement.addEventListener(
@@ -156,85 +174,37 @@
             themeSnapshotElement,
             '.snapshot-container #classicChromeBackground')!.click();
         // Assert
-        assertFalse(clicked);
+        assertTrue(clicked);
       });
 
-  suite('chrome refresh 2023', () => {
-    suiteSetup(() => {
-      document.documentElement.toggleAttribute('chrome-refresh-2023', true);
-    });
+  test(
+      'clicking custom theme snapshot creates edit-theme-click event',
+      async () => {
+        // Arrange.
+        createThemeSnapshotElement();
+        let clicked = false;
+        themeSnapshotElement.addEventListener(
+            'edit-theme-click', () => clicked = true);
+        // Act
+        $$<HTMLElement>(
+            themeSnapshotElement,
+            '.snapshot-container #customThemeImageBackground')!.click();
+        // Assert
+        assertTrue(clicked);
+      });
 
-    test('classic chrome snapshot shows correct image', async () => {
-      // Arrange.
-      createThemeSnapshotElement();
-      const theme = createTheme();
-
-      // Act.
-      callbackRouterRemote.setTheme(theme);
-      await callbackRouterRemote.$.flushForTesting();
-
-      // Assert.
-      assertEquals(1, handler.getCallCount('updateTheme'));
-      const shownPages =
-          themeSnapshotElement.shadowRoot!.querySelectorAll('.iron-selected');
-      assertTrue(!!shownPages);
-      assertEquals(shownPages.length, 1);
-      assertEquals(
-          shownPages[0]!.getAttribute('theme-type'),
-          CustomizeThemeType.CLASSIC_CHROME);
-      assertEquals(
-          $$<SVGUseElement>(
-              themeSnapshotElement,
-              '#classicChromeBackground svg use')!.href.baseVal,
-          'icons/gm3_mini_new_tab_page.svg#miniNewTabPage');
-    });
-
-    test(
-        'clicking classic chrome snapshot creates edit-theme-click event',
-        async () => {
-          // Arrange.
-          createThemeSnapshotElement();
-          let clicked = false;
-          themeSnapshotElement.addEventListener(
-              'edit-theme-click', () => clicked = true);
-          // Act
-          $$<HTMLElement>(
-              themeSnapshotElement,
-              '.snapshot-container #classicChromeBackground')!.click();
-          // Assert
-          assertTrue(clicked);
-        });
-
-    test(
-        'clicking custom theme snapshot creates edit-theme-click event',
-        async () => {
-          // Arrange.
-          createThemeSnapshotElement();
-          let clicked = false;
-          themeSnapshotElement.addEventListener(
-              'edit-theme-click', () => clicked = true);
-          // Act
-          $$<HTMLElement>(
-              themeSnapshotElement,
-              '.snapshot-container #customThemeImageBackground')!.click();
-          // Assert
-          assertTrue(clicked);
-        });
-
-    test(
-        'clicking uploaded snapshot creates edit-theme-click event',
-        async () => {
-          // Arrange.
-          createThemeSnapshotElement();
-          let clicked = false;
-          themeSnapshotElement.addEventListener(
-              'edit-theme-click', () => clicked = true);
-          // Act
-          $$<HTMLElement>(
-              themeSnapshotElement,
-              '.snapshot-container #uploadedThemeImageBackground')!.click();
-          // Assert
-          assertTrue(clicked);
-        });
-  });
+  test(
+      'clicking uploaded snapshot creates edit-theme-click event', async () => {
+        // Arrange.
+        createThemeSnapshotElement();
+        let clicked = false;
+        themeSnapshotElement.addEventListener(
+            'edit-theme-click', () => clicked = true);
+        // Act
+        $$<HTMLElement>(
+            themeSnapshotElement,
+            '.snapshot-container #uploadedThemeImageBackground')!.click();
+        // Assert
+        assertTrue(clicked);
+      });
 });
diff --git a/chrome/test/data/webui/side_panel/read_anything/app_receives_toolbar_changes_test.ts b/chrome/test/data/webui/side_panel/read_anything/app_receives_toolbar_changes_test.ts
index 68e7d54..0147ce1 100644
--- a/chrome/test/data/webui/side_panel/read_anything/app_receives_toolbar_changes_test.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/app_receives_toolbar_changes_test.ts
@@ -255,9 +255,7 @@
 
       test('starts speech', () => {
         assertFalse(app.speechPlayingState.paused);
-        // TODO: b/323960128 - Since this test browser doesn't have any
-        // voices, speechStarted doesn't get set to true. Find a way to add a
-        // mock voice to this browser, and test that app.speechStarted is true.
+        assertTrue(app.speechPlayingState.speechStarted);
       });
     });
 
@@ -269,6 +267,7 @@
 
       test('stops speech', () => {
         assertTrue(app.speechPlayingState.paused);
+        assertTrue(app.speechPlayingState.speechStarted);
       });
     });
 
diff --git a/chrome/test/data/webui/side_panel/read_anything/links_toggled_integration.ts b/chrome/test/data/webui/side_panel/read_anything/links_toggled_integration.ts
index 0b12c36..cac1b7e 100644
--- a/chrome/test/data/webui/side_panel/read_anything/links_toggled_integration.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/links_toggled_integration.ts
@@ -7,7 +7,7 @@
 import {flush} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import type {ReadAnythingElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/app.js';
 import {LINK_TOGGLE_BUTTON_ID, NEXT_GRANULARITY_EVENT} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything_toolbar.js';
-import {assertEquals} from 'chrome-untrusted://webui-test/chai_assert.js';
+import {assertEquals, assertFalse, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js';
 
 import {emitEvent, suppressInnocuousErrors} from './common.js';
 
@@ -86,6 +86,12 @@
     test('container has links', () => {
       assertContainerHasLinks(true);
     });
+
+    test('container has no highlight', () => {
+      const currentHighlight =
+          app.$.container.querySelector('.current-read-highlight');
+      assertFalse(!!currentHighlight);
+    });
   });
 
   suite('without speech', () => {
@@ -109,6 +115,12 @@
       assertContainerHasLinks(false);
     });
 
+    test('container has highlight', () => {
+      const currentHighlight =
+          app.$.container.querySelector('.current-read-highlight');
+      assertTrue(!!currentHighlight);
+    });
+
     suite('and after speech finishes', () => {
       setup(() => {
         for (let i = 0; i < axTree.nodes.length + 1; i++) {
@@ -131,6 +143,12 @@
     test('container has links again', () => {
       assertContainerHasLinks(true);
     });
+
+    test('container still has highlight', () => {
+      const currentHighlight =
+          app.$.container.querySelector('.current-read-highlight');
+      assertTrue(!!currentHighlight);
+    });
   });
 
   suite('with links toggled off', () => {
@@ -154,6 +172,12 @@
       test('container does not have links', () => {
         assertContainerHasLinks(false);
       });
+
+      test('container has highlight', () => {
+        const currentHighlight =
+            app.$.container.querySelector('.current-read-highlight');
+        assertTrue(!!currentHighlight);
+      });
     });
 
     suite('after speech pauses', () => {
@@ -165,6 +189,12 @@
       test('container does not have links', () => {
         assertContainerHasLinks(false);
       });
+
+      test('container still has highlight', () => {
+        const currentHighlight =
+            app.$.container.querySelector('.current-read-highlight');
+        assertTrue(!!currentHighlight);
+      });
     });
   });
 });
diff --git a/chrome/updater/cleanup_task.cc b/chrome/updater/cleanup_task.cc
index f29ee3b4..e0578f6 100644
--- a/chrome/updater/cleanup_task.cc
+++ b/chrome/updater/cleanup_task.cc
@@ -6,6 +6,7 @@
 
 #include <optional>
 
+#include "base/check_op.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
 #include "base/functional/bind.h"
@@ -29,8 +30,7 @@
 
 namespace {
 
-// Versions up to this version will be uninstalled.
-constexpr char kCleanupVersionMax[] = "117.0.5859.0";
+constexpr int kMilestoneDeletionThreshold = 8;
 
 void CleanupGoogleUpdate(UpdaterScope scope) {
 #if BUILDFLAG(IS_WIN)
@@ -42,18 +42,18 @@
 }
 
 void CleanupOldUpdaterVersions(UpdaterScope scope) {
-  CHECK(base::Version(kCleanupVersionMax).IsValid());
-  CHECK(base::Version(kUpdaterVersion)
-            .CompareTo(base::Version(kCleanupVersionMax)) > 0);
+  base::Version cleanup_max =
+      base::Version({base::Version(kUpdaterVersion).components()[0] -
+                     kMilestoneDeletionThreshold});
+  CHECK_GT(base::Version(kUpdaterVersion), cleanup_max);
   std::optional<base::FilePath> dir = GetInstallDirectory(scope);
   if (!dir) {
     return;
   }
   base::FileEnumerator(*dir, false, base::FileEnumerator::DIRECTORIES)
-      .ForEach([&scope](const base::FilePath& item) {
+      .ForEach([&scope, &cleanup_max](const base::FilePath& item) {
         base::Version version(item.BaseName().MaybeAsASCII());
-        if (!version.IsValid() ||
-            version.CompareTo(base::Version(kCleanupVersionMax)) > 0) {
+        if (!version.IsValid() || version.CompareTo(cleanup_max) > 0) {
           return;
         }
         VLOG(1) << __func__ << " cleaning up " << item;
diff --git a/chrome/updater/cleanup_task_unittest.cc b/chrome/updater/cleanup_task_unittest.cc
index cb5e543..8bc140d6 100644
--- a/chrome/updater/cleanup_task_unittest.cc
+++ b/chrome/updater/cleanup_task_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/test/task_environment.h"
 #include "base/version.h"
 #include "chrome/updater/test_scope.h"
+#include "chrome/updater/updater_version.h"
 #include "chrome/updater/util/unit_test_util.h"
 #include "chrome/updater/util/util.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -23,7 +24,12 @@
 
 namespace updater {
 
-class CleanupTaskTest : public testing::Test {};
+class CleanupTaskTest : public testing::Test {
+ protected:
+  void TearDown() override {
+    base::DeletePathRecursively(*GetInstallDirectory(GetTestScope()));
+  }
+};
 
 TEST_F(CleanupTaskTest, RunCleanupObsoleteFiles) {
   base::test::TaskEnvironment task_environment;
@@ -46,6 +52,11 @@
       GetVersionedInstallDirectory(GetTestScope(), base::Version("100"));
   ASSERT_TRUE(folder_path);
   ASSERT_TRUE(base::CreateDirectory(*folder_path));
+  std::optional<base::FilePath> folder_path_current =
+      GetVersionedInstallDirectory(GetTestScope(),
+                                   base::Version(kUpdaterVersion));
+  ASSERT_TRUE(folder_path_current);
+  ASSERT_TRUE(base::CreateDirectory(*folder_path_current));
 
   auto cleanup_task = base::MakeRefCounted<CleanupTask>(GetTestScope());
   base::RunLoop run_loop;
@@ -53,6 +64,7 @@
   run_loop.Run();
 
   ASSERT_FALSE(base::PathExists(*folder_path));
+  ASSERT_TRUE(base::PathExists(*folder_path_current));
 
 #if BUILDFLAG(IS_WIN)
   // Expect only a single file `GoogleUpdate.exe` and nothing else under
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc
index ccaf99bc..e9890b81 100644
--- a/chrome/updater/test/integration_tests.cc
+++ b/chrome/updater/test/integration_tests.cc
@@ -2901,7 +2901,8 @@
                                             kEnrollmentToken, kDMToken);
   OmahaSettingsClientProto omaha_settings;
   omaha_settings.set_proxy_mode("fixed_servers");
-  omaha_settings.set_proxy_server(test_server_->proxy_url_no_path());
+  omaha_settings.set_proxy_server(
+      base::StrCat({test_server_->proxy_url_no_path(), ";DIRECT"}));
   ExpectDeviceManagementPolicyFetchRequest(test_server_.get(), kDMToken,
                                            omaha_settings);
   ASSERT_NO_FATAL_FAILURE(
@@ -2909,7 +2910,7 @@
   ASSERT_NO_FATAL_FAILURE(RunWake(0));
   ASSERT_TRUE(WaitForUpdaterExit());
 
-  // Redirect network traffics to remote hosts to engage the proxy.
+  // Redirect network traffic to remote hosts to engage the proxy.
   const GURL update_check_url = GURL("http://update.server.not_exist/update");
   const GURL dm_server_url = GURL("http://dm.server.not_exist/dmapi");
   EnterTestMode(update_check_url, test_server_->crash_upload_url(),
@@ -2919,12 +2920,50 @@
                                            dm_server_url);
   ASSERT_NO_FATAL_FAILURE(RunWake(0));
   ASSERT_TRUE(WaitForUpdaterExit());
-
   ASSERT_NO_FATAL_FAILURE(
       ExpectUninstallPing(test_server_.get(), update_check_url));
   ASSERT_NO_FATAL_FAILURE(UninstallApp(kApp1.appid));
   ASSERT_NO_FATAL_FAILURE(Uninstall());
 }
+
+TEST_F(IntegrationTestDeviceManagement, PacScript) {
+  ASSERT_NO_FATAL_FAILURE(Install());
+  ASSERT_NO_FATAL_FAILURE(InstallTestApp(kApp1, /*install_v1=*/false));
+
+  ASSERT_NO_FATAL_FAILURE(ExpectInstalled());
+  ASSERT_NO_FATAL_FAILURE(ExpectAppInstalled(kApp1.appid, kApp1.v2));
+
+  // Fetch proxy settings policy.
+  DMPushEnrollmentToken(kEnrollmentToken);
+  ExpectDeviceManagementRegistrationRequest(test_server_.get(),
+                                            kEnrollmentToken, kDMToken);
+  OmahaSettingsClientProto omaha_settings;
+  omaha_settings.set_proxy_mode("pac_script");
+  omaha_settings.set_proxy_pac_url(test_server_->proxy_pac_url().spec());
+  ExpectDeviceManagementPolicyFetchRequest(test_server_.get(), kDMToken,
+                                           omaha_settings);
+  ExpectProxyPacScriptRequest(test_server_.get());
+  ASSERT_NO_FATAL_FAILURE(
+      ExpectNoUpdateSequence(test_server_.get(), kApp1.appid));
+  ASSERT_NO_FATAL_FAILURE(RunWake(0));
+  ASSERT_TRUE(WaitForUpdaterExit());
+
+  // Redirect network traffic to remote hosts to engage the proxy.
+  // Note the test server won't receive additional PAC script download requests
+  // because Windows caches it.
+  const GURL update_check_url = GURL("http://update.server.not_exist/update");
+  const GURL dm_server_url = GURL("http://dm.server.not_exist2/dmapi");
+  EnterTestMode(update_check_url, test_server_->crash_upload_url(),
+                dm_server_url, {}, base::Minutes(5));
+  ExpectDeviceManagementPolicyFetchRequest(test_server_.get(), kDMToken,
+                                           omaha_settings, false, false,
+                                           dm_server_url);
+  ASSERT_NO_FATAL_FAILURE(RunWake(0));
+  ASSERT_TRUE(WaitForUpdaterExit());
+  ASSERT_NO_FATAL_FAILURE(ExpectUninstallPing(test_server_.get()));
+  ASSERT_NO_FATAL_FAILURE(UninstallApp(kApp1.appid));
+  ASSERT_NO_FATAL_FAILURE(Uninstall());
+}
 #endif  // BUILDFLAG(IS_WIN)
 
 #endif  // !defined(COMPONENT_BUILD)
diff --git a/chrome/updater/test/integration_tests_impl.cc b/chrome/updater/test/integration_tests_impl.cc
index b9da52f..a340baf4 100644
--- a/chrome/updater/test/integration_tests_impl.cc
+++ b/chrome/updater/test/integration_tests_impl.cc
@@ -1449,4 +1449,14 @@
                                 "GoogleDMToken", dm_token, net::HTTP_OK, "");
 }
 
+void ExpectProxyPacScriptRequest(ScopedServer* test_server) {
+  test_server->ExpectOnce(
+      {request::GetPathMatcher(test_server->proxy_pac_path()),
+       request::GetHeaderMatcher(
+           {{"User-Agent", "WinHttp-Autoproxy-Service.*"}})},
+      base::StringPrintf(
+          "function FindProxyForURL(url, host) { return \"PROXY %s\"; }",
+          test_server->host_port_pair().c_str()));
+}
+
 }  // namespace updater::test
diff --git a/chrome/updater/test/integration_tests_impl.h b/chrome/updater/test/integration_tests_impl.h
index 823c960..f579935 100644
--- a/chrome/updater/test/integration_tests_impl.h
+++ b/chrome/updater/test/integration_tests_impl.h
@@ -446,6 +446,7 @@
                                                 bool invalidate_token);
 void ExpectDeviceManagementPolicyValidationRequest(ScopedServer* test_server,
                                                    const std::string& dm_token);
+void ExpectProxyPacScriptRequest(ScopedServer* test_server);
 
 }  // namespace updater::test
 
diff --git a/chrome/updater/test/server.cc b/chrome/updater/test/server.cc
index 82fb013..10ee469c 100644
--- a/chrome/updater/test/server.cc
+++ b/chrome/updater/test/server.cc
@@ -114,6 +114,9 @@
   if (base::StartsWith(request.relative_url, device_management_path())) {
     response->set_content_type("application/x-protobuf");
   }
+  if (base::StartsWith(request.relative_url, proxy_pac_path())) {
+    VLOG(1) << "PAC proxy settings: [ " << response_body << "]";
+  }
   response->set_content(response_body);
   request_matcher_groups_.pop_front();
   responses_.pop_front();
diff --git a/chrome/updater/test/server.h b/chrome/updater/test/server.h
index 6606e3f..ad7b4b9 100644
--- a/chrome/updater/test/server.h
+++ b/chrome/updater/test/server.h
@@ -47,6 +47,10 @@
   ScopedServer(const ScopedServer&) = delete;
   ScopedServer& operator=(const ScopedServer&) = delete;
 
+  std::string host_port_pair() const {
+    return test_server_->host_port_pair().ToString();
+  }
+
   // Registers an expected request with the server. Requests must match the
   // expectation defined by applying all individual request matchers composing
   // the `request_matcher_group` in the order the expectations were set.
@@ -81,6 +85,9 @@
   std::string app_logo_path() const { return "/applogo/"; }
   GURL app_logo_url() const { return test_server_->GetURL(app_logo_path()); }
 
+  std::string proxy_pac_path() const { return "/pac_script.pac"; }
+  GURL proxy_pac_url() const { return test_server_->GetURL(proxy_pac_path()); }
+
   std::string proxy_url_no_path() const {
     std::string proxy = test_server_->base_url().spec();
     // A valid proxy string should not have any path component. Strip the root
diff --git a/chrome/updater/win/task_scheduler.cc b/chrome/updater/win/task_scheduler.cc
index aa140df0..316af81 100644
--- a/chrome/updater/win/task_scheduler.cc
+++ b/chrome/updater/win/task_scheduler.cc
@@ -1108,7 +1108,7 @@
     base::win::ScopedBstr task_subfolder_name(GetTaskSubfolderName());
     hr = root_task_folder->GetFolder(task_subfolder_name.Get(), &folder);
 
-    // Try creating the folder it wasn't there.
+    // Try creating the folder if it wasn't there.
     if (IsFileOrPathNotFoundError(hr)) {
       // Use default SDDL.
       hr = root_task_folder->CreateFolder(
@@ -1116,7 +1116,9 @@
           &folder);
 
       if (FAILED(hr)) {
-        LOG(ERROR) << "Failed to create the folder." << std::hex << hr;
+        LOG(ERROR) << "Failed to create the folder: "
+                   << task_subfolder_name.Get() << ", error: " << std::hex
+                   << hr;
         return nullptr;
       }
     } else if (FAILED(hr)) {
diff --git a/chromecast/chromecast.gni b/chromecast/chromecast.gni
index f04c5989..538fa2b 100644
--- a/chromecast/chromecast.gni
+++ b/chromecast/chromecast.gni
@@ -143,6 +143,18 @@
     "tablet",
     "automotive",
   ]
+
+  # Use Starboard graphics backend. Compile it in statically.
+  enable_starboard_graphics = false
+
+  # Build Starboard graphics backend as shared library.
+  starboard_graphics_is_shared = false
+
+  # Use Starboard media backend.
+  enable_starboard_media = false
+
+  # Build Starboard media backend as shared library.
+  starboard_media_is_shared = false
 }
 
 declare_args() {
diff --git a/chromecast/starboard/BUILD.gn b/chromecast/starboard/BUILD.gn
new file mode 100644
index 0000000..14c5581
--- /dev/null
+++ b/chromecast/starboard/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2024 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/buildflag_header.gni")
+import("//chromecast/starboard/starboard.gni")
+
+buildflag_header("starboard_buildflags") {
+  header = "starboard_buildflags.h"
+  flags = [ "REMOVE_STARBOARD_HEADERS=$remove_starboard_headers" ]
+}
diff --git a/chromecast/starboard/DEPS b/chromecast/starboard/DEPS
new file mode 100644
index 0000000..809f8ba5
--- /dev/null
+++ b/chromecast/starboard/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+chromecast/media",
+]
diff --git a/chromecast/starboard/chromecast/starboard_adapter/BUILD.gn b/chromecast/starboard/chromecast/starboard_adapter/BUILD.gn
new file mode 100644
index 0000000..29b7a24a
--- /dev/null
+++ b/chromecast/starboard/chromecast/starboard_adapter/BUILD.gn
@@ -0,0 +1,52 @@
+# Copyright 2024 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//chromecast/chromecast.gni")
+import("//chromecast/starboard/starboard.gni")
+
+config("public_config") {
+  include_dirs =
+      [ "//chromecast/starboard/chromecast/starboard_adapter/public" ]
+}
+
+source_set("starboard_adapter_public") {
+  sources = [ "public/cast_starboard_api_adapter.h" ]
+  public_configs = [ ":public_config" ]
+  public_deps = []
+  if (!remove_starboard_headers) {
+    public_deps += [ "//chromecast/starboard/third_party/starboard/public" ]
+  }
+  deps = [ "//chromecast/starboard:starboard_buildflags" ]
+}
+
+source_set("starboard_adapter_static") {
+  sources = []
+  public_deps = [ ":starboard_adapter_public" ]
+
+  if (remove_starboard_headers) {
+    sources += [ "src/cast_starboard_api_adapter_dummy.cc" ]
+  } else {
+    sources += [
+      "src/cast_starboard_api_adapter_impl.cc",
+      "src/cast_starboard_api_adapter_impl.h",
+    ]
+    public_deps += [
+      "//chromecast/starboard/chromecast/starboard_cast_api",
+      "//chromecast/starboard/chromecast/starboard_cast_dummy:cast_starboard_api",
+    ]
+  }
+
+  # TODO(riazantsevv@): To implement this in a better way.
+  defines = [ "SB_IS_EVERGREEN" ]
+}
+
+if (starboard_graphics_is_shared || starboard_media_is_shared) {
+  shared_library("starboard_adapter") {
+    public_deps = [ ":starboard_adapter_static" ]
+  }
+} else {
+  source_set("starboard_adapter") {
+    public_deps = [ ":starboard_adapter_static" ]
+  }
+}
diff --git a/chromecast/starboard/chromecast/starboard_adapter/public/cast_starboard_api_adapter.h b/chromecast/starboard/chromecast/starboard_adapter/public/cast_starboard_api_adapter.h
new file mode 100644
index 0000000..73ebf39
--- /dev/null
+++ b/chromecast/starboard/chromecast/starboard_adapter/public/cast_starboard_api_adapter.h
@@ -0,0 +1,57 @@
+// 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 CHROMECAST_STARBOARD_CHROMECAST_STARBOARD_ADAPTER_PUBLIC_CAST_STARBOARD_API_ADAPTER_H_
+#define CHROMECAST_STARBOARD_CHROMECAST_STARBOARD_ADAPTER_PUBLIC_CAST_STARBOARD_API_ADAPTER_H_
+
+#include "chromecast/starboard/starboard_buildflags.h"
+
+#if BUILDFLAG(REMOVE_STARBOARD_HEADERS)
+
+using SbEvent = void;
+using SbWindowOptions = void;
+using SbEglNativeDisplayType = void*;
+using SbWindow = void*;
+
+#else
+#include <starboard/egl.h>
+#include <starboard/event.h>
+#include <starboard/export.h>
+#endif  // BUILDFLAG(REMOVE_STARBOARD_HEADERS)
+
+namespace chromecast {
+
+// CastStarboardApiAdapter provides a C++ wrapper to the CastStarboardApi,
+// which is a C-style interface implemented in an external library. The primary
+// purpose of CastStarboardApiAdapter is to managage the lifecycle of the
+// external library, which expects to always be initialized before use and only
+// have a single instance.
+class __attribute__((visibility("default"))) CastStarboardApiAdapter {
+ public:
+  static CastStarboardApiAdapter* GetInstance();
+
+  virtual ~CastStarboardApiAdapter() = default;
+
+  // Ensures that the CastStarboardApi is initialized. Callers should invoke
+  // this before any other functions.
+  virtual bool EnsureInitialized() = 0;
+
+  // When Starboard events occur, `callback` will be called with `context`, an
+  // integer corresponding to the SbEventType, and a void* containing the data
+  // for the event (which may be null, since some events do not contain data).
+  // The `callback` must be thread safe, i.e. it will not automatically be
+  // posted to the same thread on which Subscribe was called.
+  virtual void Subscribe(void* context,
+                         void (*callback)(void* context,
+                                          const SbEvent* event)) = 0;
+
+  // Gets the SbEglDisplay associated with the internally managed context.
+  virtual SbEglNativeDisplayType GetEglNativeDisplayType() = 0;
+
+  // Gets the window shared between the graphics and media libraries.
+  virtual SbWindow GetWindow(const SbWindowOptions* options) = 0;
+};
+
+}  // namespace chromecast
+
+#endif  // CHROMECAST_STARBOARD_CHROMECAST_STARBOARD_ADAPTER_PUBLIC_CAST_STARBOARD_API_ADAPTER_H_
diff --git a/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_dummy.cc b/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_dummy.cc
new file mode 100644
index 0000000..9d6edd1
--- /dev/null
+++ b/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_dummy.cc
@@ -0,0 +1,22 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A dummy implementation of egl_starboard.h. This can be used to compile
+// without starboard headers. It should never be used in production.
+//
+// TODO(b/333131992): remove this
+
+#include <iostream>
+
+#include "chromecast/starboard/chromecast/starboard_adapter/public/cast_starboard_api_adapter.h"
+
+namespace chromecast {
+
+// static
+CastStarboardApiAdapter* CastStarboardApiAdapter::GetInstance() {
+  std::cerr << "Returning a null CastStarboardApiAdapter" << std::endl;
+  return nullptr;
+}
+
+}  // namespace chromecast
diff --git a/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_impl.cc b/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_impl.cc
new file mode 100644
index 0000000..65656e2
--- /dev/null
+++ b/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_impl.cc
@@ -0,0 +1,113 @@
+// 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 "cast_starboard_api_adapter_impl.h"
+
+// TODO(b/333961720): remove all the macros in this file and split the impl into
+// two different classes: one for SB 15+, one for older versions of starboard.
+// Only include the relevant one in the BUILD.gn file.
+#if SB_API_VERSION >= 15
+#include <starboard/event.h>
+#else  // SB_API_VERSION >=15
+#include <cast_starboard_api.h>
+#endif  // SB_API_VERSION >= 15
+
+namespace chromecast {
+namespace {
+CastStarboardApiAdapterImpl* GetImpl() {
+  static CastStarboardApiAdapterImpl* starboard_adapter =
+      new CastStarboardApiAdapterImpl();
+  return starboard_adapter;
+}
+}  // namespace
+
+CastStarboardApiAdapter* CastStarboardApiAdapter::GetInstance() {
+  return GetImpl();
+}
+
+#if SB_API_VERSION >= 15
+CastStarboardApiAdapterImpl::CastStarboardApiAdapterImpl()
+    : init_f_(init_p_.get_future()), initialized_(false) {}
+#else   // SB_API_VERSION >=15
+CastStarboardApiAdapterImpl::CastStarboardApiAdapterImpl()
+    : initialized_(false) {}
+#endif  // SB_API_VERSION >= 15
+
+CastStarboardApiAdapterImpl::~CastStarboardApiAdapterImpl() {}
+
+SbEglNativeDisplayType CastStarboardApiAdapterImpl::GetEglNativeDisplayType() {
+  return SB_EGL_DEFAULT_DISPLAY;
+}
+
+// static
+void CastStarboardApiAdapterImpl::SbEventHandle(const SbEvent* event) {
+  GetImpl()->SbEventHandleInternal(event);
+}
+
+#if SB_API_VERSION >= 15
+void CastStarboardApiAdapterImpl::SbEventHandleInternal(const SbEvent* event) {
+  switch (event->type) {
+    case kSbEventTypeStart:
+      init_p_.set_value(true);
+      break;
+    default:
+      for (const auto p : subscribers_) {
+        p.second(p.first, event);
+      }
+      break;
+  }
+}
+#else   // SB_API_VERSION >=15
+void CastStarboardApiAdapterImpl::SbEventHandleInternal(const SbEvent* event) {
+  std::lock_guard<decltype(lock_)> lock(lock_);
+  for (const auto p : subscribers_) {
+    p.second(p.first, event);
+  }
+}
+#endif  // SB_API_VERSION >= 15
+
+#if SB_API_VERSION >= 15
+bool CastStarboardApiAdapterImpl::EnsureInitialized() {
+  std::lock_guard<decltype(lock_)> lock(lock_);
+  if (initialized_) {
+    return true;
+  }
+
+  sb_main_ = std::make_unique<std::thread>(
+      &SbRunStarboardMain, /*argc=*/0, /*argv=*/nullptr,
+      &CastStarboardApiAdapterImpl::SbEventHandle);
+  sb_main_->detach();
+  initialized_ = init_f_.get();
+  return initialized_;
+}
+#else   // SB_API_VERSION >=15
+bool CastStarboardApiAdapterImpl::EnsureInitialized() {
+  std::lock_guard<decltype(lock_)> lock(lock_);
+  if (initialized_) {
+    return true;
+  }
+
+  CastStarboardApiInitialize(/*argc=*/0, /*argv=*/nullptr,
+                             &CastStarboardApiAdapterImpl::SbEventHandle);
+  initialized_ = true;
+  return true;
+}
+#endif  // SB_API_VERSION >= 15
+
+void CastStarboardApiAdapterImpl::Subscribe(void* context,
+                                            CastStarboardApiAdapterImplCB cb) {
+  std::lock_guard<decltype(lock_)> lock(lock_);
+  subscribers_.insert({context, cb});
+}
+
+SbWindow CastStarboardApiAdapterImpl::GetWindow(
+    const SbWindowOptions* options) {
+  if (!SbWindowIsValid(window_)) {
+    window_ = SbWindowCreate(options);
+  }
+
+  return window_;
+}
+
+}  // namespace chromecast
diff --git a/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_impl.h b/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_impl.h
new file mode 100644
index 0000000..0b5cb95
--- /dev/null
+++ b/chromecast/starboard/chromecast/starboard_adapter/src/cast_starboard_api_adapter_impl.h
@@ -0,0 +1,58 @@
+// 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 CHROMECAST_STARBOARD_CHROMECAST_STARBOARD_ADAPTER_SRC_CAST_STARBOARD_API_ADAPTER_IMPL_H_
+#define CHROMECAST_STARBOARD_CHROMECAST_STARBOARD_ADAPTER_SRC_CAST_STARBOARD_API_ADAPTER_IMPL_H_
+
+#include <mutex>
+#include <unordered_map>
+
+#if SB_API_VERSION >= 15
+#include <future>
+#include <thread>
+#endif  // SB_API_VERSION >= 15
+
+#include "chromecast/starboard/chromecast/starboard_adapter/public/cast_starboard_api_adapter.h"
+
+namespace chromecast {
+
+using CastStarboardApiAdapterImplCB = void (*)(void* context,
+                                               const SbEvent* event);
+
+// Utility class for wrapping CastStarboardApi which allows delivery of events
+// to multiple subscribers.
+class CastStarboardApiAdapterImpl : public CastStarboardApiAdapter {
+ public:
+  // SbEventHandle is provided when calling CastStarboardApiInitialize and is
+  // expected to be used as the event callback for Starboard events. It routes
+  // events to the singleton instance via SbEventHandleInternal.
+  static void SbEventHandle(const SbEvent* event);
+
+  CastStarboardApiAdapterImpl();
+  ~CastStarboardApiAdapterImpl() override;
+
+ private:
+  void SbEventHandleInternal(const SbEvent* event);
+
+  // CastStarboardApiAdapter implementation:
+  bool EnsureInitialized() override;
+  void Subscribe(void* context,
+                 CastStarboardApiAdapterImplCB callback) override;
+  SbEglNativeDisplayType GetEglNativeDisplayType() override;
+  SbWindow GetWindow(const SbWindowOptions*) override;
+
+#if SB_API_VERSION >= 15
+  std::unique_ptr<std::thread> sb_main_;
+  std::promise<bool> init_p_;
+  std::future<bool> init_f_;
+#endif  // SB_API_VERSION >= 15
+  SbWindow window_ = kSbWindowInvalid;
+  std::mutex lock_;
+  bool initialized_;
+  std::unordered_map<void*, CastStarboardApiAdapterImplCB> subscribers_;
+};
+
+}  // namespace chromecast
+
+#endif  // CHROMECAST_STARBOARD_CHROMECAST_STARBOARD_ADAPTER_SRC_CAST_STARBOARD_API_ADAPTER_IMPL_H_
diff --git a/chromecast/starboard/chromecast/starboard_cast_api/BUILD.gn b/chromecast/starboard/chromecast/starboard_cast_api/BUILD.gn
new file mode 100644
index 0000000..c3966b1
--- /dev/null
+++ b/chromecast/starboard/chromecast/starboard_cast_api/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2024 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+config("public_config") {
+  include_dirs = [ "//chromecast/starboard/chromecast/starboard_cast_api" ]
+}
+
+source_set("starboard_cast_api") {
+  sources = [ "cast_starboard_api.h" ]
+  public_configs = [ ":public_config" ]
+}
+
+source_set("cast_starboard_api_types") {
+  sources = [ "cast_starboard_api_types.h" ]
+  public_configs = [ ":public_config" ]
+}
diff --git a/chromecast/starboard/chromecast/starboard_cast_api/cast_starboard_api.h b/chromecast/starboard/chromecast/starboard_cast_api/cast_starboard_api.h
new file mode 100644
index 0000000..ead8068b
--- /dev/null
+++ b/chromecast/starboard/chromecast/starboard_cast_api/cast_starboard_api.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 CHROMECAST_STARBOARD_CHROMECAST_STARBOARD_CAST_API_CAST_STARBOARD_API_H_
+#define CHROMECAST_STARBOARD_CHROMECAST_STARBOARD_CAST_API_CAST_STARBOARD_API_H_
+
+#include <starboard/egl.h>
+#include <starboard/event.h>
+#include <starboard/gles.h>
+#include <starboard/media.h>
+#include <starboard/player.h>
+#include <starboard/window.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*SbEventHandleCB)(const SbEvent*);
+
+// Initializes the Starboard thread and event loop. After this function is
+// called, the Starboard APIs included above are expected to be available.
+//
+// Optional command line arguments are passed through |argc| and |argv|.
+// The |callback| is analogous to SbEventHandle and must receive SbEvents.
+//
+// Must be called prior to the other library functions.
+__attribute__((visibility("default"))) int
+CastStarboardApiInitialize(int argc, char** argv, SbEventHandleCB callback);
+
+// Finalizes the library in the provided |context|.
+//
+// Must not be called prior to the other library functions.
+__attribute__((visibility("default"))) void CastStarboardApiFinalize();
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // CHROMECAST_STARBOARD_CHROMECAST_STARBOARD_CAST_API_CAST_STARBOARD_API_H_
diff --git a/chromecast/starboard/chromecast/starboard_cast_api/cast_starboard_api_types.h b/chromecast/starboard/chromecast/starboard_cast_api/cast_starboard_api_types.h
new file mode 100644
index 0000000..9b6f2dd5
--- /dev/null
+++ b/chromecast/starboard/chromecast/starboard_cast_api/cast_starboard_api_types.h
@@ -0,0 +1,28 @@
+// 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 CHROMECAST_STARBOARD_CHROMECAST_STARBOARD_CAST_API_CAST_STARBOARD_API_TYPES_H_
+#define CHROMECAST_STARBOARD_CHROMECAST_STARBOARD_CAST_API_CAST_STARBOARD_API_TYPES_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// TODO(b/334907387): this enum can likely be removed in favor of a simpler
+// approach to output formats. Either way, this file should be moved out of the
+// starboard_cast_api dir, unless we make it part of a starboard API.
+//
+// Represents a sample format for PCM data to be resampled to. All formats are
+// little endian and interleaved.
+enum StarboardPcmSampleFormat {
+  kStarboardPcmSampleFormatS16,
+  kStarboardPcmSampleFormatS32,
+  kStarboardPcmSampleFormatF32,
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // CHROMECAST_STARBOARD_CHROMECAST_STARBOARD_CAST_API_CAST_STARBOARD_API_TYPES_H_
diff --git a/chromecast/starboard/chromecast/starboard_cast_dummy/BUILD.gn b/chromecast/starboard/chromecast/starboard_cast_dummy/BUILD.gn
new file mode 100644
index 0000000..5788d64
--- /dev/null
+++ b/chromecast/starboard/chromecast/starboard_cast_dummy/BUILD.gn
@@ -0,0 +1,18 @@
+# Copyright 2024 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//chromecast/starboard/starboard.gni")
+
+if (!remove_starboard_headers) {
+  shared_library("cast_starboard_api") {
+    sources = [ "cast_starboard_api_dummy.cc" ]
+    configs += [ "//chromecast/starboard/third_party/starboard/sabi" ]
+    defines = [
+      "STARBOARD_IMPLEMENTATION",
+      "SB_IS_EVERGREEN",
+    ]
+    deps = [ "//chromecast/starboard/chromecast/starboard_cast_api" ]
+    public_deps = [ "//chromecast/starboard/third_party/starboard/public" ]
+  }
+}
diff --git a/chromecast/starboard/chromecast/starboard_cast_dummy/cast_starboard_api_dummy.cc b/chromecast/starboard/chromecast/starboard_cast_dummy/cast_starboard_api_dummy.cc
new file mode 100644
index 0000000..5759e1a7
--- /dev/null
+++ b/chromecast/starboard/chromecast/starboard_cast_dummy/cast_starboard_api_dummy.cc
@@ -0,0 +1,129 @@
+// 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 <starboard/egl.h>
+#include <starboard/event.h>
+#include <starboard/gles.h>
+#include <starboard/player.h>
+#include <starboard/window.h>
+
+#if SB_API_VERSION < 15
+#include <cast_starboard_api.h>
+#endif  // SB_API_VERSION < 15
+
+#if SB_API_VERSION >= 15
+int SbRunStarboardMain(int argc, char** argv, SbEventHandleCallback callback) {
+  SbEvent* fake_start = new SbEvent;
+  fake_start->type = kSbEventTypeStart;
+  callback(fake_start);
+  return 0;
+}
+#else  // SB_API_VERSION >= 15
+int StarboardMain(int argc, char** argv) {
+  return 0;
+}
+
+int CastStarboardApiInitialize(int argc,
+                               char** argv,
+                               SbEventHandleCB callback) {
+  SbEvent* fake_start = new SbEvent;
+  fake_start->type = kSbEventTypeStart;
+  callback(fake_start);
+  return 0;
+}
+
+void CastStarboardApiFinalize() {}
+
+#endif  // SB_API_VERSION >= 15
+
+const SbGlesInterface* SbGetGlesInterface() {
+  return nullptr;
+}
+const SbEglInterface* SbGetEglInterface() {
+  return nullptr;
+}
+
+SbWindow SbWindowCreate(const SbWindowOptions* options) {
+  return nullptr;
+}
+
+void* SbWindowGetPlatformHandle(SbWindow window) {
+  return nullptr;
+}
+
+SbPlayer SbPlayerCreate(
+    SbWindow window,
+    const SbPlayerCreationParam* creation_param,
+    SbPlayerDeallocateSampleFunc sample_deallocate_func,
+    SbPlayerDecoderStatusFunc decoder_status_func,
+    SbPlayerStatusFunc player_status_func,
+    SbPlayerErrorFunc player_error_func,
+    void* context,
+    SbDecodeTargetGraphicsContextProvider* context_provider) {
+  return nullptr;
+}
+
+void SbPlayerSetBounds(SbPlayer player,
+                       int z_index,
+                       int x,
+                       int y,
+                       int width,
+                       int height) {}
+void SbPlayerWriteEndOfStream(SbPlayer player, SbMediaType stream_type) {}
+#if SB_API_VERSION >= 15
+void SbPlayerSeek(SbPlayer player, SbTime seek_to_timestamp, int ticket) {}
+void SbPlayerWriteSamples(SbPlayer player,
+                          SbMediaType sample_type,
+                          const SbPlayerSampleInfo* sample_infos,
+                          int number_of_sample_infos) {}
+void SbPlayerGetInfo(SbPlayer player, SbPlayerInfo* out_player_info2) {}
+#else   // SB_API_VERSION >= 15
+void SbPlayerSeek2(SbPlayer player, SbTime seek_to_timestamp, int ticket) {}
+void SbPlayerWriteSample2(SbPlayer player,
+                          SbMediaType sample_type,
+                          const SbPlayerSampleInfo* sample_infos,
+                          int number_of_sample_infos) {}
+void SbPlayerGetInfo2(SbPlayer player, SbPlayerInfo2* out_player_info2) {}
+#endif  // SB_API_VERSION >= 15
+void SbPlayerSetVolume(SbPlayer player, double volume) {}
+bool SbPlayerSetPlaybackRate(SbPlayer player, double playback_rate) {
+  return false;
+}
+void SbPlayerDestroy(SbPlayer player) {}
+
+SbDrmSystem SbDrmCreateSystem(
+    const char* key_system,
+    void* context,
+    SbDrmSessionUpdateRequestFunc update_request_callback,
+    SbDrmSessionUpdatedFunc session_updated_callback,
+    SbDrmSessionKeyStatusesChangedFunc key_statuses_changed_callback,
+    SbDrmServerCertificateUpdatedFunc server_certificate_updated_callback,
+    SbDrmSessionClosedFunc session_closed_callback) {
+  return kSbDrmSystemInvalid;
+}
+void SbDrmGenerateSessionUpdateRequest(SbDrmSystem drm_system,
+                                       int ticket,
+                                       const char* type,
+                                       const void* initialization_data,
+                                       int initialization_data_size) {}
+void SbDrmUpdateSession(SbDrmSystem drm_system,
+                        int ticket,
+                        const void* key,
+                        int key_size,
+                        const void* session_id,
+                        int session_id_size) {}
+void SbDrmCloseSession(SbDrmSystem drm_system,
+                       const void* session_id,
+                       int session_id_size) {}
+bool SbDrmIsServerCertificateUpdatable(SbDrmSystem drm_system) {
+  return false;
+}
+void SbDrmUpdateServerCertificate(SbDrmSystem drm_system,
+                                  int ticket,
+                                  const void* certificate,
+                                  int certificate_size) {}
+const void* SbDrmGetMetrics(SbDrmSystem drm_system, int* size) {
+  return nullptr;
+}
+void SbDrmDestroySystem(SbDrmSystem drm_system) {}
diff --git a/chromecast/starboard/graphics/BUILD.gn b/chromecast/starboard/graphics/BUILD.gn
new file mode 100644
index 0000000..b0ce02b
--- /dev/null
+++ b/chromecast/starboard/graphics/BUILD.gn
@@ -0,0 +1,63 @@
+# Copyright 2024 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# TODO(b/333131992): remove this, using the real impls instead of dummies.
+import("//chromecast/starboard/starboard.gni")
+shared_library("EGL_starboard") {
+  sources = [ "egl_starboard.h" ]
+  configs += [ "//third_party/khronos:khronos_headers" ]
+
+  deps = []
+  if (remove_starboard_headers) {
+    sources += [ "egl_starboard_dummy.cc" ]
+  } else {
+    sources += [ "egl_starboard.cc" ]
+    configs += [ "//chromecast/starboard/third_party/starboard/sabi" ]
+    deps += [
+      "//chromecast/starboard/chromecast/starboard_cast_dummy:cast_starboard_api",
+      "//chromecast/starboard/third_party/starboard/public",
+    ]
+  }
+}
+
+shared_library("GLES2_starboard") {
+  sources = [ "gles2_starboard.h" ]
+  configs += [ "//third_party/khronos:khronos_headers" ]
+  deps = []
+  if (remove_starboard_headers) {
+    sources += [ "gles2_starboard_dummy.cc" ]
+  } else {
+    sources += [ "gles2_starboard.cc" ]
+    configs += [ "//chromecast/starboard/third_party/starboard/sabi" ]
+    deps += [
+      "//chromecast/starboard/chromecast/starboard_cast_dummy:cast_starboard_api",
+      "//chromecast/starboard/third_party/starboard/public",
+    ]
+  }
+}
+
+source_set("graphics") {
+  sources = [
+    "cast_egl_platform_starboard.cc",
+    "graphics_properties_default.cc",
+  ]
+  deps = [
+    ":EGL_starboard",
+    ":GLES2_starboard",
+    "//chromecast/public",
+    "//chromecast/starboard:starboard_buildflags",
+    "//chromecast/starboard/chromecast/starboard_adapter",
+  ]
+  if (!remove_starboard_headers) {
+    configs += [ "//chromecast/starboard/third_party/starboard/sabi" ]
+    deps += [
+      "//chromecast/starboard/chromecast/starboard_cast_dummy:cast_starboard_api",
+      "//chromecast/starboard/third_party/starboard/public",
+    ]
+  }
+}
+
+shared_library("libcast_graphics_1.0_starboard") {
+  deps = [ ":graphics" ]
+}
diff --git a/chromecast/starboard/graphics/cast_egl_platform_starboard.cc b/chromecast/starboard/graphics/cast_egl_platform_starboard.cc
new file mode 100644
index 0000000..fbd88f1
--- /dev/null
+++ b/chromecast/starboard/graphics/cast_egl_platform_starboard.cc
@@ -0,0 +1,127 @@
+// 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 <dlfcn.h>
+#include <unistd.h>
+
+#include <cassert>
+
+#include "chromecast/public/cast_egl_platform.h"
+#include "chromecast/public/cast_egl_platform_shlib.h"
+#include "chromecast/public/graphics_types.h"
+#include "chromecast/starboard/starboard_buildflags.h"
+
+#if !BUILDFLAG(REMOVE_STARBOARD_HEADERS)
+#include <starboard/window.h>
+
+#include "chromecast/starboard/chromecast/starboard_adapter/public/cast_starboard_api_adapter.h"
+#endif
+
+namespace chromecast {
+namespace {
+
+// TODO(b/333131992): remove [[maybe_unused]] after removing the
+// REMOVE_STARBOARD_HEADERS build flag.
+[[maybe_unused]] constexpr char kGlesLibraryName[] = "libGLES2_starboard.so";
+[[maybe_unused]] constexpr char kEglLibraryName[] = "libEGL_starboard.so";
+
+// Starboard CastEglPlatform implementation.
+class CastEglPlatformStarboard : public CastEglPlatform {
+ public:
+  CastEglPlatformStarboard()
+#if !BUILDFLAG(REMOVE_STARBOARD_HEADERS)
+      : sb_adapter_(CastStarboardApiAdapter::GetInstance())
+#endif
+  {
+  }
+
+  const int* GetEGLSurfaceProperties(const int* desired) override {
+    return desired;
+  }
+
+  ~CastEglPlatformStarboard() override {}
+
+  bool InitializeHardware() override {
+#if BUILDFLAG(REMOVE_STARBOARD_HEADERS)
+    return false;
+#else
+    if (!sb_adapter_->EnsureInitialized()) {
+      return false;
+    }
+    egl_library_ = dlopen(kEglLibraryName, RTLD_NOW | RTLD_LOCAL);
+    gles_library_ = dlopen(kGlesLibraryName, RTLD_NOW | RTLD_LOCAL);
+    if (!egl_library_ || !gles_library_) {
+      return false;
+    }
+
+    get_proc_address_ = reinterpret_cast<GLGetProcAddressProc>(
+        dlsym(egl_library_, "Sb_eglGetProcAddress"));
+
+    if (!get_proc_address_) {
+      return false;
+    }
+    return true;
+#endif
+  }
+
+  void* GetEglLibrary() override { return static_cast<void*>(egl_library_); }
+
+  void* GetGles2Library() override { return static_cast<void*>(gles_library_); }
+
+  GLGetProcAddressProc GetGLProcAddressProc() override {
+    return get_proc_address_;
+  }
+
+  NativeDisplayType CreateDisplayType(const Size& size) override {
+#if BUILDFLAG(REMOVE_STARBOARD_HEADERS)
+    return nullptr;
+#else
+    // TODO(b/334138792): The need to create a window before getting the display
+    // is an implementation detail. Luckily for us, created windows are not
+    // visible and GlOzoneEglCast always couples the call to CreateDisplayType
+    // and CreateWindow, so there is no downside to creating |window_| early.
+    if (!SbWindowIsValid(window_)) {
+      SbWindowOptions options{};
+      options.name = "cast";
+      options.size.width = size.width;
+      options.size.height = size.height;
+      window_ = sb_adapter_->GetWindow(&options);
+    }
+
+    NativeDisplayType ndt = reinterpret_cast<NativeDisplayType>(
+        sb_adapter_->GetEglNativeDisplayType());
+    return ndt;
+#endif
+  }
+
+  NativeWindowType CreateWindow(NativeDisplayType display_type,
+                                const Size& size) override {
+#if BUILDFLAG(REMOVE_STARBOARD_HEADERS)
+    return nullptr;
+#else
+    assert(SbWindowIsValid(window_));
+    auto* result =
+        static_cast<NativeWindowType>(SbWindowGetPlatformHandle(window_));
+
+    return result;
+#endif
+  }
+
+ private:
+  void* egl_library_ = nullptr;
+  void* gles_library_ = nullptr;
+  GLGetProcAddressProc get_proc_address_ = nullptr;
+#if !BUILDFLAG(REMOVE_STARBOARD_HEADERS)
+  SbWindow window_ = nullptr;
+  CastStarboardApiAdapter* sb_adapter_;
+#endif
+};
+}  // namespace
+
+CastEglPlatform* CastEglPlatformShlib::Create(
+    const std::vector<std::string>& argv) {
+  return new CastEglPlatformStarboard();
+}
+
+}  // namespace chromecast
diff --git a/chromecast/starboard/graphics/egl_starboard.cc b/chromecast/starboard/graphics/egl_starboard.cc
new file mode 100644
index 0000000..e70b76b
--- /dev/null
+++ b/chromecast/starboard/graphics/egl_starboard.cc
@@ -0,0 +1,210 @@
+// 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 "chromecast/starboard/graphics/egl_starboard.h"
+
+#include <starboard/egl.h>
+#include <starboard/gles.h>
+#include <stdio.h>
+
+#include <cstdlib>
+
+extern "C" {
+
+EGLBoolean Sb_eglChooseConfig(EGLDisplay dpy,
+                              const EGLint* attrib_list,
+                              EGLConfig* configs,
+                              EGLint config_size,
+                              EGLint* num_config) {
+  return SbGetEglInterface()->eglChooseConfig(dpy, attrib_list, configs,
+                                              config_size, num_config);
+}
+
+EGLBoolean Sb_eglCopyBuffers(EGLDisplay dpy,
+                             EGLSurface surface,
+                             EGLNativePixmapType target) {
+  return SbGetEglInterface()->eglCopyBuffers(dpy, surface, target);
+}
+
+EGLContext Sb_eglCreateContext(EGLDisplay dpy,
+                               EGLConfig config,
+                               EGLContext share_context,
+                               const EGLint* attrib_list) {
+  return SbGetEglInterface()->eglCreateContext(dpy, config, share_context,
+                                               attrib_list);
+}
+
+EGLSurface Sb_eglCreatePbufferSurface(EGLDisplay dpy,
+                                      EGLConfig config,
+                                      const EGLint* attrib_list) {
+  return SbGetEglInterface()->eglCreatePbufferSurface(dpy, config, attrib_list);
+}
+
+EGLSurface Sb_eglCreatePixmapSurface(EGLDisplay dpy,
+                                     EGLConfig config,
+                                     EGLNativePixmapType pixmap,
+                                     const EGLint* attrib_list) {
+  return SbGetEglInterface()->eglCreatePixmapSurface(dpy, config, pixmap,
+                                                     attrib_list);
+}
+
+EGLSurface Sb_eglCreateWindowSurface(EGLDisplay dpy,
+                                     EGLConfig config,
+                                     EGLNativeWindowType win,
+                                     const EGLint* attrib_list) {
+  return SbGetEglInterface()->eglCreateWindowSurface(dpy, config, win,
+                                                     attrib_list);
+}
+
+EGLBoolean Sb_eglDestroyContext(EGLDisplay dpy, EGLContext ctx) {
+  return SbGetEglInterface()->eglDestroyContext(dpy, ctx);
+}
+
+EGLBoolean Sb_eglDestroySurface(EGLDisplay dpy, EGLSurface surface) {
+  return SbGetEglInterface()->eglDestroySurface(dpy, surface);
+}
+
+EGLBoolean Sb_eglGetConfigAttrib(EGLDisplay dpy,
+                                 EGLConfig config,
+                                 EGLint attribute,
+                                 EGLint* value) {
+  return SbGetEglInterface()->eglGetConfigAttrib(dpy, config, attribute, value);
+}
+
+EGLBoolean Sb_eglGetConfigs(EGLDisplay dpy,
+                            EGLConfig* configs,
+                            EGLint config_size,
+                            EGLint* num_config) {
+  return SbGetEglInterface()->eglGetConfigs(dpy, configs, config_size,
+                                            num_config);
+}
+
+EGLDisplay Sb_eglGetCurrentDisplay(void) {
+  return SbGetEglInterface()->eglGetCurrentDisplay();
+}
+
+EGLSurface Sb_eglGetCurrentSurface(EGLint readdraw) {
+  return SbGetEglInterface()->eglGetCurrentSurface(readdraw);
+}
+
+EGLDisplay Sb_eglGetDisplay(EGLNativeDisplayType display_id) {
+  return SbGetEglInterface()->eglGetDisplay(
+      reinterpret_cast<SbEglNativeDisplayType>(display_id));
+}
+
+EGLint Sb_eglGetError(void) {
+  return SbGetEglInterface()->eglGetError();
+}
+
+__eglMustCastToProperFunctionPointerType Sb_eglGetProcAddress(
+    const char* procname) {
+  auto* addr = SbGetEglInterface()->eglGetProcAddress(procname);
+  return addr;
+}
+
+EGLBoolean Sb_eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) {
+  return SbGetEglInterface()->eglInitialize(dpy, major, minor);
+}
+
+EGLBoolean Sb_eglMakeCurrent(EGLDisplay dpy,
+                             EGLSurface draw,
+                             EGLSurface read,
+                             EGLContext ctx) {
+  return SbGetEglInterface()->eglMakeCurrent(dpy, draw, read, ctx);
+}
+
+EGLBoolean Sb_eglQueryContext(EGLDisplay dpy,
+                              EGLContext ctx,
+                              EGLint attribute,
+                              EGLint* value) {
+  return SbGetEglInterface()->eglQueryContext(dpy, ctx, attribute, value);
+}
+
+const char* Sb_eglQueryString(EGLDisplay dpy, EGLint name) {
+  return SbGetEglInterface()->eglQueryString(dpy, name);
+}
+
+EGLBoolean Sb_eglQuerySurface(EGLDisplay dpy,
+                              EGLSurface surface,
+                              EGLint attribute,
+                              EGLint* value) {
+  return SbGetEglInterface()->eglQuerySurface(dpy, surface, attribute, value);
+}
+
+EGLBoolean Sb_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
+  static const char* const cast_quirk_disable_ui =
+      std::getenv("CAST_QUIRK_DISABLE_UI");
+  if (cast_quirk_disable_ui && cast_quirk_disable_ui[0] != '0') {
+    auto* gles = SbGetGlesInterface();
+    gles->glClearColor(0, 0, 0, 0);
+    gles->glClear(SB_GL_COLOR_BUFFER_BIT);
+  }
+  return SbGetEglInterface()->eglSwapBuffers(dpy, surface);
+}
+
+EGLBoolean Sb_eglTerminate(EGLDisplay dpy) {
+  return SbGetEglInterface()->eglTerminate(dpy);
+}
+
+EGLBoolean Sb_eglWaitGL(void) {
+  return SbGetEglInterface()->eglWaitGL();
+}
+
+EGLBoolean Sb_eglWaitNative(EGLint engine) {
+  return SbGetEglInterface()->eglWaitNative(engine);
+}
+
+EGLBoolean Sb_eglBindTexImage(EGLDisplay dpy,
+                              EGLSurface surface,
+                              EGLint buffer) {
+  return SbGetEglInterface()->eglBindTexImage(dpy, surface, buffer);
+}
+
+EGLBoolean Sb_eglReleaseTexImage(EGLDisplay dpy,
+                                 EGLSurface surface,
+                                 EGLint buffer) {
+  return SbGetEglInterface()->eglReleaseTexImage(dpy, surface, buffer);
+}
+
+EGLBoolean Sb_eglSurfaceAttrib(EGLDisplay dpy,
+                               EGLSurface surface,
+                               EGLint attribute,
+                               EGLint value) {
+  return SbGetEglInterface()->eglSurfaceAttrib(dpy, surface, attribute, value);
+}
+
+EGLBoolean Sb_eglSwapInterval(EGLDisplay dpy, EGLint interval) {
+  return SbGetEglInterface()->eglSwapInterval(dpy, interval);
+}
+
+EGLBoolean Sb_eglBindAPI(EGLenum api) {
+  return SbGetEglInterface()->eglBindAPI(api);
+}
+
+EGLenum Sb_eglQueryAPI(void) {
+  return SbGetEglInterface()->eglQueryAPI();
+}
+
+EGLSurface Sb_eglCreatePbufferFromClientBuffer(EGLDisplay dpy,
+                                               EGLenum buftype,
+                                               EGLClientBuffer buffer,
+                                               EGLConfig config,
+                                               const EGLint* attrib_list) {
+  return SbGetEglInterface()->eglCreatePbufferFromClientBuffer(
+      dpy, buftype, buffer, config, attrib_list);
+}
+
+EGLBoolean Sb_eglWaitClient(void) {
+  return SbGetEglInterface()->eglWaitClient();
+}
+
+EGLBoolean Sb_eglReleaseThread(void) {
+  return SbGetEglInterface()->eglReleaseThread();
+}
+
+EGLContext Sb_eglGetCurrentContext(void) {
+  return SbGetEglInterface()->eglGetCurrentContext();
+}
+
+}  // extern "C"
diff --git a/chromecast/starboard/graphics/egl_starboard.h b/chromecast/starboard/graphics/egl_starboard.h
new file mode 100644
index 0000000..2589a556
--- /dev/null
+++ b/chromecast/starboard/graphics/egl_starboard.h
@@ -0,0 +1,160 @@
+// 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 CHROMECAST_STARBOARD_GRAPHICS_EGL_STARBOARD_H_
+#define CHROMECAST_STARBOARD_GRAPHICS_EGL_STARBOARD_H_
+
+#include <EGL/egl.h>
+
+extern "C" {
+
+// egl 1.0
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglChooseConfig(
+    EGLDisplay dpy,
+    const EGLint* attrib_list,
+    EGLConfig* configs,
+    EGLint config_size,
+    EGLint* num_config);
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglCopyBuffers(
+    EGLDisplay dpy,
+    EGLSurface surface,
+    EGLNativePixmapType target);
+
+__attribute__((visibility("default"))) EGLContext Sb_eglCreateContext(
+    EGLDisplay dpy,
+    EGLConfig config,
+    EGLContext share_context,
+    const EGLint* attrib_list);
+
+__attribute__((visibility("default"))) EGLSurface Sb_eglCreatePbufferSurface(
+    EGLDisplay dpy,
+    EGLConfig config,
+    const EGLint* attrib_list);
+
+__attribute__((visibility("default"))) EGLSurface Sb_eglCreatePixmapSurface(
+    EGLDisplay dpy,
+    EGLConfig config,
+    EGLNativePixmapType pixmap,
+    const EGLint* attrib_list);
+
+__attribute__((visibility("default"))) EGLSurface Sb_eglCreateWindowSurface(
+    EGLDisplay dpy,
+    EGLConfig config,
+    EGLNativeWindowType win,
+    const EGLint* attrib_list);
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglDestroyContext(
+    EGLDisplay dpy,
+    EGLContext ctx);
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglDestroySurface(
+    EGLDisplay dpy,
+    EGLSurface surface);
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglGetConfigAttrib(
+    EGLDisplay dpy,
+    EGLConfig config,
+    EGLint attribute,
+    EGLint* value);
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglGetConfigs(
+    EGLDisplay dpy,
+    EGLConfig* configs,
+    EGLint config_size,
+    EGLint* num_config);
+
+__attribute__((visibility("default"))) EGLDisplay Sb_eglGetCurrentDisplay(void);
+
+__attribute__((visibility("default"))) EGLSurface Sb_eglGetCurrentSurface(
+    EGLint readdraw);
+
+__attribute__((visibility("default"))) EGLDisplay Sb_eglGetDisplay(
+    EGLNativeDisplayType display_id);
+
+__attribute__((visibility("default"))) __eglMustCastToProperFunctionPointerType
+Sb_eglGetProcAddress(const char* procname);
+
+__attribute__((visibility("default"))) EGLBoolean
+Sb_eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor);
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglMakeCurrent(
+    EGLDisplay dpy,
+    EGLSurface draw,
+    EGLSurface read,
+    EGLContext ctx);
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglQueryContext(
+    EGLDisplay dpy,
+    EGLContext ctx,
+    EGLint attribute,
+    EGLint* value);
+
+__attribute__((visibility("default"))) const char* Sb_eglQueryString(
+    EGLDisplay dpy,
+    EGLint name);
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglQuerySurface(
+    EGLDisplay dpy,
+    EGLSurface surface,
+    EGLint attribute,
+    EGLint* value);
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglSwapBuffers(
+    EGLDisplay dpy,
+    EGLSurface surface);
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglTerminate(
+    EGLDisplay dpy);
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglWaitGL(void);
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglWaitNative(
+    EGLint engine);
+
+// egl 1.1
+
+__attribute__((visibility("default"))) EGLBoolean
+Sb_eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+
+__attribute__((visibility("default"))) EGLBoolean
+Sb_eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglSurfaceAttrib(
+    EGLDisplay dpy,
+    EGLSurface surface,
+    EGLint attribute,
+    EGLint value);
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglSwapInterval(
+    EGLDisplay dpy,
+    EGLint interval);
+
+// egl 1.2
+__attribute__((visibility("default"))) EGLBoolean Sb_eglBindAPI(EGLenum api);
+
+__attribute__((visibility("default"))) EGLenum Sb_eglQueryAPI(void);
+
+__attribute__((visibility("default"))) EGLSurface
+Sb_eglCreatePbufferFromClientBuffer(EGLDisplay dpy,
+                                    EGLenum buftype,
+                                    EGLClientBuffer buffer,
+                                    EGLConfig config,
+                                    const EGLint* attrib_list);
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglReleaseThread(void);
+
+__attribute__((visibility("default"))) EGLBoolean Sb_eglWaitClient(void);
+
+// egl 1.3
+// does not define new function prototypes.
+
+// egl 1.4
+
+__attribute__((visibility("default"))) EGLContext Sb_eglGetCurrentContext(void);
+
+}  // extern "C"
+
+#endif  // CHROMECAST_STARBOARD_GRAPHICS_EGL_STARBOARD_H_
diff --git a/chromecast/starboard/graphics/egl_starboard_dummy.cc b/chromecast/starboard/graphics/egl_starboard_dummy.cc
new file mode 100644
index 0000000..632eda4
--- /dev/null
+++ b/chromecast/starboard/graphics/egl_starboard_dummy.cc
@@ -0,0 +1,194 @@
+// 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.
+
+// A dummy implementation of egl_starboard.h. This can be used to compile
+// without starboard headers. It should never be used in production.
+//
+// TODO(b/333131992): remove this
+
+#include "chromecast/starboard/graphics/egl_starboard.h"
+
+extern "C" {
+
+EGLBoolean Sb_eglChooseConfig(EGLDisplay dpy,
+                              const EGLint* attrib_list,
+                              EGLConfig* configs,
+                              EGLint config_size,
+                              EGLint* num_config) {
+  return 0;
+}
+
+EGLBoolean Sb_eglCopyBuffers(EGLDisplay dpy,
+                             EGLSurface surface,
+                             EGLNativePixmapType target) {
+  return 0;
+}
+
+EGLContext Sb_eglCreateContext(EGLDisplay dpy,
+                               EGLConfig config,
+                               EGLContext share_context,
+                               const EGLint* attrib_list) {
+  return nullptr;
+}
+
+EGLSurface Sb_eglCreatePbufferSurface(EGLDisplay dpy,
+                                      EGLConfig config,
+                                      const EGLint* attrib_list) {
+  return nullptr;
+}
+
+EGLSurface Sb_eglCreatePixmapSurface(EGLDisplay dpy,
+                                     EGLConfig config,
+                                     EGLNativePixmapType pixmap,
+                                     const EGLint* attrib_list) {
+  return nullptr;
+}
+
+EGLSurface Sb_eglCreateWindowSurface(EGLDisplay dpy,
+                                     EGLConfig config,
+                                     EGLNativeWindowType win,
+                                     const EGLint* attrib_list) {
+  return nullptr;
+}
+
+EGLBoolean Sb_eglDestroyContext(EGLDisplay dpy, EGLContext ctx) {
+  return 0;
+}
+
+EGLBoolean Sb_eglDestroySurface(EGLDisplay dpy, EGLSurface surface) {
+  return 0;
+}
+
+EGLBoolean Sb_eglGetConfigAttrib(EGLDisplay dpy,
+                                 EGLConfig config,
+                                 EGLint attribute,
+                                 EGLint* value) {
+  return 0;
+}
+
+EGLBoolean Sb_eglGetConfigs(EGLDisplay dpy,
+                            EGLConfig* configs,
+                            EGLint config_size,
+                            EGLint* num_config) {
+  return 0;
+}
+
+EGLDisplay Sb_eglGetCurrentDisplay(void) {
+  return nullptr;
+}
+
+EGLSurface Sb_eglGetCurrentSurface(EGLint readdraw) {
+  return nullptr;
+}
+
+EGLDisplay Sb_eglGetDisplay(EGLNativeDisplayType display_id) {
+  return nullptr;
+}
+
+EGLint Sb_eglGetError(void) {
+  return 0;
+}
+
+__eglMustCastToProperFunctionPointerType Sb_eglGetProcAddress(
+    const char* procname) {
+  return nullptr;
+}
+
+EGLBoolean Sb_eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) {
+  return 0;
+}
+
+EGLBoolean Sb_eglMakeCurrent(EGLDisplay dpy,
+                             EGLSurface draw,
+                             EGLSurface read,
+                             EGLContext ctx) {
+  return 0;
+}
+
+EGLBoolean Sb_eglQueryContext(EGLDisplay dpy,
+                              EGLContext ctx,
+                              EGLint attribute,
+                              EGLint* value) {
+  return 0;
+}
+
+const char* Sb_eglQueryString(EGLDisplay dpy, EGLint name) {
+  return "";
+}
+
+EGLBoolean Sb_eglQuerySurface(EGLDisplay dpy,
+                              EGLSurface surface,
+                              EGLint attribute,
+                              EGLint* value) {
+  return 0;
+}
+
+EGLBoolean Sb_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
+  return 0;
+}
+
+EGLBoolean Sb_eglTerminate(EGLDisplay dpy) {
+  return 0;
+}
+
+EGLBoolean Sb_eglWaitGL(void) {
+  return 0;
+}
+
+EGLBoolean Sb_eglWaitNative(EGLint engine) {
+  return 0;
+}
+
+EGLBoolean Sb_eglBindTexImage(EGLDisplay dpy,
+                              EGLSurface surface,
+                              EGLint buffer) {
+  return 0;
+}
+
+EGLBoolean Sb_eglReleaseTexImage(EGLDisplay dpy,
+                                 EGLSurface surface,
+                                 EGLint buffer) {
+  return 0;
+}
+
+EGLBoolean Sb_eglSurfaceAttrib(EGLDisplay dpy,
+                               EGLSurface surface,
+                               EGLint attribute,
+                               EGLint value) {
+  return 0;
+}
+
+EGLBoolean Sb_eglSwapInterval(EGLDisplay dpy, EGLint interval) {
+  return 0;
+}
+
+EGLBoolean Sb_eglBindAPI(EGLenum api) {
+  return 0;
+}
+
+EGLenum Sb_eglQueryAPI(void) {
+  return 0;
+}
+
+EGLSurface Sb_eglCreatePbufferFromClientBuffer(EGLDisplay dpy,
+                                               EGLenum buftype,
+                                               EGLClientBuffer buffer,
+                                               EGLConfig config,
+                                               const EGLint* attrib_list) {
+  return nullptr;
+}
+
+EGLBoolean Sb_eglWaitClient(void) {
+  return 0;
+}
+
+EGLBoolean Sb_eglReleaseThread(void) {
+  return 0;
+}
+
+EGLContext Sb_eglGetCurrentContext(void) {
+  return nullptr;
+}
+
+}  // extern "C"
diff --git a/chromecast/starboard/graphics/gles2_starboard.cc b/chromecast/starboard/graphics/gles2_starboard.cc
new file mode 100644
index 0000000..75864f48
--- /dev/null
+++ b/chromecast/starboard/graphics/gles2_starboard.cc
@@ -0,0 +1,856 @@
+// 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 "chromecast/starboard/graphics/gles2_starboard.h"
+
+#include <starboard/gles.h>
+
+extern "C" {
+
+// gl2.h
+
+GL_APICALL void GL_APIENTRY Sb_glActiveTexture(GLenum texture) {
+  return SbGetGlesInterface()->glActiveTexture(texture);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glAttachShader(GLuint program, GLuint shader) {
+  return SbGetGlesInterface()->glAttachShader(program, shader);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glBindAttribLocation(GLuint program,
+                                                    GLuint index,
+                                                    const GLchar* name) {
+  return SbGetGlesInterface()->glBindAttribLocation(program, index, name);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glBindBuffer(GLenum target, GLuint buffer) {
+  return SbGetGlesInterface()->glBindBuffer(target, buffer);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glBindFramebuffer(GLenum target,
+                                                 GLuint framebuffer) {
+  return SbGetGlesInterface()->glBindFramebuffer(target, framebuffer);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glBindRenderbuffer(GLenum target,
+                                                  GLuint renderbuffer) {
+  return SbGetGlesInterface()->glBindRenderbuffer(target, renderbuffer);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glBindTexture(GLenum target, GLuint texture) {
+  return SbGetGlesInterface()->glBindTexture(target, texture);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glBlendColor(GLfloat red,
+                                            GLfloat green,
+                                            GLfloat blue,
+                                            GLfloat alpha) {
+  return SbGetGlesInterface()->glBlendColor(red, green, blue, alpha);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glBlendEquation(GLenum mode) {
+  return SbGetGlesInterface()->glBlendEquation(mode);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glBlendEquationSeparate(GLenum modeRGB,
+                                                       GLenum modeAlpha) {
+  return SbGetGlesInterface()->glBlendEquationSeparate(modeRGB, modeAlpha);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glBlendFunc(GLenum sfactor, GLenum dfactor) {
+  return SbGetGlesInterface()->glBlendFunc(sfactor, dfactor);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glBlendFuncSeparate(GLenum sfactorRGB,
+                                                   GLenum dfactorRGB,
+                                                   GLenum sfactorAlpha,
+                                                   GLenum dfactorAlpha) {
+  return SbGetGlesInterface()->glBlendFuncSeparate(sfactorRGB, dfactorRGB,
+                                                   sfactorAlpha, dfactorAlpha);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glBufferData(GLenum target,
+                                            GLsizeiptr size,
+                                            const void* data,
+                                            GLenum usage) {
+  return SbGetGlesInterface()->glBufferData(target, size, data, usage);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glBufferSubData(GLenum target,
+                                               GLintptr offset,
+                                               GLsizeiptr size,
+                                               const void* data) {
+  return SbGetGlesInterface()->glBufferSubData(target, offset, size, data);
+}
+
+GL_APICALL GLenum GL_APIENTRY Sb_glCheckFramebufferStatus(GLenum target) {
+  return SbGetGlesInterface()->glCheckFramebufferStatus(target);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glClear(GLbitfield mask) {
+  return SbGetGlesInterface()->glClear(mask);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glClearColor(GLfloat red,
+                                            GLfloat green,
+                                            GLfloat blue,
+                                            GLfloat alpha) {
+  // TODO(rknichols):
+  // When casting, the UI overlay is rendered on top of the video frame.
+  // We must use punch through to display the video frame underneath, thus
+  // the alpha when displaying videos must be 0.f.
+  // However, sourcing the location in chromium's code that sets us to (0,0,0,1)
+  // is proving difficult. the last breadcrumb has been:
+  // `cc/layers/recording_source.cc:DetermineIfSolidColor`
+  // if `solid_color_` is set at the end of the function, to 0 then we observe
+  // the expected output. Where the originating `black` layer comes from is
+  // unclear.
+  //
+  // Remove the force set of alpha to 0.f when the above comment has been
+  // resolved.
+  return SbGetGlesInterface()->glClearColor(red, green, blue, 0.f);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glClearDepthf(GLfloat d) {
+  return SbGetGlesInterface()->glClearDepthf(d);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glClearStencil(GLint s) {
+  return SbGetGlesInterface()->glClearStencil(s);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glColorMask(GLboolean red,
+                                           GLboolean green,
+                                           GLboolean blue,
+                                           GLboolean alpha) {
+  return SbGetGlesInterface()->glColorMask(red, green, blue, alpha);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glCompileShader(GLuint shader) {
+  return SbGetGlesInterface()->glCompileShader(shader);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glCompressedTexImage2D(GLenum target,
+                                                      GLint level,
+                                                      GLenum internalformat,
+                                                      GLsizei width,
+                                                      GLsizei height,
+                                                      GLint border,
+                                                      GLsizei imageSize,
+                                                      const void* data) {
+  return SbGetGlesInterface()->glCompressedTexImage2D(
+      target, level, internalformat, width, height, border, imageSize, data);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glCompressedTexSubImage2D(GLenum target,
+                                                         GLint level,
+                                                         GLint xoffset,
+                                                         GLint yoffset,
+                                                         GLsizei width,
+                                                         GLsizei height,
+                                                         GLenum format,
+                                                         GLsizei imageSize,
+                                                         const void* data) {
+  return SbGetGlesInterface()->glCompressedTexSubImage2D(
+      target, level, xoffset, yoffset, width, height, format, imageSize, data);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glCopyTexImage2D(GLenum target,
+                                                GLint level,
+                                                GLenum internalformat,
+                                                GLint x,
+                                                GLint y,
+                                                GLsizei width,
+                                                GLsizei height,
+                                                GLint border) {
+  return SbGetGlesInterface()->glCopyTexImage2D(target, level, internalformat,
+                                                x, y, width, height, border);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glCopyTexSubImage2D(GLenum target,
+                                                   GLint level,
+                                                   GLint xoffset,
+                                                   GLint yoffset,
+                                                   GLint x,
+                                                   GLint y,
+                                                   GLsizei width,
+                                                   GLsizei height) {
+  return SbGetGlesInterface()->glCopyTexSubImage2D(
+      target, level, xoffset, yoffset, x, y, width, height);
+}
+
+GL_APICALL GLuint GL_APIENTRY Sb_glCreateProgram(void) {
+  return SbGetGlesInterface()->glCreateProgram();
+}
+
+GL_APICALL GLuint GL_APIENTRY Sb_glCreateShader(GLenum type) {
+  return SbGetGlesInterface()->glCreateShader(type);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glCullFace(GLenum mode) {
+  return SbGetGlesInterface()->glCullFace(mode);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glDeleteBuffers(GLsizei n,
+                                               const GLuint* buffers) {
+  return SbGetGlesInterface()->glDeleteBuffers(n, buffers);
+}
+
+GL_APICALL void GL_APIENTRY
+Sb_glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) {
+  return SbGetGlesInterface()->glDeleteFramebuffers(n, framebuffers);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glDeleteProgram(GLuint program) {
+  return SbGetGlesInterface()->glDeleteProgram(program);
+}
+
+GL_APICALL void GL_APIENTRY
+Sb_glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) {
+  return SbGetGlesInterface()->glDeleteRenderbuffers(n, renderbuffers);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glDeleteShader(GLuint shader) {
+  return SbGetGlesInterface()->glDeleteShader(shader);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glDeleteTextures(GLsizei n,
+                                                const GLuint* textures) {
+  return SbGetGlesInterface()->glDeleteTextures(n, textures);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glDepthFunc(GLenum func) {
+  return SbGetGlesInterface()->glDepthFunc(func);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glDepthMask(GLboolean flag) {
+  return SbGetGlesInterface()->glDepthMask(flag);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glDepthRangef(GLfloat n, GLfloat f) {
+  return SbGetGlesInterface()->glDepthRangef(n, f);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glDetachShader(GLuint program, GLuint shader) {
+  return SbGetGlesInterface()->glDetachShader(program, shader);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glDisable(GLenum cap) {
+  return SbGetGlesInterface()->glDisable(cap);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glDisableVertexAttribArray(GLuint index) {
+  return SbGetGlesInterface()->glDisableVertexAttribArray(index);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glDrawArrays(GLenum mode,
+                                            GLint first,
+                                            GLsizei count) {
+  return SbGetGlesInterface()->glDrawArrays(mode, first, count);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glDrawElements(GLenum mode,
+                                              GLsizei count,
+                                              GLenum type,
+                                              const void* indices) {
+  return SbGetGlesInterface()->glDrawElements(mode, count, type, indices);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glEnable(GLenum cap) {
+  return SbGetGlesInterface()->glEnable(cap);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glEnableVertexAttribArray(GLuint index) {
+  return SbGetGlesInterface()->glEnableVertexAttribArray(index);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glFinish(void) {
+  return SbGetGlesInterface()->glFinish();
+}
+
+GL_APICALL void GL_APIENTRY Sb_glFlush(void) {
+  return SbGetGlesInterface()->glFlush();
+}
+
+GL_APICALL void GL_APIENTRY
+Sb_glFramebufferRenderbuffer(GLenum target,
+                             GLenum attachment,
+                             GLenum renderbuffertarget,
+                             GLuint renderbuffer) {
+  return SbGetGlesInterface()->glFramebufferRenderbuffer(
+      target, attachment, renderbuffertarget, renderbuffer);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glFramebufferTexture2D(GLenum target,
+                                                      GLenum attachment,
+                                                      GLenum textarget,
+                                                      GLuint texture,
+                                                      GLint level) {
+  return SbGetGlesInterface()->glFramebufferTexture2D(
+      target, attachment, textarget, texture, level);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glFrontFace(GLenum mode) {
+  return SbGetGlesInterface()->glFrontFace(mode);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGenBuffers(GLsizei n, GLuint* buffers) {
+  return SbGetGlesInterface()->glGenBuffers(n, buffers);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGenerateMipmap(GLenum target) {
+  return SbGetGlesInterface()->glGenerateMipmap(target);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGenFramebuffers(GLsizei n,
+                                                 GLuint* framebuffers) {
+  return SbGetGlesInterface()->glGenFramebuffers(n, framebuffers);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGenRenderbuffers(GLsizei n,
+                                                  GLuint* renderbuffers) {
+  return SbGetGlesInterface()->glGenRenderbuffers(n, renderbuffers);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGenTextures(GLsizei n, GLuint* textures) {
+  return SbGetGlesInterface()->glGenTextures(n, textures);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetActiveAttrib(GLuint program,
+                                                 GLuint index,
+                                                 GLsizei bufSize,
+                                                 GLsizei* length,
+                                                 GLint* size,
+                                                 GLenum* type,
+                                                 GLchar* name) {
+  return SbGetGlesInterface()->glGetActiveAttrib(program, index, bufSize,
+                                                 length, size, type, name);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetActiveUniform(GLuint program,
+                                                  GLuint index,
+                                                  GLsizei bufSize,
+                                                  GLsizei* length,
+                                                  GLint* size,
+                                                  GLenum* type,
+                                                  GLchar* name) {
+  return SbGetGlesInterface()->glGetActiveUniform(program, index, bufSize,
+                                                  length, size, type, name);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetAttachedShaders(GLuint program,
+                                                    GLsizei maxCount,
+                                                    GLsizei* count,
+                                                    GLuint* shaders) {
+  return SbGetGlesInterface()->glGetAttachedShaders(program, maxCount, count,
+                                                    shaders);
+}
+
+GL_APICALL GLint GL_APIENTRY Sb_glGetAttribLocation(GLuint program,
+                                                    const GLchar* name) {
+  return SbGetGlesInterface()->glGetAttribLocation(program, name);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetBooleanv(GLenum pname, GLboolean* data) {
+  return SbGetGlesInterface()->glGetBooleanv(pname, data);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetBufferParameteriv(GLenum target,
+                                                      GLenum pname,
+                                                      GLint* params) {
+  return SbGetGlesInterface()->glGetBufferParameteriv(target, pname, params);
+}
+
+GL_APICALL GLenum GL_APIENTRY Sb_glGetError(void) {
+  return SbGetGlesInterface()->glGetError();
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetFloatv(GLenum pname, GLfloat* data) {
+  return SbGetGlesInterface()->glGetFloatv(pname, data);
+}
+
+GL_APICALL void GL_APIENTRY
+Sb_glGetFramebufferAttachmentParameteriv(GLenum target,
+                                         GLenum attachment,
+                                         GLenum pname,
+                                         GLint* params) {
+  return SbGetGlesInterface()->glGetFramebufferAttachmentParameteriv(
+      target, attachment, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetIntegerv(GLenum pname, GLint* data) {
+  return SbGetGlesInterface()->glGetIntegerv(pname, data);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetProgramiv(GLuint program,
+                                              GLenum pname,
+                                              GLint* params) {
+  return SbGetGlesInterface()->glGetProgramiv(program, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetProgramInfoLog(GLuint program,
+                                                   GLsizei bufSize,
+                                                   GLsizei* length,
+                                                   GLchar* infoLog) {
+  return SbGetGlesInterface()->glGetProgramInfoLog(program, bufSize, length,
+                                                   infoLog);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetRenderbufferParameteriv(GLenum target,
+                                                            GLenum pname,
+                                                            GLint* params) {
+  return SbGetGlesInterface()->glGetRenderbufferParameteriv(target, pname,
+                                                            params);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetShaderiv(GLuint shader,
+                                             GLenum pname,
+                                             GLint* params) {
+  return SbGetGlesInterface()->glGetShaderiv(shader, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetShaderInfoLog(GLuint shader,
+                                                  GLsizei bufSize,
+                                                  GLsizei* length,
+                                                  GLchar* infoLog) {
+  return SbGetGlesInterface()->glGetShaderInfoLog(shader, bufSize, length,
+                                                  infoLog);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetShaderPrecisionFormat(GLenum shadertype,
+                                                          GLenum precisiontype,
+                                                          GLint* range,
+                                                          GLint* precision) {
+  return SbGetGlesInterface()->glGetShaderPrecisionFormat(
+      shadertype, precisiontype, range, precision);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetShaderSource(GLuint shader,
+                                                 GLsizei bufSize,
+                                                 GLsizei* length,
+                                                 GLchar* source) {
+  return SbGetGlesInterface()->glGetShaderSource(shader, bufSize, length,
+                                                 source);
+}
+
+GL_APICALL const GLubyte* GL_APIENTRY Sb_glGetString(GLenum name) {
+  static const unsigned char opengl_es_2_str[] = "OpenGL ES 2.0";
+
+  const GLubyte* result = SbGetGlesInterface()->glGetString(name);
+  return (result && name == SB_GL_VERSION) ? opengl_es_2_str : result;
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetTexParameterfv(GLenum target,
+                                                   GLenum pname,
+                                                   GLfloat* params) {
+  return SbGetGlesInterface()->glGetTexParameterfv(target, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetTexParameteriv(GLenum target,
+                                                   GLenum pname,
+                                                   GLint* params) {
+  return SbGetGlesInterface()->glGetTexParameteriv(target, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetUniformfv(GLuint program,
+                                              GLint location,
+                                              GLfloat* params) {
+  return SbGetGlesInterface()->glGetUniformfv(program, location, params);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetUniformiv(GLuint program,
+                                              GLint location,
+                                              GLint* params) {
+  return SbGetGlesInterface()->glGetUniformiv(program, location, params);
+}
+
+GL_APICALL GLint GL_APIENTRY Sb_glGetUniformLocation(GLuint program,
+                                                     const GLchar* name) {
+  return SbGetGlesInterface()->glGetUniformLocation(program, name);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetVertexAttribfv(GLuint index,
+                                                   GLenum pname,
+                                                   GLfloat* params) {
+  return SbGetGlesInterface()->glGetVertexAttribfv(index, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetVertexAttribiv(GLuint index,
+                                                   GLenum pname,
+                                                   GLint* params) {
+  return SbGetGlesInterface()->glGetVertexAttribiv(index, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetVertexAttribPointerv(GLuint index,
+                                                         GLenum pname,
+                                                         void** pointer) {
+  return SbGetGlesInterface()->glGetVertexAttribPointerv(index, pname, pointer);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glHint(GLenum target, GLenum mode) {
+  return SbGetGlesInterface()->glHint(target, mode);
+}
+
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsBuffer(GLuint buffer) {
+  return SbGetGlesInterface()->glIsBuffer(buffer);
+}
+
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsEnabled(GLenum cap) {
+  return SbGetGlesInterface()->glIsEnabled(cap);
+}
+
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsFramebuffer(GLuint framebuffer) {
+  return SbGetGlesInterface()->glIsFramebuffer(framebuffer);
+}
+
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsProgram(GLuint program) {
+  return SbGetGlesInterface()->glIsProgram(program);
+}
+
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsRenderbuffer(GLuint renderbuffer) {
+  return SbGetGlesInterface()->glIsRenderbuffer(renderbuffer);
+}
+
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsShader(GLuint shader) {
+  return SbGetGlesInterface()->glIsShader(shader);
+}
+
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsTexture(GLuint texture) {
+  return SbGetGlesInterface()->glIsTexture(texture);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glLineWidth(GLfloat width) {
+  return SbGetGlesInterface()->glLineWidth(width);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glLinkProgram(GLuint program) {
+  return SbGetGlesInterface()->glLinkProgram(program);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glPixelStorei(GLenum pname, GLint param) {
+  return SbGetGlesInterface()->glPixelStorei(pname, param);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glPolygonOffset(GLfloat factor, GLfloat units) {
+  return SbGetGlesInterface()->glPolygonOffset(factor, units);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glReadPixels(GLint x,
+                                            GLint y,
+                                            GLsizei width,
+                                            GLsizei height,
+                                            GLenum format,
+                                            GLenum type,
+                                            void* pixels) {
+  return SbGetGlesInterface()->glReadPixels(x, y, width, height, format, type,
+                                            pixels);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glReleaseShaderCompiler(void) {
+  return SbGetGlesInterface()->glReleaseShaderCompiler();
+}
+
+GL_APICALL void GL_APIENTRY Sb_glRenderbufferStorage(GLenum target,
+                                                     GLenum internalformat,
+                                                     GLsizei width,
+                                                     GLsizei height) {
+  return SbGetGlesInterface()->glRenderbufferStorage(target, internalformat,
+                                                     width, height);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glSampleCoverage(GLfloat value,
+                                                GLboolean invert) {
+  return SbGetGlesInterface()->glSampleCoverage(value, invert);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glScissor(GLint x,
+                                         GLint y,
+                                         GLsizei width,
+                                         GLsizei height) {
+  return SbGetGlesInterface()->glScissor(x, y, width, height);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glShaderBinary(GLsizei count,
+                                              const GLuint* shaders,
+                                              GLenum binaryformat,
+                                              const void* binary,
+                                              GLsizei length) {
+  return SbGetGlesInterface()->glShaderBinary(count, shaders, binaryformat,
+                                              binary, length);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glShaderSource(GLuint shader,
+                                              GLsizei count,
+                                              const GLchar* const* string,
+                                              const GLint* length) {
+  return SbGetGlesInterface()->glShaderSource(shader, count, string, length);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glStencilFunc(GLenum func,
+                                             GLint ref,
+                                             GLuint mask) {
+  return SbGetGlesInterface()->glStencilFunc(func, ref, mask);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glStencilFuncSeparate(GLenum face,
+                                                     GLenum func,
+                                                     GLint ref,
+                                                     GLuint mask) {
+  return SbGetGlesInterface()->glStencilFuncSeparate(face, func, ref, mask);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glStencilMask(GLuint mask) {
+  return SbGetGlesInterface()->glStencilMask(mask);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glStencilMaskSeparate(GLenum face, GLuint mask) {
+  return SbGetGlesInterface()->glStencilMaskSeparate(face, mask);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glStencilOp(GLenum fail,
+                                           GLenum zfail,
+                                           GLenum zpass) {
+  return SbGetGlesInterface()->glStencilOp(fail, zfail, zpass);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glStencilOpSeparate(GLenum face,
+                                                   GLenum sfail,
+                                                   GLenum dpfail,
+                                                   GLenum dppass) {
+  return SbGetGlesInterface()->glStencilOpSeparate(face, sfail, dpfail, dppass);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glTexImage2D(GLenum target,
+                                            GLint level,
+                                            GLint internalformat,
+                                            GLsizei width,
+                                            GLsizei height,
+                                            GLint border,
+                                            GLenum format,
+                                            GLenum type,
+                                            const void* pixels) {
+  return SbGetGlesInterface()->glTexImage2D(target, level, internalformat,
+                                            width, height, border, format, type,
+                                            pixels);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glTexParameterf(GLenum target,
+                                               GLenum pname,
+                                               GLfloat param) {
+  return SbGetGlesInterface()->glTexParameterf(target, pname, param);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glTexParameterfv(GLenum target,
+                                                GLenum pname,
+                                                const GLfloat* params) {
+  return SbGetGlesInterface()->glTexParameterfv(target, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glTexParameteri(GLenum target,
+                                               GLenum pname,
+                                               GLint param) {
+  return SbGetGlesInterface()->glTexParameteri(target, pname, param);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glTexParameteriv(GLenum target,
+                                                GLenum pname,
+                                                const GLint* params) {
+  return SbGetGlesInterface()->glTexParameteriv(target, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glTexSubImage2D(GLenum target,
+                                               GLint level,
+                                               GLint xoffset,
+                                               GLint yoffset,
+                                               GLsizei width,
+                                               GLsizei height,
+                                               GLenum format,
+                                               GLenum type,
+                                               const void* pixels) {
+  return SbGetGlesInterface()->glTexSubImage2D(
+      target, level, xoffset, yoffset, width, height, format, type, pixels);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform1f(GLint location, GLfloat v0) {
+  return SbGetGlesInterface()->glUniform1f(location, v0);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform1fv(GLint location,
+                                            GLsizei count,
+                                            const GLfloat* value) {
+  return SbGetGlesInterface()->glUniform1fv(location, count, value);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform1i(GLint location, GLint v0) {
+  return SbGetGlesInterface()->glUniform1i(location, v0);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform1iv(GLint location,
+                                            GLsizei count,
+                                            const GLint* value) {
+  return SbGetGlesInterface()->glUniform1iv(location, count, value);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform2f(GLint location,
+                                           GLfloat v0,
+                                           GLfloat v1) {
+  return SbGetGlesInterface()->glUniform2f(location, v0, v1);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform2fv(GLint location,
+                                            GLsizei count,
+                                            const GLfloat* value) {
+  return SbGetGlesInterface()->glUniform2fv(location, count, value);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform2i(GLint location, GLint v0, GLint v1) {
+  return SbGetGlesInterface()->glUniform2i(location, v0, v1);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform2iv(GLint location,
+                                            GLsizei count,
+                                            const GLint* value) {
+  return SbGetGlesInterface()->glUniform2iv(location, count, value);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform3f(GLint location,
+                                           GLfloat v0,
+                                           GLfloat v1,
+                                           GLfloat v2) {
+  return SbGetGlesInterface()->glUniform3f(location, v0, v1, v2);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform3fv(GLint location,
+                                            GLsizei count,
+                                            const GLfloat* value) {
+  return SbGetGlesInterface()->glUniform3fv(location, count, value);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform3i(GLint location,
+                                           GLint v0,
+                                           GLint v1,
+                                           GLint v2) {
+  return SbGetGlesInterface()->glUniform3i(location, v0, v1, v2);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform3iv(GLint location,
+                                            GLsizei count,
+                                            const GLint* value) {
+  return SbGetGlesInterface()->glUniform3iv(location, count, value);
+}
+
+GL_APICALL void GL_APIENTRY
+Sb_glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {
+  return SbGetGlesInterface()->glUniform4f(location, v0, v1, v2, v3);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform4fv(GLint location,
+                                            GLsizei count,
+                                            const GLfloat* value) {
+  return SbGetGlesInterface()->glUniform4fv(location, count, value);
+}
+
+GL_APICALL void GL_APIENTRY
+Sb_glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {
+  return SbGetGlesInterface()->glUniform4i(location, v0, v1, v2, v3);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform4iv(GLint location,
+                                            GLsizei count,
+                                            const GLint* value) {
+  return SbGetGlesInterface()->glUniform4iv(location, count, value);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniformMatrix2fv(GLint location,
+                                                  GLsizei count,
+                                                  GLboolean transpose,
+                                                  const GLfloat* value) {
+  return SbGetGlesInterface()->glUniformMatrix2fv(location, count, transpose,
+                                                  value);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniformMatrix3fv(GLint location,
+                                                  GLsizei count,
+                                                  GLboolean transpose,
+                                                  const GLfloat* value) {
+  return SbGetGlesInterface()->glUniformMatrix3fv(location, count, transpose,
+                                                  value);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniformMatrix4fv(GLint location,
+                                                  GLsizei count,
+                                                  GLboolean transpose,
+                                                  const GLfloat* value) {
+  return SbGetGlesInterface()->glUniformMatrix4fv(location, count, transpose,
+                                                  value);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUseProgram(GLuint program) {
+  return SbGetGlesInterface()->glUseProgram(program);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glValidateProgram(GLuint program) {
+  return SbGetGlesInterface()->glValidateProgram(program);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib1f(GLuint index, GLfloat x) {
+  return SbGetGlesInterface()->glVertexAttrib1f(index, x);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib1fv(GLuint index,
+                                                 const GLfloat* v) {
+  return SbGetGlesInterface()->glVertexAttrib1fv(index, v);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib2f(GLuint index,
+                                                GLfloat x,
+                                                GLfloat y) {
+  return SbGetGlesInterface()->glVertexAttrib2f(index, x, y);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib2fv(GLuint index,
+                                                 const GLfloat* v) {
+  return SbGetGlesInterface()->glVertexAttrib2fv(index, v);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib3f(GLuint index,
+                                                GLfloat x,
+                                                GLfloat y,
+                                                GLfloat z) {
+  return SbGetGlesInterface()->glVertexAttrib3f(index, x, y, z);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib3fv(GLuint index,
+                                                 const GLfloat* v) {
+  return SbGetGlesInterface()->glVertexAttrib3fv(index, v);
+}
+
+GL_APICALL void GL_APIENTRY
+Sb_glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+  return SbGetGlesInterface()->glVertexAttrib4f(index, x, y, z, w);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib4fv(GLuint index,
+                                                 const GLfloat* v) {
+  return SbGetGlesInterface()->glVertexAttrib4fv(index, v);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glVertexAttribPointer(GLuint index,
+                                                     GLint size,
+                                                     GLenum type,
+                                                     GLboolean normalized,
+                                                     GLsizei stride,
+                                                     const void* pointer) {
+  return SbGetGlesInterface()->glVertexAttribPointer(
+      index, size, type, normalized, stride, pointer);
+}
+
+GL_APICALL void GL_APIENTRY Sb_glViewport(GLint x,
+                                          GLint y,
+                                          GLsizei width,
+                                          GLsizei height) {
+  return SbGetGlesInterface()->glViewport(x, y, width, height);
+}
+
+}  // extern "C"
diff --git a/chromecast/starboard/graphics/gles2_starboard.h b/chromecast/starboard/graphics/gles2_starboard.h
new file mode 100644
index 0000000..027d817b
--- /dev/null
+++ b/chromecast/starboard/graphics/gles2_starboard.h
@@ -0,0 +1,392 @@
+// 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 CHROMECAST_STARBOARD_GRAPHICS_GLES2_STARBOARD_H_
+#define CHROMECAST_STARBOARD_GRAPHICS_GLES2_STARBOARD_H_
+
+#include <GLES2/gl2.h>
+
+extern "C" {
+
+// gl2.h
+
+GL_APICALL void GL_APIENTRY Sb_glActiveTexture(GLenum texture);
+GL_APICALL void GL_APIENTRY Sb_glAttachShader(GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY Sb_glBindAttribLocation(GLuint program,
+                                                    GLuint index,
+                                                    const GLchar* name);
+GL_APICALL void GL_APIENTRY Sb_glBindBuffer(GLenum target, GLuint buffer);
+GL_APICALL void GL_APIENTRY Sb_glBindFramebuffer(GLenum target,
+                                                 GLuint framebuffer);
+GL_APICALL void GL_APIENTRY Sb_glBindRenderbuffer(GLenum target,
+                                                  GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY Sb_glBindTexture(GLenum target, GLuint texture);
+GL_APICALL void GL_APIENTRY Sb_glBlendColor(GLfloat red,
+                                            GLfloat green,
+                                            GLfloat blue,
+                                            GLfloat alpha);
+GL_APICALL void GL_APIENTRY Sb_glBlendEquation(GLenum mode);
+GL_APICALL void GL_APIENTRY Sb_glBlendEquationSeparate(GLenum modeRGB,
+                                                       GLenum modeAlpha);
+GL_APICALL void GL_APIENTRY Sb_glBlendFunc(GLenum sfactor, GLenum dfactor);
+GL_APICALL void GL_APIENTRY Sb_glBlendFuncSeparate(GLenum sfactorRGB,
+                                                   GLenum dfactorRGB,
+                                                   GLenum sfactorAlpha,
+                                                   GLenum dfactorAlpha);
+GL_APICALL void GL_APIENTRY Sb_glBufferData(GLenum target,
+                                            GLsizeiptr size,
+                                            const void* data,
+                                            GLenum usage);
+GL_APICALL void GL_APIENTRY Sb_glBufferSubData(GLenum target,
+                                               GLintptr offset,
+                                               GLsizeiptr size,
+                                               const void* data);
+GL_APICALL GLenum GL_APIENTRY Sb_glCheckFramebufferStatus(GLenum target);
+GL_APICALL void GL_APIENTRY Sb_glClear(GLbitfield mask);
+GL_APICALL void GL_APIENTRY Sb_glClearColor(GLfloat red,
+                                            GLfloat green,
+                                            GLfloat blue,
+                                            GLfloat alpha);
+GL_APICALL void GL_APIENTRY Sb_glClearDepthf(GLfloat d);
+GL_APICALL void GL_APIENTRY Sb_glClearStencil(GLint s);
+GL_APICALL void GL_APIENTRY Sb_glColorMask(GLboolean red,
+                                           GLboolean green,
+                                           GLboolean blue,
+                                           GLboolean alpha);
+GL_APICALL void GL_APIENTRY Sb_glCompileShader(GLuint shader);
+GL_APICALL void GL_APIENTRY Sb_glCompressedTexImage2D(GLenum target,
+                                                      GLint level,
+                                                      GLenum internalformat,
+                                                      GLsizei width,
+                                                      GLsizei height,
+                                                      GLint border,
+                                                      GLsizei imageSize,
+                                                      const void* data);
+GL_APICALL void GL_APIENTRY Sb_glCompressedTexSubImage2D(GLenum target,
+                                                         GLint level,
+                                                         GLint xoffset,
+                                                         GLint yoffset,
+                                                         GLsizei width,
+                                                         GLsizei height,
+                                                         GLenum format,
+                                                         GLsizei imageSize,
+                                                         const void* data);
+GL_APICALL void GL_APIENTRY Sb_glCopyTexImage2D(GLenum target,
+                                                GLint level,
+                                                GLenum internalformat,
+                                                GLint x,
+                                                GLint y,
+                                                GLsizei width,
+                                                GLsizei height,
+                                                GLint border);
+GL_APICALL void GL_APIENTRY Sb_glCopyTexSubImage2D(GLenum target,
+                                                   GLint level,
+                                                   GLint xoffset,
+                                                   GLint yoffset,
+                                                   GLint x,
+                                                   GLint y,
+                                                   GLsizei width,
+                                                   GLsizei height);
+GL_APICALL GLuint GL_APIENTRY Sb_glCreateProgram(void);
+GL_APICALL GLuint GL_APIENTRY Sb_glCreateShader(GLenum type);
+GL_APICALL void GL_APIENTRY Sb_glCullFace(GLenum mode);
+GL_APICALL void GL_APIENTRY Sb_glDeleteBuffers(GLsizei n,
+                                               const GLuint* buffers);
+GL_APICALL void GL_APIENTRY Sb_glDeleteFramebuffers(GLsizei n,
+                                                    const GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY Sb_glDeleteProgram(GLuint program);
+GL_APICALL void GL_APIENTRY
+Sb_glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY Sb_glDeleteShader(GLuint shader);
+GL_APICALL void GL_APIENTRY Sb_glDeleteTextures(GLsizei n,
+                                                const GLuint* textures);
+GL_APICALL void GL_APIENTRY Sb_glDepthFunc(GLenum func);
+GL_APICALL void GL_APIENTRY Sb_glDepthMask(GLboolean flag);
+GL_APICALL void GL_APIENTRY Sb_glDepthRangef(GLfloat n, GLfloat f);
+GL_APICALL void GL_APIENTRY Sb_glDetachShader(GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY Sb_glDisable(GLenum cap);
+GL_APICALL void GL_APIENTRY Sb_glDisableVertexAttribArray(GLuint index);
+GL_APICALL void GL_APIENTRY Sb_glDrawArrays(GLenum mode,
+                                            GLint first,
+                                            GLsizei count);
+GL_APICALL void GL_APIENTRY Sb_glDrawElements(GLenum mode,
+                                              GLsizei count,
+                                              GLenum type,
+                                              const void* indices);
+GL_APICALL void GL_APIENTRY Sb_glEnable(GLenum cap);
+GL_APICALL void GL_APIENTRY Sb_glEnableVertexAttribArray(GLuint index);
+GL_APICALL void GL_APIENTRY Sb_glFinish(void);
+GL_APICALL void GL_APIENTRY Sb_glFlush(void);
+GL_APICALL void GL_APIENTRY
+Sb_glFramebufferRenderbuffer(GLenum target,
+                             GLenum attachment,
+                             GLenum renderbuffertarget,
+                             GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY Sb_glFramebufferTexture2D(GLenum target,
+                                                      GLenum attachment,
+                                                      GLenum textarget,
+                                                      GLuint texture,
+                                                      GLint level);
+GL_APICALL void GL_APIENTRY Sb_glFrontFace(GLenum mode);
+GL_APICALL void GL_APIENTRY Sb_glGenBuffers(GLsizei n, GLuint* buffers);
+GL_APICALL void GL_APIENTRY Sb_glGenerateMipmap(GLenum target);
+GL_APICALL void GL_APIENTRY Sb_glGenFramebuffers(GLsizei n,
+                                                 GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY Sb_glGenRenderbuffers(GLsizei n,
+                                                  GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY Sb_glGenTextures(GLsizei n, GLuint* textures);
+GL_APICALL void GL_APIENTRY Sb_glGetActiveAttrib(GLuint program,
+                                                 GLuint index,
+                                                 GLsizei bufSize,
+                                                 GLsizei* length,
+                                                 GLint* size,
+                                                 GLenum* type,
+                                                 GLchar* name);
+GL_APICALL void GL_APIENTRY Sb_glGetActiveUniform(GLuint program,
+                                                  GLuint index,
+                                                  GLsizei bufSize,
+                                                  GLsizei* length,
+                                                  GLint* size,
+                                                  GLenum* type,
+                                                  GLchar* name);
+GL_APICALL void GL_APIENTRY Sb_glGetAttachedShaders(GLuint program,
+                                                    GLsizei maxCount,
+                                                    GLsizei* count,
+                                                    GLuint* shaders);
+GL_APICALL GLint GL_APIENTRY Sb_glGetAttribLocation(GLuint program,
+                                                    const GLchar* name);
+GL_APICALL void GL_APIENTRY Sb_glGetBooleanv(GLenum pname, GLboolean* data);
+GL_APICALL void GL_APIENTRY Sb_glGetBufferParameteriv(GLenum target,
+                                                      GLenum pname,
+                                                      GLint* params);
+GL_APICALL GLenum GL_APIENTRY Sb_glGetError(void);
+GL_APICALL void GL_APIENTRY Sb_glGetFloatv(GLenum pname, GLfloat* data);
+GL_APICALL void GL_APIENTRY
+Sb_glGetFramebufferAttachmentParameteriv(GLenum target,
+                                         GLenum attachment,
+                                         GLenum pname,
+                                         GLint* params);
+GL_APICALL void GL_APIENTRY Sb_glGetIntegerv(GLenum pname, GLint* data);
+GL_APICALL void GL_APIENTRY Sb_glGetProgramiv(GLuint program,
+                                              GLenum pname,
+                                              GLint* params);
+GL_APICALL void GL_APIENTRY Sb_glGetProgramInfoLog(GLuint program,
+                                                   GLsizei bufSize,
+                                                   GLsizei* length,
+                                                   GLchar* infoLog);
+GL_APICALL void GL_APIENTRY Sb_glGetRenderbufferParameteriv(GLenum target,
+                                                            GLenum pname,
+                                                            GLint* params);
+GL_APICALL void GL_APIENTRY Sb_glGetShaderiv(GLuint shader,
+                                             GLenum pname,
+                                             GLint* params);
+GL_APICALL void GL_APIENTRY Sb_glGetShaderInfoLog(GLuint shader,
+                                                  GLsizei bufSize,
+                                                  GLsizei* length,
+                                                  GLchar* infoLog);
+GL_APICALL void GL_APIENTRY Sb_glGetShaderPrecisionFormat(GLenum shadertype,
+                                                          GLenum precisiontype,
+                                                          GLint* range,
+                                                          GLint* precision);
+GL_APICALL void GL_APIENTRY Sb_glGetShaderSource(GLuint shader,
+                                                 GLsizei bufSize,
+                                                 GLsizei* length,
+                                                 GLchar* source);
+GL_APICALL const GLubyte* GL_APIENTRY Sb_glGetString(GLenum name);
+GL_APICALL void GL_APIENTRY Sb_glGetTexParameterfv(GLenum target,
+                                                   GLenum pname,
+                                                   GLfloat* params);
+GL_APICALL void GL_APIENTRY Sb_glGetTexParameteriv(GLenum target,
+                                                   GLenum pname,
+                                                   GLint* params);
+GL_APICALL void GL_APIENTRY Sb_glGetUniformfv(GLuint program,
+                                              GLint location,
+                                              GLfloat* params);
+GL_APICALL void GL_APIENTRY Sb_glGetUniformiv(GLuint program,
+                                              GLint location,
+                                              GLint* params);
+GL_APICALL GLint GL_APIENTRY Sb_glGetUniformLocation(GLuint program,
+                                                     const GLchar* name);
+GL_APICALL void GL_APIENTRY Sb_glGetVertexAttribfv(GLuint index,
+                                                   GLenum pname,
+                                                   GLfloat* params);
+GL_APICALL void GL_APIENTRY Sb_glGetVertexAttribiv(GLuint index,
+                                                   GLenum pname,
+                                                   GLint* params);
+GL_APICALL void GL_APIENTRY Sb_glGetVertexAttribPointerv(GLuint index,
+                                                         GLenum pname,
+                                                         void** pointer);
+GL_APICALL void GL_APIENTRY Sb_glHint(GLenum target, GLenum mode);
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsBuffer(GLuint buffer);
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsEnabled(GLenum cap);
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsFramebuffer(GLuint framebuffer);
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsProgram(GLuint program);
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsRenderbuffer(GLuint renderbuffer);
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsShader(GLuint shader);
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsTexture(GLuint texture);
+GL_APICALL void GL_APIENTRY Sb_glLineWidth(GLfloat width);
+GL_APICALL void GL_APIENTRY Sb_glLinkProgram(GLuint program);
+GL_APICALL void GL_APIENTRY Sb_glPixelStorei(GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY Sb_glPolygonOffset(GLfloat factor, GLfloat units);
+GL_APICALL void GL_APIENTRY Sb_glReadPixels(GLint x,
+                                            GLint y,
+                                            GLsizei width,
+                                            GLsizei height,
+                                            GLenum format,
+                                            GLenum type,
+                                            void* pixels);
+GL_APICALL void GL_APIENTRY Sb_glReleaseShaderCompiler(void);
+GL_APICALL void GL_APIENTRY Sb_glRenderbufferStorage(GLenum target,
+                                                     GLenum internalformat,
+                                                     GLsizei width,
+                                                     GLsizei height);
+GL_APICALL void GL_APIENTRY Sb_glSampleCoverage(GLfloat value,
+                                                GLboolean invert);
+GL_APICALL void GL_APIENTRY Sb_glScissor(GLint x,
+                                         GLint y,
+                                         GLsizei width,
+                                         GLsizei height);
+GL_APICALL void GL_APIENTRY Sb_glShaderBinary(GLsizei count,
+                                              const GLuint* shaders,
+                                              GLenum binaryformat,
+                                              const void* binary,
+                                              GLsizei length);
+GL_APICALL void GL_APIENTRY Sb_glShaderSource(GLuint shader,
+                                              GLsizei count,
+                                              const GLchar* const* string,
+                                              const GLint* length);
+GL_APICALL void GL_APIENTRY Sb_glStencilFunc(GLenum func,
+                                             GLint ref,
+                                             GLuint mask);
+GL_APICALL void GL_APIENTRY Sb_glStencilFuncSeparate(GLenum face,
+                                                     GLenum func,
+                                                     GLint ref,
+                                                     GLuint mask);
+GL_APICALL void GL_APIENTRY Sb_glStencilMask(GLuint mask);
+GL_APICALL void GL_APIENTRY Sb_glStencilMaskSeparate(GLenum face, GLuint mask);
+GL_APICALL void GL_APIENTRY Sb_glStencilOp(GLenum fail,
+                                           GLenum zfail,
+                                           GLenum zpass);
+GL_APICALL void GL_APIENTRY Sb_glStencilOpSeparate(GLenum face,
+                                                   GLenum sfail,
+                                                   GLenum dpfail,
+                                                   GLenum dppass);
+GL_APICALL void GL_APIENTRY Sb_glTexImage2D(GLenum target,
+                                            GLint level,
+                                            GLint internalformat,
+                                            GLsizei width,
+                                            GLsizei height,
+                                            GLint border,
+                                            GLenum format,
+                                            GLenum type,
+                                            const void* pixels);
+GL_APICALL void GL_APIENTRY Sb_glTexParameterf(GLenum target,
+                                               GLenum pname,
+                                               GLfloat param);
+GL_APICALL void GL_APIENTRY Sb_glTexParameterfv(GLenum target,
+                                                GLenum pname,
+                                                const GLfloat* params);
+GL_APICALL void GL_APIENTRY Sb_glTexParameteri(GLenum target,
+                                               GLenum pname,
+                                               GLint param);
+GL_APICALL void GL_APIENTRY Sb_glTexParameteriv(GLenum target,
+                                                GLenum pname,
+                                                const GLint* params);
+GL_APICALL void GL_APIENTRY Sb_glTexSubImage2D(GLenum target,
+                                               GLint level,
+                                               GLint xoffset,
+                                               GLint yoffset,
+                                               GLsizei width,
+                                               GLsizei height,
+                                               GLenum format,
+                                               GLenum type,
+                                               const void* pixels);
+GL_APICALL void GL_APIENTRY Sb_glUniform1f(GLint location, GLfloat v0);
+GL_APICALL void GL_APIENTRY Sb_glUniform1fv(GLint location,
+                                            GLsizei count,
+                                            const GLfloat* value);
+GL_APICALL void GL_APIENTRY Sb_glUniform1i(GLint location, GLint v0);
+GL_APICALL void GL_APIENTRY Sb_glUniform1iv(GLint location,
+                                            GLsizei count,
+                                            const GLint* value);
+GL_APICALL void GL_APIENTRY Sb_glUniform2f(GLint location,
+                                           GLfloat v0,
+                                           GLfloat v1);
+GL_APICALL void GL_APIENTRY Sb_glUniform2fv(GLint location,
+                                            GLsizei count,
+                                            const GLfloat* value);
+GL_APICALL void GL_APIENTRY Sb_glUniform2i(GLint location, GLint v0, GLint v1);
+GL_APICALL void GL_APIENTRY Sb_glUniform2iv(GLint location,
+                                            GLsizei count,
+                                            const GLint* value);
+GL_APICALL void GL_APIENTRY Sb_glUniform3f(GLint location,
+                                           GLfloat v0,
+                                           GLfloat v1,
+                                           GLfloat v2);
+GL_APICALL void GL_APIENTRY Sb_glUniform3fv(GLint location,
+                                            GLsizei count,
+                                            const GLfloat* value);
+GL_APICALL void GL_APIENTRY Sb_glUniform3i(GLint location,
+                                           GLint v0,
+                                           GLint v1,
+                                           GLint v2);
+GL_APICALL void GL_APIENTRY Sb_glUniform3iv(GLint location,
+                                            GLsizei count,
+                                            const GLint* value);
+GL_APICALL void GL_APIENTRY
+Sb_glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+GL_APICALL void GL_APIENTRY Sb_glUniform4fv(GLint location,
+                                            GLsizei count,
+                                            const GLfloat* value);
+GL_APICALL void GL_APIENTRY
+Sb_glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+GL_APICALL void GL_APIENTRY Sb_glUniform4iv(GLint location,
+                                            GLsizei count,
+                                            const GLint* value);
+GL_APICALL void GL_APIENTRY Sb_glUniformMatrix2fv(GLint location,
+                                                  GLsizei count,
+                                                  GLboolean transpose,
+                                                  const GLfloat* value);
+GL_APICALL void GL_APIENTRY Sb_glUniformMatrix3fv(GLint location,
+                                                  GLsizei count,
+                                                  GLboolean transpose,
+                                                  const GLfloat* value);
+GL_APICALL void GL_APIENTRY Sb_glUniformMatrix4fv(GLint location,
+                                                  GLsizei count,
+                                                  GLboolean transpose,
+                                                  const GLfloat* value);
+GL_APICALL void GL_APIENTRY Sb_glUseProgram(GLuint program);
+GL_APICALL void GL_APIENTRY Sb_glValidateProgram(GLuint program);
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib1f(GLuint index, GLfloat x);
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib1fv(GLuint index,
+                                                 const GLfloat* v);
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib2f(GLuint index,
+                                                GLfloat x,
+                                                GLfloat y);
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib2fv(GLuint index,
+                                                 const GLfloat* v);
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib3f(GLuint index,
+                                                GLfloat x,
+                                                GLfloat y,
+                                                GLfloat z);
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib3fv(GLuint index,
+                                                 const GLfloat* v);
+GL_APICALL void GL_APIENTRY
+Sb_glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib4fv(GLuint index,
+                                                 const GLfloat* v);
+GL_APICALL void GL_APIENTRY Sb_glVertexAttribPointer(GLuint index,
+                                                     GLint size,
+                                                     GLenum type,
+                                                     GLboolean normalized,
+                                                     GLsizei stride,
+                                                     const void* pointer);
+GL_APICALL void GL_APIENTRY Sb_glViewport(GLint x,
+                                          GLint y,
+                                          GLsizei width,
+                                          GLsizei height);
+
+}  // extern "C"
+
+#endif  // CHROMECAST_STARBOARD_GRAPHICS_GLES2_STARBOARD_H_
diff --git a/chromecast/starboard/graphics/gles2_starboard_dummy.cc b/chromecast/starboard/graphics/gles2_starboard_dummy.cc
new file mode 100644
index 0000000..24febbe4
--- /dev/null
+++ b/chromecast/starboard/graphics/gles2_starboard_dummy.cc
@@ -0,0 +1,561 @@
+// 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.
+
+// A dummy implementation of gles2_starboard.h. This can be used to compile
+// without starboard headers. It should never be used in production.
+//
+// TODO(b/333131992): remove this
+
+#include "chromecast/starboard/graphics/gles2_starboard.h"
+
+extern "C" {
+
+GL_APICALL void GL_APIENTRY Sb_glActiveTexture(GLenum texture) {}
+
+GL_APICALL void GL_APIENTRY Sb_glAttachShader(GLuint program, GLuint shader) {}
+
+GL_APICALL void GL_APIENTRY Sb_glBindAttribLocation(GLuint program,
+                                                    GLuint index,
+                                                    const GLchar* name) {}
+
+GL_APICALL void GL_APIENTRY Sb_glBindBuffer(GLenum target, GLuint buffer) {}
+
+GL_APICALL void GL_APIENTRY Sb_glBindFramebuffer(GLenum target,
+                                                 GLuint framebuffer) {}
+
+GL_APICALL void GL_APIENTRY Sb_glBindRenderbuffer(GLenum target,
+                                                  GLuint renderbuffer) {}
+
+GL_APICALL void GL_APIENTRY Sb_glBindTexture(GLenum target, GLuint texture) {}
+
+GL_APICALL void GL_APIENTRY Sb_glBlendColor(GLfloat red,
+                                            GLfloat green,
+                                            GLfloat blue,
+                                            GLfloat alpha) {}
+
+GL_APICALL void GL_APIENTRY Sb_glBlendEquation(GLenum mode) {}
+
+GL_APICALL void GL_APIENTRY Sb_glBlendEquationSeparate(GLenum modeRGB,
+                                                       GLenum modeAlpha) {}
+
+GL_APICALL void GL_APIENTRY Sb_glBlendFunc(GLenum sfactor, GLenum dfactor) {}
+
+GL_APICALL void GL_APIENTRY Sb_glBlendFuncSeparate(GLenum sfactorRGB,
+                                                   GLenum dfactorRGB,
+                                                   GLenum sfactorAlpha,
+                                                   GLenum dfactorAlpha) {}
+
+GL_APICALL void GL_APIENTRY Sb_glBufferData(GLenum target,
+                                            GLsizeiptr size,
+                                            const void* data,
+                                            GLenum usage) {}
+
+GL_APICALL void GL_APIENTRY Sb_glBufferSubData(GLenum target,
+                                               GLintptr offset,
+                                               GLsizeiptr size,
+                                               const void* data) {}
+
+GL_APICALL GLenum GL_APIENTRY Sb_glCheckFramebufferStatus(GLenum target) {
+  return 0;
+}
+
+GL_APICALL void GL_APIENTRY Sb_glClear(GLbitfield mask) {}
+
+GL_APICALL void GL_APIENTRY Sb_glClearColor(GLfloat red,
+                                            GLfloat green,
+                                            GLfloat blue,
+                                            GLfloat alpha) {}
+
+GL_APICALL void GL_APIENTRY Sb_glClearDepthf(GLfloat d) {}
+
+GL_APICALL void GL_APIENTRY Sb_glClearStencil(GLint s) {}
+
+GL_APICALL void GL_APIENTRY Sb_glColorMask(GLboolean red,
+                                           GLboolean green,
+                                           GLboolean blue,
+                                           GLboolean alpha) {}
+
+GL_APICALL void GL_APIENTRY Sb_glCompileShader(GLuint shader) {}
+
+GL_APICALL void GL_APIENTRY Sb_glCompressedTexImage2D(GLenum target,
+                                                      GLint level,
+                                                      GLenum internalformat,
+                                                      GLsizei width,
+                                                      GLsizei height,
+                                                      GLint border,
+                                                      GLsizei imageSize,
+                                                      const void* data) {}
+
+GL_APICALL void GL_APIENTRY Sb_glCompressedTexSubImage2D(GLenum target,
+                                                         GLint level,
+                                                         GLint xoffset,
+                                                         GLint yoffset,
+                                                         GLsizei width,
+                                                         GLsizei height,
+                                                         GLenum format,
+                                                         GLsizei imageSize,
+                                                         const void* data) {}
+
+GL_APICALL void GL_APIENTRY Sb_glCopyTexImage2D(GLenum target,
+                                                GLint level,
+                                                GLenum internalformat,
+                                                GLint x,
+                                                GLint y,
+                                                GLsizei width,
+                                                GLsizei height,
+                                                GLint border) {}
+
+GL_APICALL void GL_APIENTRY Sb_glCopyTexSubImage2D(GLenum target,
+                                                   GLint level,
+                                                   GLint xoffset,
+                                                   GLint yoffset,
+                                                   GLint x,
+                                                   GLint y,
+                                                   GLsizei width,
+                                                   GLsizei height) {}
+
+GL_APICALL GLuint GL_APIENTRY Sb_glCreateProgram(void) {
+  return 0;
+}
+
+GL_APICALL GLuint GL_APIENTRY Sb_glCreateShader(GLenum type) {
+  return 0;
+}
+
+GL_APICALL void GL_APIENTRY Sb_glCullFace(GLenum mode) {}
+
+GL_APICALL void GL_APIENTRY Sb_glDeleteBuffers(GLsizei n,
+                                               const GLuint* buffers) {}
+
+GL_APICALL void GL_APIENTRY
+Sb_glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) {}
+
+GL_APICALL void GL_APIENTRY Sb_glDeleteProgram(GLuint program) {}
+
+GL_APICALL void GL_APIENTRY
+Sb_glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) {}
+
+GL_APICALL void GL_APIENTRY Sb_glDeleteShader(GLuint shader) {}
+
+GL_APICALL void GL_APIENTRY Sb_glDeleteTextures(GLsizei n,
+                                                const GLuint* textures) {}
+
+GL_APICALL void GL_APIENTRY Sb_glDepthFunc(GLenum func) {}
+
+GL_APICALL void GL_APIENTRY Sb_glDepthMask(GLboolean flag) {}
+
+GL_APICALL void GL_APIENTRY Sb_glDepthRangef(GLfloat n, GLfloat f) {}
+
+GL_APICALL void GL_APIENTRY Sb_glDetachShader(GLuint program, GLuint shader) {}
+
+GL_APICALL void GL_APIENTRY Sb_glDisable(GLenum cap) {}
+
+GL_APICALL void GL_APIENTRY Sb_glDisableVertexAttribArray(GLuint index) {}
+
+GL_APICALL void GL_APIENTRY Sb_glDrawArrays(GLenum mode,
+                                            GLint first,
+                                            GLsizei count) {}
+
+GL_APICALL void GL_APIENTRY Sb_glDrawElements(GLenum mode,
+                                              GLsizei count,
+                                              GLenum type,
+                                              const void* indices) {}
+
+GL_APICALL void GL_APIENTRY Sb_glEnable(GLenum cap) {}
+
+GL_APICALL void GL_APIENTRY Sb_glEnableVertexAttribArray(GLuint index) {}
+
+GL_APICALL void GL_APIENTRY Sb_glFinish(void) {}
+
+GL_APICALL void GL_APIENTRY Sb_glFlush(void) {}
+
+GL_APICALL void GL_APIENTRY
+Sb_glFramebufferRenderbuffer(GLenum target,
+                             GLenum attachment,
+                             GLenum renderbuffertarget,
+                             GLuint renderbuffer) {}
+
+GL_APICALL void GL_APIENTRY Sb_glFramebufferTexture2D(GLenum target,
+                                                      GLenum attachment,
+                                                      GLenum textarget,
+                                                      GLuint texture,
+                                                      GLint level) {}
+
+GL_APICALL void GL_APIENTRY Sb_glFrontFace(GLenum mode) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGenBuffers(GLsizei n, GLuint* buffers) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGenerateMipmap(GLenum target) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGenFramebuffers(GLsizei n,
+                                                 GLuint* framebuffers) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGenRenderbuffers(GLsizei n,
+                                                  GLuint* renderbuffers) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGenTextures(GLsizei n, GLuint* textures) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetActiveAttrib(GLuint program,
+                                                 GLuint index,
+                                                 GLsizei bufSize,
+                                                 GLsizei* length,
+                                                 GLint* size,
+                                                 GLenum* type,
+                                                 GLchar* name) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetActiveUniform(GLuint program,
+                                                  GLuint index,
+                                                  GLsizei bufSize,
+                                                  GLsizei* length,
+                                                  GLint* size,
+                                                  GLenum* type,
+                                                  GLchar* name) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetAttachedShaders(GLuint program,
+                                                    GLsizei maxCount,
+                                                    GLsizei* count,
+                                                    GLuint* shaders) {}
+
+GL_APICALL GLint GL_APIENTRY Sb_glGetAttribLocation(GLuint program,
+                                                    const GLchar* name) {
+  return 0;
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetBooleanv(GLenum pname, GLboolean* data) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetBufferParameteriv(GLenum target,
+                                                      GLenum pname,
+                                                      GLint* params) {}
+
+GL_APICALL GLenum GL_APIENTRY Sb_glGetError(void) {
+  return 0;
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetFloatv(GLenum pname, GLfloat* data) {}
+
+GL_APICALL void GL_APIENTRY
+Sb_glGetFramebufferAttachmentParameteriv(GLenum target,
+                                         GLenum attachment,
+                                         GLenum pname,
+                                         GLint* params) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetIntegerv(GLenum pname, GLint* data) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetProgramiv(GLuint program,
+                                              GLenum pname,
+                                              GLint* params) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetProgramInfoLog(GLuint program,
+                                                   GLsizei bufSize,
+                                                   GLsizei* length,
+                                                   GLchar* infoLog) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetRenderbufferParameteriv(GLenum target,
+                                                            GLenum pname,
+                                                            GLint* params) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetShaderiv(GLuint shader,
+                                             GLenum pname,
+                                             GLint* params) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetShaderInfoLog(GLuint shader,
+                                                  GLsizei bufSize,
+                                                  GLsizei* length,
+                                                  GLchar* infoLog) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetShaderPrecisionFormat(GLenum shadertype,
+                                                          GLenum precisiontype,
+                                                          GLint* range,
+                                                          GLint* precision) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetShaderSource(GLuint shader,
+                                                 GLsizei bufSize,
+                                                 GLsizei* length,
+                                                 GLchar* source) {}
+
+GL_APICALL const GLubyte* GL_APIENTRY Sb_glGetString(GLenum name) {
+  return nullptr;
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetTexParameterfv(GLenum target,
+                                                   GLenum pname,
+                                                   GLfloat* params) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetTexParameteriv(GLenum target,
+                                                   GLenum pname,
+                                                   GLint* params) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetUniformfv(GLuint program,
+                                              GLint location,
+                                              GLfloat* params) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetUniformiv(GLuint program,
+                                              GLint location,
+                                              GLint* params) {}
+
+GL_APICALL GLint GL_APIENTRY Sb_glGetUniformLocation(GLuint program,
+                                                     const GLchar* name) {
+  return 0;
+}
+
+GL_APICALL void GL_APIENTRY Sb_glGetVertexAttribfv(GLuint index,
+                                                   GLenum pname,
+                                                   GLfloat* params) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetVertexAttribiv(GLuint index,
+                                                   GLenum pname,
+                                                   GLint* params) {}
+
+GL_APICALL void GL_APIENTRY Sb_glGetVertexAttribPointerv(GLuint index,
+                                                         GLenum pname,
+                                                         void** pointer) {}
+
+GL_APICALL void GL_APIENTRY Sb_glHint(GLenum target, GLenum mode) {}
+
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsBuffer(GLuint buffer) {
+  return 0;
+}
+
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsEnabled(GLenum cap) {
+  return 0;
+}
+
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsFramebuffer(GLuint framebuffer) {
+  return 0;
+}
+
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsProgram(GLuint program) {
+  return 0;
+}
+
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsRenderbuffer(GLuint renderbuffer) {
+  return 0;
+}
+
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsShader(GLuint shader) {
+  return 0;
+}
+
+GL_APICALL GLboolean GL_APIENTRY Sb_glIsTexture(GLuint texture) {
+  return 0;
+}
+
+GL_APICALL void GL_APIENTRY Sb_glLineWidth(GLfloat width) {}
+
+GL_APICALL void GL_APIENTRY Sb_glLinkProgram(GLuint program) {}
+
+GL_APICALL void GL_APIENTRY Sb_glPixelStorei(GLenum pname, GLint param) {}
+
+GL_APICALL void GL_APIENTRY Sb_glPolygonOffset(GLfloat factor, GLfloat units) {}
+
+GL_APICALL void GL_APIENTRY Sb_glReadPixels(GLint x,
+                                            GLint y,
+                                            GLsizei width,
+                                            GLsizei height,
+                                            GLenum format,
+                                            GLenum type,
+                                            void* pixels) {}
+
+GL_APICALL void GL_APIENTRY Sb_glReleaseShaderCompiler(void) {}
+
+GL_APICALL void GL_APIENTRY Sb_glRenderbufferStorage(GLenum target,
+                                                     GLenum internalformat,
+                                                     GLsizei width,
+                                                     GLsizei height) {}
+
+GL_APICALL void GL_APIENTRY Sb_glSampleCoverage(GLfloat value,
+                                                GLboolean invert) {}
+
+GL_APICALL void GL_APIENTRY Sb_glScissor(GLint x,
+                                         GLint y,
+                                         GLsizei width,
+                                         GLsizei height) {}
+
+GL_APICALL void GL_APIENTRY Sb_glShaderBinary(GLsizei count,
+                                              const GLuint* shaders,
+                                              GLenum binaryformat,
+                                              const void* binary,
+                                              GLsizei length) {}
+
+GL_APICALL void GL_APIENTRY Sb_glShaderSource(GLuint shader,
+                                              GLsizei count,
+                                              const GLchar* const* string,
+                                              const GLint* length) {}
+
+GL_APICALL void GL_APIENTRY Sb_glStencilFunc(GLenum func,
+                                             GLint ref,
+                                             GLuint mask) {}
+
+GL_APICALL void GL_APIENTRY Sb_glStencilFuncSeparate(GLenum face,
+                                                     GLenum func,
+                                                     GLint ref,
+                                                     GLuint mask) {}
+
+GL_APICALL void GL_APIENTRY Sb_glStencilMask(GLuint mask) {}
+
+GL_APICALL void GL_APIENTRY Sb_glStencilMaskSeparate(GLenum face, GLuint mask) {
+}
+
+GL_APICALL void GL_APIENTRY Sb_glStencilOp(GLenum fail,
+                                           GLenum zfail,
+                                           GLenum zpass) {}
+
+GL_APICALL void GL_APIENTRY Sb_glStencilOpSeparate(GLenum face,
+                                                   GLenum sfail,
+                                                   GLenum dpfail,
+                                                   GLenum dppass) {}
+
+GL_APICALL void GL_APIENTRY Sb_glTexImage2D(GLenum target,
+                                            GLint level,
+                                            GLint internalformat,
+                                            GLsizei width,
+                                            GLsizei height,
+                                            GLint border,
+                                            GLenum format,
+                                            GLenum type,
+                                            const void* pixels) {}
+
+GL_APICALL void GL_APIENTRY Sb_glTexParameterf(GLenum target,
+                                               GLenum pname,
+                                               GLfloat param) {}
+
+GL_APICALL void GL_APIENTRY Sb_glTexParameterfv(GLenum target,
+                                                GLenum pname,
+                                                const GLfloat* params) {}
+
+GL_APICALL void GL_APIENTRY Sb_glTexParameteri(GLenum target,
+                                               GLenum pname,
+                                               GLint param) {}
+
+GL_APICALL void GL_APIENTRY Sb_glTexParameteriv(GLenum target,
+                                                GLenum pname,
+                                                const GLint* params) {}
+
+GL_APICALL void GL_APIENTRY Sb_glTexSubImage2D(GLenum target,
+                                               GLint level,
+                                               GLint xoffset,
+                                               GLint yoffset,
+                                               GLsizei width,
+                                               GLsizei height,
+                                               GLenum format,
+                                               GLenum type,
+                                               const void* pixels) {}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform1f(GLint location, GLfloat v0) {}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform1fv(GLint location,
+                                            GLsizei count,
+                                            const GLfloat* value) {}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform1i(GLint location, GLint v0) {}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform1iv(GLint location,
+                                            GLsizei count,
+                                            const GLint* value) {}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform2f(GLint location,
+                                           GLfloat v0,
+                                           GLfloat v1) {}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform2fv(GLint location,
+                                            GLsizei count,
+                                            const GLfloat* value) {}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform2i(GLint location, GLint v0, GLint v1) {
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform2iv(GLint location,
+                                            GLsizei count,
+                                            const GLint* value) {}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform3f(GLint location,
+                                           GLfloat v0,
+                                           GLfloat v1,
+                                           GLfloat v2) {}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform3fv(GLint location,
+                                            GLsizei count,
+                                            const GLfloat* value) {}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform3i(GLint location,
+                                           GLint v0,
+                                           GLint v1,
+                                           GLint v2) {}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform3iv(GLint location,
+                                            GLsizei count,
+                                            const GLint* value) {}
+
+GL_APICALL void GL_APIENTRY
+Sb_glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {
+}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform4fv(GLint location,
+                                            GLsizei count,
+                                            const GLfloat* value) {}
+
+GL_APICALL void GL_APIENTRY
+Sb_glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {}
+
+GL_APICALL void GL_APIENTRY Sb_glUniform4iv(GLint location,
+                                            GLsizei count,
+                                            const GLint* value) {}
+
+GL_APICALL void GL_APIENTRY Sb_glUniformMatrix2fv(GLint location,
+                                                  GLsizei count,
+                                                  GLboolean transpose,
+                                                  const GLfloat* value) {}
+
+GL_APICALL void GL_APIENTRY Sb_glUniformMatrix3fv(GLint location,
+                                                  GLsizei count,
+                                                  GLboolean transpose,
+                                                  const GLfloat* value) {}
+
+GL_APICALL void GL_APIENTRY Sb_glUniformMatrix4fv(GLint location,
+                                                  GLsizei count,
+                                                  GLboolean transpose,
+                                                  const GLfloat* value) {}
+
+GL_APICALL void GL_APIENTRY Sb_glUseProgram(GLuint program) {}
+
+GL_APICALL void GL_APIENTRY Sb_glValidateProgram(GLuint program) {}
+
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib1f(GLuint index, GLfloat x) {}
+
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib1fv(GLuint index,
+                                                 const GLfloat* v) {}
+
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib2f(GLuint index,
+                                                GLfloat x,
+                                                GLfloat y) {}
+
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib2fv(GLuint index,
+                                                 const GLfloat* v) {}
+
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib3f(GLuint index,
+                                                GLfloat x,
+                                                GLfloat y,
+                                                GLfloat z) {}
+
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib3fv(GLuint index,
+                                                 const GLfloat* v) {}
+
+GL_APICALL void GL_APIENTRY
+Sb_glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {}
+
+GL_APICALL void GL_APIENTRY Sb_glVertexAttrib4fv(GLuint index,
+                                                 const GLfloat* v) {}
+
+GL_APICALL void GL_APIENTRY Sb_glVertexAttribPointer(GLuint index,
+                                                     GLint size,
+                                                     GLenum type,
+                                                     GLboolean normalized,
+                                                     GLsizei stride,
+                                                     const void* pointer) {}
+
+GL_APICALL void GL_APIENTRY Sb_glViewport(GLint x,
+                                          GLint y,
+                                          GLsizei width,
+                                          GLsizei height) {}
+}
diff --git a/chromecast/starboard/graphics/graphics_properties_default.cc b/chromecast/starboard/graphics/graphics_properties_default.cc
new file mode 100644
index 0000000..7517a78
--- /dev/null
+++ b/chromecast/starboard/graphics/graphics_properties_default.cc
@@ -0,0 +1,22 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromecast/public/graphics_properties_shlib.h"
+
+namespace chromecast {
+
+bool GraphicsPropertiesShlib::IsSupported(
+    Resolution resolution,
+    const std::vector<std::string>& argv) {
+  switch (resolution) {
+    case Resolution::k1080p:
+      return true;
+    case Resolution::kUHDTV:
+      return false;
+    default:
+      return false;
+  }
+}
+
+}  // namespace chromecast
diff --git a/chromecast/starboard/media/media/BUILD.gn b/chromecast/starboard/media/media/BUILD.gn
new file mode 100644
index 0000000..8404d95
--- /dev/null
+++ b/chromecast/starboard/media/media/BUILD.gn
@@ -0,0 +1,56 @@
+# Copyright 2024 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//chromecast/chromecast.gni")
+import("//chromecast/starboard/starboard.gni")
+import("//testing/test.gni")
+
+if (!remove_starboard_headers) {
+  import(
+      "//chromecast/starboard/third_party/starboard/sabi/base_configuration.gni")
+}
+
+source_set("mock_starboard_api_wrapper") {
+  testonly = true
+  sources = [
+    "mock_starboard_api_wrapper.cc",
+    "mock_starboard_api_wrapper.h",
+    "starboard_api_wrapper.cc",
+    "starboard_api_wrapper.h",
+  ]
+  deps = [ "//testing/gmock" ]
+}
+
+cast_source_set("starboard_api_wrapper") {
+  sources = []
+  deps = []
+
+  # TODO(b/333131992): remove this case.
+  if (remove_starboard_headers) {
+    sources += [
+      "starboard_api_wrapper.cc",
+      "starboard_api_wrapper.h",
+      "starboard_api_wrapper_dummy.cc",
+    ]
+  } else {
+    sources += [
+      "starboard_api_wrapper.cc",
+      "starboard_api_wrapper.h",
+      "starboard_api_wrapper_base.cc",
+      "starboard_api_wrapper_base.h",
+    ]
+    if (sb_api_version == 15) {
+      sources += [ "starboard_api_wrapper_15.cc" ]
+    } else {
+      assert(sb_api_version == 13 || sb_api_version == 14,
+             "Only SB 13 and 14 are supported by starboard_api_wrapper_14.cc")
+      sources += [ "starboard_api_wrapper_14.cc" ]
+    }
+    deps += [
+      "//base",
+      "//chromecast/starboard/chromecast/starboard_adapter",
+      "//chromecast/starboard/chromecast/starboard_cast_dummy:cast_starboard_api",
+    ]
+  }
+}
diff --git a/chromecast/starboard/media/media/mock_starboard_api_wrapper.cc b/chromecast/starboard/media/media/mock_starboard_api_wrapper.cc
new file mode 100644
index 0000000..c0caba6c
--- /dev/null
+++ b/chromecast/starboard/media/media/mock_starboard_api_wrapper.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 "chromecast/starboard/media/media/mock_starboard_api_wrapper.h"
+
+namespace chromecast {
+namespace media {
+
+MockStarboardApiWrapper::MockStarboardApiWrapper() = default;
+MockStarboardApiWrapper::~MockStarboardApiWrapper() = default;
+
+}  // namespace media
+}  // namespace chromecast
diff --git a/chromecast/starboard/media/media/mock_starboard_api_wrapper.h b/chromecast/starboard/media/media/mock_starboard_api_wrapper.h
new file mode 100644
index 0000000..7ca8338
--- /dev/null
+++ b/chromecast/starboard/media/media/mock_starboard_api_wrapper.h
@@ -0,0 +1,99 @@
+// 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 CHROMECAST_STARBOARD_MEDIA_MEDIA_MOCK_STARBOARD_API_WRAPPER_H_
+#define CHROMECAST_STARBOARD_MEDIA_MEDIA_MOCK_STARBOARD_API_WRAPPER_H_
+
+#include "chromecast/starboard/media/media/starboard_api_wrapper.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace chromecast {
+namespace media {
+
+class MockStarboardApiWrapper : public StarboardApiWrapper {
+ public:
+  MockStarboardApiWrapper();
+  ~MockStarboardApiWrapper() override;
+
+  MOCK_METHOD(bool, EnsureInitialized, (), (override));
+
+  MOCK_METHOD(void*,
+              CreatePlayer,
+              (const StarboardPlayerCreationParam* creation_param,
+               const StarboardPlayerCallbackHandler* callback_handler),
+              (override));
+  MOCK_METHOD(void,
+              SetPlayerBounds,
+              (void* player, int z_index, int x, int y, int width, int height),
+              (override));
+  MOCK_METHOD(void,
+              SeekTo,
+              (void* player, int64_t time, int seek_ticket),
+              (override));
+  MOCK_METHOD(void,
+              WriteSample,
+              (void* player,
+               StarboardMediaType type,
+               StarboardSampleInfo* sample_infos,
+               int sample_infos_count),
+              (override));
+  MOCK_METHOD(void,
+              WriteEndOfStream,
+              (void* player, StarboardMediaType type),
+              (override));
+  MOCK_METHOD(void,
+              GetPlayerInfo,
+              (void* player, StarboardPlayerInfo* player_info),
+              (override));
+  MOCK_METHOD(void, SetVolume, (void* player, double volume), (override));
+  MOCK_METHOD(bool,
+              SetPlaybackRate,
+              (void* player, double playback_rate),
+              (override));
+  MOCK_METHOD(void, DestroyPlayer, (void* player), (override));
+
+  MOCK_METHOD(void*,
+              CreateDrmSystem,
+              (const char* key_system,
+               const StarboardDrmSystemCallbackHandler* callback_handler),
+              (override));
+  MOCK_METHOD(void,
+              DrmGenerateSessionUpdateRequest,
+              (void* drm_system,
+               int ticket,
+               const char* type,
+               const void* initialization_data,
+               int initialization_data_size),
+              (override));
+  MOCK_METHOD(void,
+              DrmUpdateSession,
+              (void* drm_system,
+               int ticket,
+               const void* key,
+               int key_size,
+               const void* session_id,
+               int session_id_size),
+              (override));
+  MOCK_METHOD(void,
+              DrmCloseSession,
+              (void* drm_system, const void* session_id, int session_id_size),
+              (override));
+  MOCK_METHOD(void,
+              DrmUpdateServerCertificate,
+              (void* drm_system,
+               int ticket,
+               const void* certificate,
+               int certificate_size),
+              (override));
+  MOCK_METHOD(bool,
+              DrmIsServerCertificateUpdatable,
+              (void* drm_system),
+              (override));
+  MOCK_METHOD(void, DrmDestroySystem, (void* drm_system), (override));
+};
+
+}  // namespace media
+}  // namespace chromecast
+
+#endif  // CHROMECAST_STARBOARD_MEDIA_MEDIA_MOCK_STARBOARD_API_WRAPPER_H_
diff --git a/chromecast/starboard/media/media/starboard_api_wrapper.cc b/chromecast/starboard/media/media/starboard_api_wrapper.cc
new file mode 100644
index 0000000..0d886642
--- /dev/null
+++ b/chromecast/starboard/media/media/starboard_api_wrapper.cc
@@ -0,0 +1,13 @@
+// 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 "chromecast/starboard/media/media/starboard_api_wrapper.h"
+
+namespace chromecast {
+namespace media {
+
+StarboardApiWrapper::~StarboardApiWrapper() = default;
+
+}  // namespace media
+}  // namespace chromecast
diff --git a/chromecast/starboard/media/media/starboard_api_wrapper.h b/chromecast/starboard/media/media/starboard_api_wrapper.h
new file mode 100644
index 0000000..3acf725
--- /dev/null
+++ b/chromecast/starboard/media/media/starboard_api_wrapper.h
@@ -0,0 +1,505 @@
+// 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.
+//
+// The structs/enums in this file represent corresponding structs/enums in
+// starboard. By using these types instead of Starboard's, we can abstract away
+// minor changes (e.g. function renames) in Starboard without having to change
+// the rest of the MediaPipelineBackend. Additionally, these types can be
+// converted to different version-specific Starboard types.
+//
+// Users of this header should interact with Starboard via a StarboardApiWrapper
+// created via GetStarboardApiWrapper(). For testing purposes, a mock
+// StarboardApiWrapper can be used instead.
+
+#ifndef CHROMECAST_STARBOARD_MEDIA_MEDIA_STARBOARD_API_WRAPPER_H_
+#define CHROMECAST_STARBOARD_MEDIA_MEDIA_STARBOARD_API_WRAPPER_H_
+
+#include <cstdint>
+#include <cstring>
+#include <memory>
+
+namespace chromecast {
+namespace media {
+
+// Copy of SbMediaType from starboard.
+enum StarboardMediaType {
+  kStarboardMediaTypeAudio,
+  kStarboardMediaTypeVideo,
+};
+
+// Copy of SbMediaAudioCodec from starboard.
+enum StarboardAudioCodec {
+  kStarboardAudioCodecNone,
+  kStarboardAudioCodecAac,
+  kStarboardAudioCodecAc3,
+  kStarboardAudioCodecEac3,
+  kStarboardAudioCodecOpus,
+  kStarboardAudioCodecVorbis,
+  kStarboardAudioCodecMp3,
+  kStarboardAudioCodecFlac,
+  kStarboardAudioCodecPcm,
+};
+
+// Copy of SbMediaVideoCodec from starboard.
+enum StarboardVideoCodec {
+  kStarboardVideoCodecNone,
+  kStarboardVideoCodecH264,
+  kStarboardVideoCodecH265,
+  kStarboardVideoCodecMpeg2,
+  kStarboardVideoCodecTheora,
+  kStarboardVideoCodecVc1,
+  kStarboardVideoCodecAv1,
+  kStarboardVideoCodecVp8,
+  kStarboardVideoCodecVp9,
+};
+
+// Copy of SbPlayerSampleSideDataType from starboard.
+enum StarboardSampleSideDataType {
+  kStarboardSampleSideDataTypeMatroskaBlockAdditional,
+};
+
+// Copy of SbPlayerDecoderState from starboard.
+enum StarboardDecoderState {
+  kStarboardDecoderStateNeedsData,
+};
+
+// Copy of SbPlayerOutputMode from starboard.
+enum StarboardPlayerOutputMode {
+  kStarboardPlayerOutputModeDecodeToTexture,
+  kStarboardPlayerOutputModePunchOut,
+  kStarboardPlayerOutputModeInvalid,
+};
+
+// Copy of SbPlayerState from starboard.
+enum StarboardPlayerState {
+  kStarboardPlayerStateInitialized,
+  kStarboardPlayerStatePrerolling,
+  kStarboardPlayerStatePresenting,
+  kStarboardPlayerStateEndOfStream,
+  kStarboardPlayerStateDestroyed,
+};
+
+// Copy of SbPlayerError from starboard.
+enum StarboardPlayerError {
+  kStarboardPlayerErrorDecode,
+  kStarboardPlayerErrorCapabilityChanged,
+  kStarboardPlayerErrorMax,
+};
+
+// Copy of SbDrmEncryptionScheme from starboard.
+enum StarboardDrmEncryptionScheme {
+  kStarboardDrmEncryptionSchemeAesCtr,
+  kStarboardDrmEncryptionSchemeAesCbc,
+};
+
+// Copy of SbDrmStatus from starboard.
+enum StarboardDrmStatus {
+  kStarboardDrmStatusSuccess,
+  kStarboardDrmStatusTypeError,
+  kStarboardDrmStatusNotSupportedError,
+  kStarboardDrmStatusInvalidStateError,
+  kStarboardDrmStatusQuotaExceededError,
+  kStarboardDrmStatusUnknownError,
+};
+
+// Copy of SbDrmSessionRequestType from starboard.
+enum StarboardDrmSessionRequestType {
+  kStarboardDrmSessionRequestTypeLicenseRequest,
+  kStarboardDrmSessionRequestTypeLicenseRenewal,
+  kStarboardDrmSessionRequestTypeLicenseRelease,
+  kStarboardDrmSessionRequestTypeIndividualizationRequest,
+};
+
+// Copy of SbDrmKeyStatus from starboard.
+enum StarboardDrmKeyStatus {
+  kStarboardDrmKeyStatusUsable,
+  kStarboardDrmKeyStatusExpired,
+  kStarboardDrmKeyStatusReleased,
+  kStarboardDrmKeyStatusRestricted,
+  kStarboardDrmKeyStatusDownscaled,
+  kStarboardDrmKeyStatusPending,
+  kStarboardDrmKeyStatusError,
+};
+
+// Copy of SbMediaMasteringMetadata from starboard.
+struct StarboardMediaMasteringMetadata {
+  float primary_r_chromaticity_x;
+  float primary_r_chromaticity_y;
+  float primary_g_chromaticity_x;
+  float primary_g_chromaticity_y;
+  float primary_b_chromaticity_x;
+  float primary_b_chromaticity_y;
+  float white_point_chromaticity_x;
+  float white_point_chromaticity_y;
+  float luminance_max;
+  float luminance_min;
+};
+
+// Copy of SbMediaMasteringMetadata from starboard.
+struct StarboardColorMetadata {
+  unsigned int bits_per_channel;
+  unsigned int chroma_subsampling_horizontal;
+  unsigned int chroma_subsampling_vertical;
+  unsigned int cb_subsampling_horizontal;
+  unsigned int cb_subsampling_vertical;
+  unsigned int chroma_siting_horizontal;
+  unsigned int chroma_siting_vertical;
+  StarboardMediaMasteringMetadata mastering_metadata;
+  unsigned int max_cll;
+  unsigned int max_fall;
+  // See SbMediaPrimaryId from starboard.
+  int primaries;
+  // See SbMediaTransferId from starboard.
+  int transfer;
+  // See SbMediaMatrixId from starboard.
+  int matrix;
+  // See SbMediaRangeId from starboard.
+  int range;
+  float custom_primary_matrix[12];
+};
+
+// Copy of SbMediaAudioSampleInfo from starboard.
+struct StarboardAudioSampleInfo {
+  StarboardAudioCodec codec;
+  const char* mime;
+  uint16_t format_tag;
+  uint16_t number_of_channels;
+  uint32_t samples_per_second;
+  uint32_t average_bytes_per_second;
+  uint16_t block_alignment;
+  uint16_t bits_per_sample;
+  uint16_t audio_specific_config_size;
+  const void* audio_specific_config;
+};
+
+// Copy of SbMediaVideoSampleInfo from starboard.
+struct StarboardVideoSampleInfo {
+  StarboardVideoCodec codec;
+  const char* mime;
+  const char* max_video_capabilities;
+  bool is_key_frame;
+  int frame_width;
+  int frame_height;
+  StarboardColorMetadata color_metadata;
+};
+
+// Copy of SbPlayerSampleSideData from starboard.
+struct StarboardSampleSideData {
+  StarboardSampleSideDataType type;
+  const uint8_t* data;
+  size_t size;
+};
+
+// Copy of SbDrmEncryptionPattern from starboard.
+struct StarboardDrmEncryptionPattern {
+  uint32_t crypt_byte_block;
+  uint32_t skip_byte_block;
+};
+
+// Copy of SbDrmSubSampleMapping from starboard.
+struct StarboardDrmSubSampleMapping {
+  // How many bytes of the corresponding subsample are not encrypted
+  int32_t clear_byte_count;
+
+  // How many bytes of the corresponding subsample are encrypted.
+  int32_t encrypted_byte_count;
+};
+
+// Copy of SbDrmSampleInfo from starboard.
+struct StarboardDrmSampleInfo {
+  StarboardDrmEncryptionScheme encryption_scheme;
+
+  // The encryption pattern of this sample.
+  StarboardDrmEncryptionPattern encryption_pattern;
+
+  // The Initialization Vector needed to decrypt this sample.
+  uint8_t initialization_vector[16];
+  int initialization_vector_size;
+
+  // The ID of the license (or key) required to decrypt this sample. For
+  // PlayReady, this is the license GUID in packed little-endian binary form.
+  uint8_t identifier[16];
+  int identifier_size;
+
+  // The number of subsamples in this sample, must be at least 1.
+  int32_t subsample_count;
+
+  // The clear/encrypted mapping of each subsample in this sample. This must be
+  // an array of |subsample_count| mappings.
+  const StarboardDrmSubSampleMapping* subsample_mapping;
+};
+
+// Copy of SbPlayerSampleInfo from starboard.
+struct StarboardSampleInfo {
+  // See SbMediaType.
+  int type;
+  // Points to the buffer containing the sample data.
+  const void* buffer;
+  // Size of the data pointed to by |buffer|.
+  int buffer_size;
+  // The timestamp of the sample.
+  int64_t timestamp;
+  // Points to an array of side data for the input, when available.
+  StarboardSampleSideData* side_data;
+  // The number of side data pointed by |side_data|.  It should be set to 0 if
+  // there is no side data for the input.
+  int side_data_count;
+  union {
+    // Information about an audio sample. This value can only be used when
+    // |type| is kSbMediaTypeAudio.
+    StarboardAudioSampleInfo audio_sample_info;
+    // Information about a video sample. This value can only be used when |type|
+    // is kSbMediaTypeVideo.
+    StarboardVideoSampleInfo video_sample_info;
+  };
+  // The DRM system related info for the media sample. This value is required
+  // for encrypted samples. Otherwise, it must be |NULL|.
+  const StarboardDrmSampleInfo* drm_info;
+};
+
+// Copy of SbPlayerCreationParam from starboard.
+struct StarboardPlayerCreationParam {
+  // Note: a DRM system is not included in this struct. Due to the architecture
+  // of cast, the MediaPipelineBackend does not have direct access to the CDM.
+  // So instead we pass a global to Starboard (in starboard_media_api.cc).
+
+  // Contains a populated SbMediaAudioSampleInfo if |audio_sample_info.codec|
+  // isn't |kSbMediaAudioCodecNone|.  When |audio_sample_info.codec| is
+  // |kSbMediaAudioCodecNone|, the video doesn't have an audio track.
+  StarboardAudioSampleInfo audio_sample_info;
+
+  // Contains a populated SbMediaVideoSampleInfo if |video_sample_info.codec|
+  // isn't |kSbMediaVideoCodecNone|.  When |video_sample_info.codec| is
+  // |kSbMediaVideoCodecNone|, the video is audio only.
+  StarboardVideoSampleInfo video_sample_info;
+
+  // Selects how the decoded video frames will be output.  For example,
+  // |kSbPlayerOutputModePunchOut| indicates that the decoded video frames will
+  // be output to a background video layer by the platform, and
+  // |kSbPlayerOutputDecodeToTexture| indicates that the decoded video frames
+  // should be made available for the application to pull via calls to
+  // SbPlayerGetCurrentFrame().
+  StarboardPlayerOutputMode output_mode;
+};
+
+// Copy of SbPlayerInfo2 from starboard.
+struct StarboardPlayerInfo {
+  // The position of the playback head, as precisely as possible, in
+  // microseconds.
+  int64_t current_media_timestamp_micros;
+  // The known duration of the currently playing media stream, in microseconds.
+  int64_t duration_micros;
+  // The result of getStartDate for the currently playing media stream, in
+  // microseconds since the epoch of January 1, 1601 UTC.
+  int64_t start_date;
+  // The width of the currently displayed frame, in pixels, or 0 if not provided
+  // by this player.
+  int frame_width;
+  // The height of the currently displayed frame, in pixels, or 0 if not
+  // provided by this player.
+  int frame_height;
+  // Whether playback is currently paused.
+  bool is_paused;
+  // The current player volume in [0, 1].
+  double volume;
+  // The number of video frames sent to the player since the creation of the
+  // player.
+  int total_video_frames;
+  // The number of video frames decoded but not displayed since the creation of
+  // the player.
+  int dropped_video_frames;
+  // The number of video frames that failed to be decoded since the creation of
+  // the player.
+  int corrupted_video_frames;
+  // The rate of playback. The video is played back in a speed that is
+  // proportional to this. By default it is 1.0 which indicates that the
+  // playback is at normal speed. When it is greater than one, the video is
+  // played in a faster than normal speed. When it is less than one, the video
+  // is played in a slower than normal speed. Negative speeds are not supported.
+  double playback_rate;
+};
+
+// Copy of SbDrmKeyId from starboard.
+struct StarboardDrmKeyId {
+  uint8_t identifier[16];
+  int identifier_size;
+};
+
+// Copy of SbPlayerDecoderStatusFunc from starboard.
+using StarboardPlayerDecoderStatusFunc =
+    void (*)(void* player,
+             void* context,
+             StarboardMediaType type,
+             StarboardDecoderState decoder_state,
+             int ticket);
+
+// Copy of SbPlayerDeallocateSampleFunc from starboard.
+using StarboardPlayerDeallocateSampleFunc = void (*)(void* player,
+                                                     void* context,
+                                                     const void* sample_buffer);
+
+// Copy of SbPlayerStatusFunc from starboard.
+using StarboardPlayerStatusFunc = void (*)(void* player,
+                                           void* context,
+                                           StarboardPlayerState state,
+                                           int ticket);
+
+// Copy of SbPlayerErrorFunc from starboard.
+using StarboardPlayerErrorFunc = void (*)(void* player,
+                                          void* context,
+                                          StarboardPlayerError error,
+                                          const char* message);
+
+// Copy of SbDrmSessionUpdateRequestFunc from starboard.
+using StarboardDrmSessionUpdateRequestFunc =
+    void (*)(void* drm_system,
+             void* context,
+             int ticket,
+             StarboardDrmStatus status,
+             StarboardDrmSessionRequestType type,
+             const char* error_message,
+             const void* session_id,
+             int session_id_size,
+             const void* content,
+             int content_size,
+             const char* url);
+
+// Copy of SbDrmSessionUpdatedFunc from starboard.
+using StarboardDrmSessionUpdatedFunc = void (*)(void* drm_system,
+                                                void* context,
+                                                int ticket,
+                                                StarboardDrmStatus status,
+                                                const char* error_message,
+                                                const void* session_id,
+                                                int session_id_size);
+
+// Copy of SbDrmSessionKeyStatusesChangedFunc from starboard.
+using StarboardDrmSessionKeyStatusesChangedFunc =
+    void (*)(void* drm_system,
+             void* context,
+             const void* session_id,
+             int session_id_size,
+             int number_of_keys,
+             const StarboardDrmKeyId* key_ids,
+             const StarboardDrmKeyStatus* key_statuses);
+
+// Copy of SbDrmServerCertificateUpdatedFunc from starboard.
+using StarboardDrmServerCertificateUpdatedFunc =
+    void (*)(void* drm_system,
+             void* context,
+             int ticket,
+             StarboardDrmStatus status,
+             const char* error_message);
+
+// Copy of SbDrmSessionClosedFunc from starboard.
+using StarboardDrmSessionClosedFunc = void (*)(void* drm_system,
+                                               void* context,
+                                               const void* session_id,
+                                               int session_id_size);
+
+// A wrapper for the player-related callbacks that starboard calls.
+struct StarboardPlayerCallbackHandler {
+  // The context that will be passed to all functions.
+  void* context;
+  StarboardPlayerDecoderStatusFunc decoder_status_fn;
+  StarboardPlayerDeallocateSampleFunc deallocate_sample_fn;
+  StarboardPlayerStatusFunc player_status_fn;
+  StarboardPlayerErrorFunc player_error_fn;
+};
+
+// A wrapper for the DRM-related callbacks that starboard calls.
+struct StarboardDrmSystemCallbackHandler {
+  // The context that will be passed to all functions.
+  void* context;
+  StarboardDrmSessionUpdateRequestFunc update_request_fn;
+  StarboardDrmSessionUpdatedFunc session_updated_fn;
+  StarboardDrmSessionKeyStatusesChangedFunc key_statuses_changed_fn;
+  StarboardDrmServerCertificateUpdatedFunc server_certificate_updated_fn;
+  StarboardDrmSessionClosedFunc session_closed_fn;
+};
+
+// A wrapper around the Starboard API, allowing a mock to be used for testing.
+// It also abstracts away details specific to certain versions of Starboard, by
+// utilizing the structs defined above. Internally, those structs will be
+// converted to the relevant starboard structs for the given starboard version.
+class StarboardApiWrapper {
+ public:
+  virtual ~StarboardApiWrapper();
+
+  // This function matches the EnsureInitialized function in
+  // cast_starboard_api_adapter.h. It blocks until Starboard has started and
+  // returns true, or returns false if initialization fails.
+  //
+  // This function is included in this wrapper so we can avoid calling the
+  // production implementation in unit tests, thus removing a dependency on
+  // Starboard.
+  virtual bool EnsureInitialized() = 0;
+
+  // Version-agnostic functions for SbPlayer. See starboard/player.h for more
+  // info about the corresponding functions.
+  //
+  // StarboardPlayerCallbackHandler is used to wrap multiple callbacks that are
+  // passed to starboard.
+  virtual void* CreatePlayer(
+      const StarboardPlayerCreationParam* creation_param,
+      const StarboardPlayerCallbackHandler* callback_handler) = 0;
+  virtual void SetPlayerBounds(void* player,
+                               int z_index,
+                               int x,
+                               int y,
+                               int width,
+                               int height) = 0;
+  virtual void SeekTo(void* player, int64_t time, int seek_ticket) = 0;
+  virtual void WriteSample(void* player,
+                           StarboardMediaType type,
+                           StarboardSampleInfo* sample_infos,
+                           int sample_infos_count) = 0;
+  virtual void WriteEndOfStream(void* player, StarboardMediaType type) = 0;
+  virtual void GetPlayerInfo(void* player,
+                             StarboardPlayerInfo* player_info) = 0;
+  virtual void SetVolume(void* player, double volume) = 0;
+  virtual bool SetPlaybackRate(void* player, double playback_rate) = 0;
+  virtual void DestroyPlayer(void* player) = 0;
+
+  // Version-agnostic functions for SbDrmSystem. See starboard/drm.h for more
+  // info about the corresponding functions.
+  //
+  // StarboardDrmSystemCallbackHandler is used to wrap multiple callbacks that
+  // are passed to starboard.
+  virtual void* CreateDrmSystem(
+      const char* key_system,
+      const StarboardDrmSystemCallbackHandler* callback_handler) = 0;
+  virtual void DrmGenerateSessionUpdateRequest(
+      void* drm_system,
+      int ticket,
+      const char* type,
+      const void* initialization_data,
+      int initialization_data_size) = 0;
+  virtual void DrmUpdateSession(void* drm_system,
+                                int ticket,
+                                const void* key,
+                                int key_size,
+                                const void* session_id,
+                                int session_id_size) = 0;
+  virtual void DrmCloseSession(void* drm_system,
+                               const void* session_id,
+                               int session_id_size) = 0;
+  virtual void DrmUpdateServerCertificate(void* drm_system,
+                                          int ticket,
+                                          const void* certificate,
+                                          int certificate_size) = 0;
+  virtual bool DrmIsServerCertificateUpdatable(void* drm_system) = 0;
+  virtual void DrmDestroySystem(void* drm_system) = 0;
+};
+
+// Returns a StarboardApiWrapper that calls into libcast_starboard_api.so. This
+// function is defined for each starboard version supported by cast. For
+// example, there is a starboard 15 version that calls the starboard 15 APIs, a
+// starboard 14 version that calls the starboard 14 APIs, etc.
+std::unique_ptr<StarboardApiWrapper> GetStarboardApiWrapper();
+
+}  // namespace media
+}  // namespace chromecast
+
+#endif  // CHROMECAST_STARBOARD_MEDIA_MEDIA_STARBOARD_API_WRAPPER_H_
diff --git a/chromecast/starboard/media/media/starboard_api_wrapper_14.cc b/chromecast/starboard/media/media/starboard_api_wrapper_14.cc
new file mode 100644
index 0000000..624d1cd
--- /dev/null
+++ b/chromecast/starboard/media/media/starboard_api_wrapper_14.cc
@@ -0,0 +1,166 @@
+// 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.
+
+// Defines APIs that are specific to Starboard 14. GetStarboardApiWrapper() is
+// the public API; everything else is an implementation detail.
+#include <starboard/drm.h>
+#include <starboard/media.h>
+#include <starboard/player.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/logging.h"
+#include "chromecast/starboard/media/media/starboard_api_wrapper_base.h"
+
+namespace chromecast {
+namespace media {
+
+namespace {
+
+// A concrete implementation of StarboardApiWrapper for Starboard version 14.
+class StarboardApiWrapper14 : public StarboardApiWrapperBase {
+ public:
+  StarboardApiWrapper14() = default;
+  ~StarboardApiWrapper14() override = default;
+
+  // StarboardApiWrapper impl:
+  void SeekTo(void* player, int64_t time, int seek_ticket) override {
+    SbPlayerSeek2(static_cast<SbPlayer>(player), time, seek_ticket);
+  }
+
+  void GetPlayerInfo(void* player, StarboardPlayerInfo* player_info) override {
+    SbPlayerInfo2 sb_player_info = {};
+    SbPlayerGetInfo2(static_cast<SbPlayer>(player), &sb_player_info);
+
+    player_info->current_media_timestamp_micros =
+        sb_player_info.current_media_timestamp;
+    player_info->duration_micros = sb_player_info.duration;
+    player_info->start_date = sb_player_info.start_date;
+    player_info->frame_width = sb_player_info.frame_width;
+    player_info->frame_height = sb_player_info.frame_height;
+    player_info->is_paused = sb_player_info.is_paused;
+    player_info->volume = sb_player_info.volume;
+    player_info->total_video_frames = sb_player_info.total_video_frames;
+    player_info->dropped_video_frames = sb_player_info.dropped_video_frames;
+    player_info->corrupted_video_frames = sb_player_info.corrupted_video_frames;
+    player_info->playback_rate = sb_player_info.playback_rate;
+  }
+
+ private:
+  // StarboardApiWrapperBase impl:
+  SbPlayerCreationParam ToSbPlayerCreationParam(
+      const StarboardPlayerCreationParam& in_param,
+      void* drm_system) override {
+    SbPlayerCreationParam out_param = {};
+
+    out_param.audio_sample_info =
+        ToSbMediaAudioSampleInfo(in_param.audio_sample_info);
+    out_param.video_sample_info =
+        ToSbMediaVideoSampleInfo(in_param.video_sample_info);
+    out_param.output_mode =
+        static_cast<SbPlayerOutputMode>(in_param.output_mode);
+
+    if (drm_system) {
+      LOG(INFO) << "Using an SbDrmSystem for decryption.";
+      out_param.drm_system = static_cast<SbDrmSystem>(drm_system);
+    } else {
+      LOG(INFO)
+          << "No SbDrmSystem was created before SbPlayer; no decryption is "
+             "possible in starboard.";
+      out_param.drm_system = kSbDrmSystemInvalid;
+    }
+
+    return out_param;
+  }
+
+  SbMediaVideoSampleInfo ToSbMediaVideoSampleInfo(
+      const StarboardVideoSampleInfo& in_video_info) override {
+    SbMediaVideoSampleInfo out_video_info = {};
+
+    out_video_info.codec = static_cast<SbMediaVideoCodec>(in_video_info.codec);
+    out_video_info.mime = in_video_info.mime;
+    out_video_info.max_video_capabilities =
+        in_video_info.max_video_capabilities;
+    out_video_info.is_key_frame = in_video_info.is_key_frame;
+    out_video_info.frame_width = in_video_info.frame_width;
+    out_video_info.frame_height = in_video_info.frame_height;
+
+    const StarboardColorMetadata& in_color_metadata =
+        in_video_info.color_metadata;
+    SbMediaColorMetadata& out_color_metadata = out_video_info.color_metadata;
+
+    out_color_metadata.bits_per_channel = in_color_metadata.bits_per_channel;
+    out_color_metadata.chroma_subsampling_horizontal =
+        in_color_metadata.chroma_subsampling_horizontal;
+    out_color_metadata.chroma_subsampling_vertical =
+        in_color_metadata.chroma_subsampling_vertical;
+    out_color_metadata.cb_subsampling_horizontal =
+        in_color_metadata.cb_subsampling_horizontal;
+    out_color_metadata.cb_subsampling_vertical =
+        in_color_metadata.cb_subsampling_vertical;
+    out_color_metadata.chroma_siting_horizontal =
+        in_color_metadata.chroma_siting_horizontal;
+    out_color_metadata.chroma_siting_vertical =
+        in_color_metadata.chroma_siting_vertical;
+    // note: we skip SbMediaMasteringMetadata
+    out_color_metadata.max_cll = in_color_metadata.max_cll;
+    out_color_metadata.max_fall = in_color_metadata.max_fall;
+    out_color_metadata.primaries =
+        static_cast<SbMediaPrimaryId>(in_color_metadata.primaries);
+    out_color_metadata.transfer =
+        static_cast<SbMediaTransferId>(in_color_metadata.transfer);
+    out_color_metadata.matrix =
+        static_cast<SbMediaMatrixId>(in_color_metadata.matrix);
+    out_color_metadata.range =
+        static_cast<SbMediaRangeId>(in_color_metadata.range);
+
+    static_assert(sizeof(out_color_metadata.custom_primary_matrix) ==
+                      sizeof(in_color_metadata.custom_primary_matrix),
+                  "Struct field size mismatch (custom_primary_matrix)");
+    memcpy(out_color_metadata.custom_primary_matrix,
+           in_color_metadata.custom_primary_matrix,
+           sizeof(out_color_metadata.custom_primary_matrix));
+
+    return out_video_info;
+  }
+
+  SbMediaAudioSampleInfo ToSbMediaAudioSampleInfo(
+      const StarboardAudioSampleInfo& in_audio_info) override {
+    SbMediaAudioSampleInfo out_audio_info = {};
+
+    out_audio_info.codec = static_cast<SbMediaAudioCodec>(in_audio_info.codec);
+    out_audio_info.mime = in_audio_info.mime;
+    out_audio_info.format_tag = in_audio_info.format_tag;
+    out_audio_info.number_of_channels = in_audio_info.number_of_channels;
+    out_audio_info.samples_per_second = in_audio_info.samples_per_second;
+    out_audio_info.average_bytes_per_second =
+        in_audio_info.average_bytes_per_second;
+    out_audio_info.block_alignment = in_audio_info.block_alignment;
+    out_audio_info.bits_per_sample = in_audio_info.bits_per_sample;
+    out_audio_info.audio_specific_config_size =
+        in_audio_info.audio_specific_config_size;
+    out_audio_info.audio_specific_config = in_audio_info.audio_specific_config;
+
+    return out_audio_info;
+  }
+
+  void CallWriteSamples(SbPlayer player,
+                        SbMediaType sample_type,
+                        const SbPlayerSampleInfo* sample_infos,
+                        int number_of_sample_infos) override {
+    SbPlayerWriteSample2(player, sample_type, sample_infos,
+                         number_of_sample_infos);
+  }
+};
+
+}  // namespace
+
+// Note: declared in starboard_api_wrapper.h.
+std::unique_ptr<StarboardApiWrapper> GetStarboardApiWrapper() {
+  return std::make_unique<StarboardApiWrapper14>();
+}
+
+}  // namespace media
+}  // namespace chromecast
diff --git a/chromecast/starboard/media/media/starboard_api_wrapper_15.cc b/chromecast/starboard/media/media/starboard_api_wrapper_15.cc
new file mode 100644
index 0000000..b78e1f9a
--- /dev/null
+++ b/chromecast/starboard/media/media/starboard_api_wrapper_15.cc
@@ -0,0 +1,178 @@
+// 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.
+
+// Defines APIs that are specific to Starboard 15. GetStarboardApiWrapper() is
+// the public API; everything else is an implementation detail.
+#include <starboard/drm.h>
+#include <starboard/media.h>
+#include <starboard/player.h>
+
+#include "base/logging.h"
+#include "chromecast/starboard/media/media/starboard_api_wrapper_base.h"
+
+namespace chromecast {
+namespace media {
+
+namespace {
+
+// Populates a VideoStreamInfo struct from a StarboardVideoSampleInfo.
+SbMediaVideoStreamInfo ToSbMediaVideoStreamInfo(
+    const StarboardVideoSampleInfo& in_video_info) {
+  SbMediaVideoStreamInfo out_video_info = {};
+
+  out_video_info.codec = static_cast<SbMediaVideoCodec>(in_video_info.codec);
+  out_video_info.mime = in_video_info.mime;
+  out_video_info.max_video_capabilities = in_video_info.max_video_capabilities;
+  out_video_info.frame_width = in_video_info.frame_width;
+  out_video_info.frame_height = in_video_info.frame_height;
+
+  const StarboardColorMetadata& in_color_metadata =
+      in_video_info.color_metadata;
+  SbMediaColorMetadata& out_color_metadata = out_video_info.color_metadata;
+
+  out_color_metadata.bits_per_channel = in_color_metadata.bits_per_channel;
+  out_color_metadata.chroma_subsampling_horizontal =
+      in_color_metadata.chroma_subsampling_horizontal;
+  out_color_metadata.chroma_subsampling_vertical =
+      in_color_metadata.chroma_subsampling_vertical;
+  out_color_metadata.cb_subsampling_horizontal =
+      in_color_metadata.cb_subsampling_horizontal;
+  out_color_metadata.cb_subsampling_vertical =
+      in_color_metadata.cb_subsampling_vertical;
+  out_color_metadata.chroma_siting_horizontal =
+      in_color_metadata.chroma_siting_horizontal;
+  out_color_metadata.chroma_siting_vertical =
+      in_color_metadata.chroma_siting_vertical;
+  // note: we skip SbMediaMasteringMetadata
+  out_color_metadata.max_cll = in_color_metadata.max_cll;
+  out_color_metadata.max_fall = in_color_metadata.max_fall;
+  out_color_metadata.primaries =
+      static_cast<SbMediaPrimaryId>(in_color_metadata.primaries);
+  out_color_metadata.transfer =
+      static_cast<SbMediaTransferId>(in_color_metadata.transfer);
+  out_color_metadata.matrix =
+      static_cast<SbMediaMatrixId>(in_color_metadata.matrix);
+  out_color_metadata.range =
+      static_cast<SbMediaRangeId>(in_color_metadata.range);
+
+  static_assert(sizeof(out_color_metadata.custom_primary_matrix) ==
+                    sizeof(in_color_metadata.custom_primary_matrix),
+                "Struct field size mismatch (custom_primary_matrix)");
+  memcpy(out_color_metadata.custom_primary_matrix,
+         in_color_metadata.custom_primary_matrix,
+         sizeof(out_color_metadata.custom_primary_matrix));
+
+  return out_video_info;
+}
+
+// Populates an AudioStreamInfo struct from a StarboardAudioSampleInfo.
+SbMediaAudioStreamInfo ToSbMediaAudioStreamInfo(
+    const StarboardAudioSampleInfo& in_audio_info) {
+  SbMediaAudioStreamInfo out_audio_info = {};
+
+  out_audio_info.codec = static_cast<SbMediaAudioCodec>(in_audio_info.codec);
+  out_audio_info.mime = in_audio_info.mime;
+  out_audio_info.number_of_channels = in_audio_info.number_of_channels;
+  out_audio_info.samples_per_second = in_audio_info.samples_per_second;
+  out_audio_info.bits_per_sample = in_audio_info.bits_per_sample;
+  out_audio_info.audio_specific_config_size =
+      in_audio_info.audio_specific_config_size;
+  out_audio_info.audio_specific_config = in_audio_info.audio_specific_config;
+
+  return out_audio_info;
+}
+
+// A concrete implementation of StarboardApiWrapper for Starboard version 15.
+class StarboardApiWrapper15 : public StarboardApiWrapperBase {
+ public:
+  StarboardApiWrapper15() = default;
+  ~StarboardApiWrapper15() override = default;
+
+  // StarboardApiWrapper impl:
+  void SeekTo(void* player, int64_t time, int seek_ticket) override {
+    SbPlayerSeek(static_cast<SbPlayer>(player), time, seek_ticket);
+  }
+
+  void GetPlayerInfo(void* player, StarboardPlayerInfo* player_info) override {
+    SbPlayerInfo sb_player_info = {};
+    SbPlayerGetInfo(static_cast<SbPlayer>(player), &sb_player_info);
+
+    player_info->current_media_timestamp_micros =
+        sb_player_info.current_media_timestamp;
+    player_info->duration_micros = sb_player_info.duration;
+    player_info->start_date = sb_player_info.start_date;
+    player_info->frame_width = sb_player_info.frame_width;
+    player_info->frame_height = sb_player_info.frame_height;
+    player_info->is_paused = sb_player_info.is_paused;
+    player_info->volume = sb_player_info.volume;
+    player_info->total_video_frames = sb_player_info.total_video_frames;
+    player_info->dropped_video_frames = sb_player_info.dropped_video_frames;
+    player_info->corrupted_video_frames = sb_player_info.corrupted_video_frames;
+    player_info->playback_rate = sb_player_info.playback_rate;
+  }
+
+ private:
+  // StarboardApiWrapperBase impl:
+  SbPlayerCreationParam ToSbPlayerCreationParam(
+      const StarboardPlayerCreationParam& in_param,
+      void* drm_system) override {
+    SbPlayerCreationParam out_param = {};
+
+    out_param.audio_stream_info =
+        ToSbMediaAudioStreamInfo(in_param.audio_sample_info);
+    out_param.video_stream_info =
+        ToSbMediaVideoStreamInfo(in_param.video_sample_info);
+    out_param.output_mode =
+        static_cast<SbPlayerOutputMode>(in_param.output_mode);
+
+    if (drm_system) {
+      LOG(INFO) << "Using an SbDrmSystem for decryption.";
+      out_param.drm_system = static_cast<SbDrmSystem>(drm_system);
+    } else {
+      LOG(INFO)
+          << "No SbDrmSystem was created before SbPlayer; no decryption is "
+             "possible in starboard.";
+      out_param.drm_system = kSbDrmSystemInvalid;
+    }
+
+    return out_param;
+  }
+
+  SbMediaVideoSampleInfo ToSbMediaVideoSampleInfo(
+      const StarboardVideoSampleInfo& in_video_info) override {
+    SbMediaVideoSampleInfo out_video_info;
+    out_video_info.stream_info = ToSbMediaVideoStreamInfo(in_video_info);
+    out_video_info.is_key_frame = in_video_info.is_key_frame;
+
+    return out_video_info;
+  }
+
+  SbMediaAudioSampleInfo ToSbMediaAudioSampleInfo(
+      const StarboardAudioSampleInfo& in_audio_info) override {
+    SbMediaAudioSampleInfo out_audio_info = {};
+    out_audio_info.stream_info = ToSbMediaAudioStreamInfo(in_audio_info);
+    out_audio_info.discarded_duration_from_front = 0;
+    out_audio_info.discarded_duration_from_back = 0;
+
+    return out_audio_info;
+  }
+
+  void CallWriteSamples(SbPlayer player,
+                        SbMediaType sample_type,
+                        const SbPlayerSampleInfo* sample_infos,
+                        int number_of_sample_infos) override {
+    SbPlayerWriteSamples(player, sample_type, sample_infos,
+                         number_of_sample_infos);
+  }
+};
+
+}  // namespace
+
+// Note: declared in starboard_api_wrapper.h.
+std::unique_ptr<StarboardApiWrapper> GetStarboardApiWrapper() {
+  return std::make_unique<StarboardApiWrapper15>();
+}
+
+}  // namespace media
+}  // namespace chromecast
diff --git a/chromecast/starboard/media/media/starboard_api_wrapper_base.cc b/chromecast/starboard/media/media/starboard_api_wrapper_base.cc
new file mode 100644
index 0000000..ea1251e
--- /dev/null
+++ b/chromecast/starboard/media/media/starboard_api_wrapper_base.cc
@@ -0,0 +1,395 @@
+// 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 "chromecast/starboard/media/media/starboard_api_wrapper_base.h"
+
+#include <starboard/drm.h>
+#include <starboard/media.h>
+#include <starboard/player.h>
+
+#include <cstring>
+#include <vector>
+
+#include "base/logging.h"
+#include "chromecast/starboard/chromecast/starboard_adapter/public/cast_starboard_api_adapter.h"
+#include "chromecast/starboard/media/media/starboard_api_wrapper.h"
+
+namespace chromecast {
+namespace media {
+
+namespace {
+
+// Set via StarboardCreateDrmSystem, and passed to the SbPlayer when the player
+// is created.
+SbDrmSystem g_drm_system = nullptr;
+
+void DeallocateSample(SbPlayer player,
+                      void* context,
+                      const void* sample_buffer) {
+  const auto* handler =
+      static_cast<const StarboardPlayerCallbackHandler*>(context);
+  handler->deallocate_sample_fn(player, handler->context, sample_buffer);
+}
+
+// Called by starboard to notify cast of a decoder state change.
+void OnDecoderStatus(SbPlayer player,
+                     void* context,
+                     SbMediaType type,
+                     SbPlayerDecoderState state,
+                     int ticket) {
+  const auto* handler =
+      static_cast<const StarboardPlayerCallbackHandler*>(context);
+  handler->decoder_status_fn(player, handler->context,
+                             static_cast<StarboardMediaType>(type),
+                             static_cast<StarboardDecoderState>(state), ticket);
+}
+
+// Called by starboard to notify cast of a player state change.
+void OnPlayerStatus(SbPlayer player,
+                    void* context,
+                    SbPlayerState state,
+                    int ticket) {
+  const auto* handler =
+      static_cast<const StarboardPlayerCallbackHandler*>(context);
+  handler->player_status_fn(player, handler->context,
+                            static_cast<StarboardPlayerState>(state), ticket);
+}
+
+// Called by starboard to notify cast of a player error.
+void OnPlayerError(SbPlayer player,
+                   void* context,
+                   SbPlayerError error,
+                   const char* message) {
+  const auto* handler =
+      static_cast<const StarboardPlayerCallbackHandler*>(context);
+  handler->player_error_fn(player, handler->context,
+                           static_cast<StarboardPlayerError>(error), message);
+}
+
+// Converts starboard's representation of a key ID to cast's version-agnostic
+// representation.
+StarboardDrmKeyId ToStarboardDrmKeyId(const SbDrmKeyId& in_key_id) {
+  StarboardDrmKeyId out_key_id = {};
+
+  static_assert(sizeof(in_key_id.identifier) == sizeof(out_key_id.identifier),
+                "StarboardDrmKeyId.identifier and SbDrmKeyId.identifier must "
+                "be arrays of the same size");
+
+  memcpy(out_key_id.identifier, in_key_id.identifier,
+         sizeof(out_key_id.identifier));
+  out_key_id.identifier_size = in_key_id.identifier_size;
+
+  return out_key_id;
+}
+
+// Called by starboard when a generated session update request is ready to be
+// sent to cast.
+void OnUpdateRequest(SbDrmSystem drm_system,
+                     void* context,
+                     int ticket,
+                     SbDrmStatus status,
+                     SbDrmSessionRequestType type,
+                     const char* error_message,
+                     const void* session_id,
+                     int session_id_size,
+                     const void* content,
+                     int content_size,
+                     const char* url) {
+  const auto* handler =
+      static_cast<const StarboardDrmSystemCallbackHandler*>(context);
+  handler->update_request_fn(drm_system, handler->context, ticket,
+                             static_cast<StarboardDrmStatus>(status),
+                             static_cast<StarboardDrmSessionRequestType>(type),
+                             error_message, session_id, session_id_size,
+                             content, content_size, url);
+}
+
+// Called by starboard to notify cast that a session has been updated.
+void OnSessionUpdated(SbDrmSystem drm_system,
+                      void* context,
+                      int ticket,
+                      SbDrmStatus status,
+                      const char* error_message,
+                      const void* session_id,
+                      int session_id_size) {
+  const auto* handler =
+      static_cast<const StarboardDrmSystemCallbackHandler*>(context);
+  handler->session_updated_fn(drm_system, handler->context, ticket,
+                              static_cast<StarboardDrmStatus>(status),
+                              error_message, session_id, session_id_size);
+}
+
+// Called by starboard to notify cast that key statuses have changed.
+void OnKeyStatusesChanged(SbDrmSystem drm_system,
+                          void* context,
+                          const void* session_id,
+                          int session_id_size,
+                          int number_of_keys,
+                          const SbDrmKeyId* key_ids,
+                          const SbDrmKeyStatus* key_statuses) {
+  std::vector<StarboardDrmKeyId> internal_key_ids;
+  std::vector<StarboardDrmKeyStatus> internal_key_statuses;
+
+  internal_key_ids.reserve(number_of_keys);
+  internal_key_statuses.reserve(number_of_keys);
+
+  for (int i = 0; i < number_of_keys; ++i) {
+    internal_key_ids.push_back(ToStarboardDrmKeyId(key_ids[i]));
+    internal_key_statuses.push_back(
+        static_cast<StarboardDrmKeyStatus>(key_statuses[i]));
+  }
+
+  const auto* handler =
+      static_cast<const StarboardDrmSystemCallbackHandler*>(context);
+  handler->key_statuses_changed_fn(
+      drm_system, handler->context, session_id, session_id_size, number_of_keys,
+      internal_key_ids.data(), internal_key_statuses.data());
+}
+
+// Called by starboard when a server certificate has been updated.
+void OnServerCertificateUpdated(SbDrmSystem drm_system,
+                                void* context,
+                                int ticket,
+                                SbDrmStatus status,
+                                const char* error_message) {
+  const auto* handler =
+      static_cast<const StarboardDrmSystemCallbackHandler*>(context);
+  handler->server_certificate_updated_fn(
+      drm_system, handler->context, ticket,
+      static_cast<StarboardDrmStatus>(status), error_message);
+}
+
+// Called by starboard when a DRM session has closed.
+void OnSessionClosed(SbDrmSystem drm_system,
+                     void* context,
+                     const void* session_id,
+                     int session_id_size) {
+  const auto* handler =
+      static_cast<const StarboardDrmSystemCallbackHandler*>(context);
+  handler->session_closed_fn(drm_system, handler->context, session_id,
+                             session_id_size);
+}
+
+}  // namespace
+
+StarboardApiWrapperBase::StarboardApiWrapperBase() = default;
+StarboardApiWrapperBase::~StarboardApiWrapperBase() = default;
+
+bool StarboardApiWrapperBase::EnsureInitialized() {
+  return chromecast::CastStarboardApiAdapter::GetInstance()
+      ->EnsureInitialized();
+}
+
+void* StarboardApiWrapperBase::CreatePlayer(
+    const StarboardPlayerCreationParam* creation_param,
+    const StarboardPlayerCallbackHandler* callback_handler) {
+  SbWindow window =
+      chromecast::CastStarboardApiAdapter::GetInstance()->GetWindow(nullptr);
+
+  SbPlayerCreationParam sb_creation_param =
+      ToSbPlayerCreationParam(*creation_param, g_drm_system);
+
+  return SbPlayerCreate(
+      window, &sb_creation_param, &DeallocateSample, &OnDecoderStatus,
+      &OnPlayerStatus, &OnPlayerError,
+      /*context=*/
+      static_cast<void*>(
+          const_cast<StarboardPlayerCallbackHandler*>(callback_handler)),
+      nullptr);
+}
+
+void StarboardApiWrapperBase::SetPlayerBounds(void* player,
+                                              int z_index,
+                                              int x,
+                                              int y,
+                                              int width,
+                                              int height) {
+  SbPlayerSetBounds(static_cast<SbPlayer>(player), z_index, x, y, width,
+                    height);
+}
+
+void StarboardApiWrapperBase::WriteEndOfStream(void* player,
+                                               StarboardMediaType type) {
+  SbPlayerWriteEndOfStream(static_cast<SbPlayer>(player),
+                           static_cast<SbMediaType>(type));
+}
+
+void StarboardApiWrapperBase::SetVolume(void* player, double volume) {
+  SbPlayerSetVolume(static_cast<SbPlayer>(player), volume);
+}
+
+bool StarboardApiWrapperBase::SetPlaybackRate(void* player,
+                                              double playback_rate) {
+  return SbPlayerSetPlaybackRate(static_cast<SbPlayer>(player), playback_rate);
+}
+
+void StarboardApiWrapperBase::DestroyPlayer(void* player) {
+  SbPlayerDestroy(static_cast<SbPlayer>(player));
+}
+
+void* StarboardApiWrapperBase::CreateDrmSystem(
+    const char* key_system,
+    const StarboardDrmSystemCallbackHandler* callback_handler) {
+  // TODO(b/334171644): verify that this does not break any apps.
+  CHECK(g_drm_system == nullptr) << "An SbDrmSystem already exists";
+
+  LOG(INFO) << "Creating SbDrmSystem";
+  g_drm_system = SbDrmCreateSystem(
+      key_system,
+      /*context=*/
+      static_cast<void*>(
+          const_cast<StarboardDrmSystemCallbackHandler*>(callback_handler)),
+      &OnUpdateRequest, &OnSessionUpdated, &OnKeyStatusesChanged,
+      &OnServerCertificateUpdated, &OnSessionClosed);
+  return g_drm_system;
+}
+
+void StarboardApiWrapperBase::DrmGenerateSessionUpdateRequest(
+    void* drm_system,
+    int ticket,
+    const char* type,
+    const void* initialization_data,
+    int initialization_data_size) {
+  SbDrmGenerateSessionUpdateRequest(static_cast<SbDrmSystem>(drm_system),
+                                    ticket, type, initialization_data,
+                                    initialization_data_size);
+}
+
+void StarboardApiWrapperBase::DrmUpdateSession(void* drm_system,
+                                               int ticket,
+                                               const void* key,
+                                               int key_size,
+                                               const void* session_id,
+                                               int session_id_size) {
+  SbDrmUpdateSession(static_cast<SbDrmSystem>(drm_system), ticket, key,
+                     key_size, session_id, session_id_size);
+}
+
+void StarboardApiWrapperBase::DrmCloseSession(void* drm_system,
+                                              const void* session_id,
+                                              int session_id_size) {
+  SbDrmCloseSession(static_cast<SbDrmSystem>(drm_system), session_id,
+                    session_id_size);
+}
+
+void StarboardApiWrapperBase::DrmUpdateServerCertificate(
+    void* drm_system,
+    int ticket,
+    const void* certificate,
+    int certificate_size) {
+  SbDrmUpdateServerCertificate(static_cast<SbDrmSystem>(drm_system), ticket,
+                               certificate, certificate_size);
+}
+
+bool StarboardApiWrapperBase::DrmIsServerCertificateUpdatable(
+    void* drm_system) {
+  return SbDrmIsServerCertificateUpdatable(
+      static_cast<SbDrmSystem>(drm_system));
+}
+
+void StarboardApiWrapperBase::DrmDestroySystem(void* drm_system) {
+  CHECK_EQ(drm_system, reinterpret_cast<void*>(g_drm_system));
+
+  LOG(INFO) << "Destroying SbDrmSystem";
+  g_drm_system = nullptr;
+  SbDrmDestroySystem(static_cast<SbDrmSystem>(drm_system));
+}
+
+SbPlayerSampleInfo StarboardApiWrapperBase::ToSbPlayerSampleInfo(
+    const StarboardSampleInfo& in_info,
+    std::vector<SbPlayerSampleSideData>& side_data,
+    SbDrmSampleInfo& drm_info,
+    std::vector<SbDrmSubSampleMapping>& subsample_mappings) {
+  SbPlayerSampleInfo out_info = {};
+  out_info.type = static_cast<SbMediaType>(in_info.type);
+  out_info.buffer = in_info.buffer;
+  out_info.buffer_size = in_info.buffer_size;
+  out_info.timestamp = in_info.timestamp;
+
+  side_data.reserve(in_info.side_data_count);
+  for (int i = 0; i < in_info.side_data_count; ++i) {
+    const StarboardSampleSideData& in_side_data = in_info.side_data[i];
+    SbPlayerSampleSideData out_side_data;
+
+    out_side_data.type =
+        static_cast<SbPlayerSampleSideDataType>(in_side_data.type);
+    out_side_data.data = in_side_data.data;
+    out_side_data.size = in_side_data.size;
+
+    side_data.push_back(std::move(out_side_data));
+  }
+  out_info.side_data = side_data.empty() ? nullptr : side_data.data();
+  out_info.side_data_count = side_data.size();
+
+  // Set the audio/video specific fields.
+  switch (in_info.type) {
+    case kStarboardMediaTypeAudio:
+      out_info.audio_sample_info =
+          ToSbMediaAudioSampleInfo(in_info.audio_sample_info);
+      break;
+    case kStarboardMediaTypeVideo:
+      out_info.video_sample_info =
+          ToSbMediaVideoSampleInfo(in_info.video_sample_info);
+      break;
+  }
+
+  if (in_info.drm_info) {
+    const StarboardDrmSampleInfo& in_drm_info = *in_info.drm_info;
+
+    drm_info.encryption_scheme =
+        static_cast<SbDrmEncryptionScheme>(in_drm_info.encryption_scheme);
+    drm_info.encryption_pattern.crypt_byte_block =
+        in_drm_info.encryption_pattern.crypt_byte_block;
+    drm_info.encryption_pattern.skip_byte_block =
+        in_drm_info.encryption_pattern.skip_byte_block;
+
+    memcpy(drm_info.initialization_vector, in_drm_info.initialization_vector,
+           in_drm_info.initialization_vector_size);
+    drm_info.initialization_vector_size =
+        in_drm_info.initialization_vector_size;
+
+    memcpy(drm_info.identifier, in_drm_info.identifier,
+           in_drm_info.identifier_size);
+    drm_info.identifier_size = in_drm_info.identifier_size;
+
+    subsample_mappings.reserve(in_drm_info.subsample_count);
+    for (int i = 0; i < in_drm_info.subsample_count; ++i) {
+      SbDrmSubSampleMapping mapping;
+      mapping.clear_byte_count =
+          in_drm_info.subsample_mapping[i].clear_byte_count;
+      mapping.encrypted_byte_count =
+          in_drm_info.subsample_mapping[i].encrypted_byte_count;
+      subsample_mappings.push_back(std::move(mapping));
+    }
+    drm_info.subsample_count = subsample_mappings.size();
+    drm_info.subsample_mapping =
+        subsample_mappings.empty() ? nullptr : subsample_mappings.data();
+
+    out_info.drm_info = &drm_info;
+  } else {
+    out_info.drm_info = nullptr;
+  }
+  return out_info;
+}
+
+void StarboardApiWrapperBase::WriteSample(void* player,
+                                          StarboardMediaType type,
+                                          StarboardSampleInfo* sample_infos,
+                                          int sample_infos_count) {
+  std::vector<SbPlayerSampleInfo> samples;
+  std::vector<std::vector<SbPlayerSampleSideData>> side_data;
+  SbDrmSampleInfo drm_info;
+  std::vector<SbDrmSubSampleMapping> subsample_mappings;
+  for (int i = 0; i < sample_infos_count; ++i) {
+    side_data.push_back({});
+    samples.push_back(ToSbPlayerSampleInfo(sample_infos[i], side_data.back(),
+                                           drm_info, subsample_mappings));
+  }
+  CallWriteSamples(static_cast<SbPlayer>(player),
+                   static_cast<SbMediaType>(type), samples.data(),
+                   sample_infos_count);
+}
+
+}  // namespace media
+}  // namespace chromecast
diff --git a/chromecast/starboard/media/media/starboard_api_wrapper_base.h b/chromecast/starboard/media/media/starboard_api_wrapper_base.h
new file mode 100644
index 0000000..f7aaf0b3
--- /dev/null
+++ b/chromecast/starboard/media/media/starboard_api_wrapper_base.h
@@ -0,0 +1,108 @@
+// 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 CHROMECAST_STARBOARD_MEDIA_MEDIA_STARBOARD_API_WRAPPER_BASE_H_
+#define CHROMECAST_STARBOARD_MEDIA_MEDIA_STARBOARD_API_WRAPPER_BASE_H_
+
+#include <starboard/media.h>
+#include <starboard/player.h>
+
+#include <vector>
+
+#include "chromecast/starboard/media/media/starboard_api_wrapper.h"
+
+namespace chromecast {
+namespace media {
+
+// Implements the functions of StarboardApiWrapper that are common across
+// different starboard versions. This is still an abstract class, as it does not
+// implement all of StarboardApiWrapper's functions.
+class StarboardApiWrapperBase : public StarboardApiWrapper {
+ public:
+  StarboardApiWrapperBase();
+  ~StarboardApiWrapperBase() override;
+
+  // StarboardApiWrapper impl:
+  bool EnsureInitialized() override;
+  void* CreatePlayer(
+      const StarboardPlayerCreationParam* creation_param,
+      const StarboardPlayerCallbackHandler* callback_handler) override;
+  void SetPlayerBounds(void* player,
+                       int z_index,
+                       int x,
+                       int y,
+                       int width,
+                       int height) override;
+  void WriteSample(void* player,
+                   StarboardMediaType type,
+                   StarboardSampleInfo* sample_infos,
+                   int sample_infos_count) override;
+  void WriteEndOfStream(void* player, StarboardMediaType type) override;
+  void SetVolume(void* player, double volume) override;
+  bool SetPlaybackRate(void* player, double playback_rate) override;
+  void DestroyPlayer(void* player) override;
+  void* CreateDrmSystem(
+      const char* key_system,
+      const StarboardDrmSystemCallbackHandler* callback_handler) override;
+  void DrmGenerateSessionUpdateRequest(void* drm_system,
+                                       int ticket,
+                                       const char* type,
+                                       const void* initialization_data,
+                                       int initialization_data_size) override;
+  void DrmUpdateSession(void* drm_system,
+                        int ticket,
+                        const void* key,
+                        int key_size,
+                        const void* session_id,
+                        int session_id_size) override;
+  void DrmCloseSession(void* drm_system,
+                       const void* session_id,
+                       int session_id_size) override;
+  void DrmUpdateServerCertificate(void* drm_system,
+                                  int ticket,
+                                  const void* certificate,
+                                  int certificate_size) override;
+  bool DrmIsServerCertificateUpdatable(void* drm_system) override;
+  void DrmDestroySystem(void* drm_system) override;
+
+ private:
+  // Converts StarboardSampleInfo to SbPlayerSampleInfo. `side_data` is used to
+  // store side data for this sample, since that data must outlive this function
+  // call. Same for `drm_info` and `subsample_mappings`.
+  //
+  // `side_data` and `subsample_mappings` should be empty vectors. They will be
+  // populated as necessary, so that they can outlive the later call to
+  // SbPlayerWriteSample.
+  SbPlayerSampleInfo ToSbPlayerSampleInfo(
+      const StarboardSampleInfo& in_info,
+      std::vector<SbPlayerSampleSideData>& side_data,
+      SbDrmSampleInfo& drm_info,
+      std::vector<SbDrmSubSampleMapping>& subsample_mappings);
+
+  // Converts the version-agnostic StarboardPlayerCreationParam to starboard's
+  // SbPlayerCreationParam.
+  virtual SbPlayerCreationParam ToSbPlayerCreationParam(
+      const StarboardPlayerCreationParam& in_param,
+      void* drm_system) = 0;
+
+  // Converts from cast's version-agnostic struct to starboard's version.
+  virtual SbMediaVideoSampleInfo ToSbMediaVideoSampleInfo(
+      const StarboardVideoSampleInfo& in_video_info) = 0;
+
+  // Converts from cast's version-agnostic struct to starboard's version.
+  virtual SbMediaAudioSampleInfo ToSbMediaAudioSampleInfo(
+      const StarboardAudioSampleInfo& in_audio_info) = 0;
+
+  // Calls the relevant starboard version's function to write samples (e.g.
+  // SbPlayerWriteSamples or SbPlayerWriteSample2).
+  virtual void CallWriteSamples(SbPlayer player,
+                                SbMediaType sample_type,
+                                const SbPlayerSampleInfo* sample_infos,
+                                int number_of_sample_infos) = 0;
+};
+
+}  // namespace media
+}  // namespace chromecast
+
+#endif  // CHROMECAST_STARBOARD_MEDIA_MEDIA_STARBOARD_API_WRAPPER_BASE_H_
diff --git a/chromecast/starboard/media/media/starboard_api_wrapper_dummy.cc b/chromecast/starboard/media/media/starboard_api_wrapper_dummy.cc
new file mode 100644
index 0000000..efade84
--- /dev/null
+++ b/chromecast/starboard/media/media/starboard_api_wrapper_dummy.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 "chromecast/starboard/media/media/starboard_api_wrapper.h"
+
+namespace chromecast {
+namespace media {
+
+std::unique_ptr<StarboardApiWrapper> GetStarboardApiWrapper() {
+  return nullptr;
+}
+
+}  // namespace media
+}  // namespace chromecast
diff --git a/chromecast/starboard/starboard.gni b/chromecast/starboard/starboard.gni
new file mode 100644
index 0000000..51aef967
--- /dev/null
+++ b/chromecast/starboard/starboard.gni
@@ -0,0 +1,8 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+declare_args() {
+  # If true, starboard headers are NOT included. Cast will not function.
+  remove_starboard_headers = true
+}
diff --git a/chromeos/ash/components/wifi_p2p/wifi_p2p_controller.cc b/chromeos/ash/components/wifi_p2p/wifi_p2p_controller.cc
index 93070e4..c0256c2 100644
--- a/chromeos/ash/components/wifi_p2p/wifi_p2p_controller.cc
+++ b/chromeos/ash/components/wifi_p2p/wifi_p2p_controller.cc
@@ -70,7 +70,28 @@
   }
 
   NET_LOG(ERROR) << "Unexpected result code: " << shill_result_code;
-  return WifiP2PController::OperationResult::kUnknownError;
+  return WifiP2PController::OperationResult::kInvalidResultCode;
+}
+
+bool IsDigitOrAlpha(char c) {
+  return std::isdigit(c) || std::isalpha(c);
+}
+
+// WiFi Direct ssid should follows WiFi Direct v1.9 3.2.1 (I.e. must begin with
+// DIRECT-xy where x and y are random letters/numbers). The passphrase must be
+// at least 8 character long.
+bool ValidateWifiDirectCredentails(const std::string& ssid,
+                                   const std::string& passphrase) {
+  if (ssid.length() != 9 || !ssid.starts_with("DIRECT-") ||
+      !IsDigitOrAlpha(ssid[7]) || !IsDigitOrAlpha(ssid[8])) {
+    NET_LOG(ERROR) << "Invalid SSID for WiFi Direct.";
+    return false;
+  }
+  if (passphrase.length() < 8) {
+    NET_LOG(ERROR) << "Invalid passphrase for WiFi Direct.";
+    return false;
+  }
+  return true;
 }
 
 }  // namespace
@@ -125,6 +146,12 @@
 void WifiP2PController::CreateWifiP2PGroup(const std::string& ssid,
                                            const std::string& passphrase,
                                            WifiP2PGroupCallback callback) {
+  if (!ValidateWifiDirectCredentails(ssid, passphrase)) {
+    std::move(callback).Run(OperationResult::kInvalidArguments,
+                            /*metadata=*/std::nullopt);
+    return;
+  }
+
   auto callback_split = base::SplitOnceCallback(std::move(callback));
   ShillManagerClient::Get()->CreateP2PGroup(
       ShillManagerClient::CreateP2PGroupParameter{ssid, passphrase},
diff --git a/chromeos/ash/components/wifi_p2p/wifi_p2p_controller.h b/chromeos/ash/components/wifi_p2p/wifi_p2p_controller.h
index 397cb37..e8dce8b 100644
--- a/chromeos/ash/components/wifi_p2p/wifi_p2p_controller.h
+++ b/chromeos/ash/components/wifi_p2p/wifi_p2p_controller.h
@@ -76,8 +76,6 @@
     kOperationFailed,
     // Wifi direct operation failed due to DBus error.
     kDBusError,
-    // Unknown error.
-    kUnknownError,
   };
 
   // Return callback for the CreateWifiP2PGroup or ConnectToWifiP2PGroup
diff --git a/chromeos/ash/components/wifi_p2p/wifi_p2p_controller_unittest.cc b/chromeos/ash/components/wifi_p2p/wifi_p2p_controller_unittest.cc
index 189eab8..3982f83 100644
--- a/chromeos/ash/components/wifi_p2p/wifi_p2p_controller_unittest.cc
+++ b/chromeos/ash/components/wifi_p2p/wifi_p2p_controller_unittest.cc
@@ -123,7 +123,7 @@
       ->SetSimulateCreateP2PGroupResult(FakeShillSimulatedResult::kSuccess,
                                         shill::kCreateP2PGroupResultSuccess);
   const WifiP2POperationTestResult& result_arguments =
-      CreateP2PGroup("ssid", "passphrase");
+      CreateP2PGroup("DIRECT-1a", "passphrase");
   EXPECT_EQ(result_arguments.result,
             WifiP2PController::OperationResult::kSuccess);
   ASSERT_TRUE(result_arguments.metadata);
@@ -159,7 +159,7 @@
       ->SetSimulateCreateP2PGroupResult(FakeShillSimulatedResult::kFailure,
                                         std::string());
   const WifiP2POperationTestResult& result_arguments =
-      CreateP2PGroup("ssid", "passphrase");
+      CreateP2PGroup("DIRECT-1a", "passphrase");
   EXPECT_EQ(result_arguments.result,
             WifiP2PController::OperationResult::kDBusError);
   EXPECT_FALSE(result_arguments.metadata);
@@ -176,7 +176,7 @@
           FakeShillSimulatedResult::kSuccess,
           shill::kConnectToP2PGroupResultSuccess);
   const WifiP2POperationTestResult& result_arguments =
-      ConnectP2PGroup("ssid", "passphrase", /*frequency=*/5200u);
+      ConnectP2PGroup("DIRECT-1a", "passphrase", /*frequency=*/5200u);
   EXPECT_EQ(result_arguments.result,
             WifiP2PController::OperationResult::kSuccess);
   ASSERT_TRUE(result_arguments.metadata);
@@ -197,7 +197,7 @@
           FakeShillSimulatedResult::kSuccess,
           shill::kConnectToP2PGroupResultConcurrencyNotSupported);
   const WifiP2POperationTestResult& result_arguments =
-      ConnectP2PGroup("ssid", "passphrase", /*frequency=*/5200u);
+      ConnectP2PGroup("DIRECT-1a", "passphrase", /*frequency=*/5200u);
   EXPECT_EQ(result_arguments.result,
             WifiP2PController::OperationResult::kConcurrencyNotSupported);
   EXPECT_FALSE(result_arguments.metadata);
diff --git a/chromeos/ash/services/BUILD.gn b/chromeos/ash/services/BUILD.gn
index 5a996f93..64acd2c 100644
--- a/chromeos/ash/services/BUILD.gn
+++ b/chromeos/ash/services/BUILD.gn
@@ -37,6 +37,7 @@
     "//chromeos/ash/services/quick_pair:unit_tests",
     "//chromeos/ash/services/recording:unit_tests",
     "//chromeos/ash/services/secure_channel:unit_tests",
+    "//chromeos/ash/services/wifi_direct:unit_tests",
     "//chromeos/services/machine_learning/public/cpp:ash_unit_tests",
   ]
 
diff --git a/chromeos/ash/services/nearby/public/mojom/BUILD.gn b/chromeos/ash/services/nearby/public/mojom/BUILD.gn
index 32dd0b7..9248c94 100644
--- a/chromeos/ash/services/nearby/public/mojom/BUILD.gn
+++ b/chromeos/ash/services/nearby/public/mojom/BUILD.gn
@@ -42,6 +42,7 @@
 
   public_deps = [
     ":nearby_share_settings",
+    "//chromeos/ash/services/wifi_direct/public/mojom",
     "//chromeos/services/network_config/public/mojom",
     "//device/bluetooth/public/mojom:deprecated_experimental_interfaces",
     "//mojo/public/mojom/base",
diff --git a/chromeos/ash/services/recording/webm_encoder_muxer.cc b/chromeos/ash/services/recording/webm_encoder_muxer.cc
index c675faec..23af6d3 100644
--- a/chromeos/ash/services/recording/webm_encoder_muxer.cc
+++ b/chromeos/ash/services/recording/webm_encoder_muxer.cc
@@ -396,8 +396,12 @@
 
   // TODO(crbug.com/1143798): Explore changing the WebmMuxer so it doesn't work
   // with strings, to avoid copying the encoded data.
-  std::string encoded_data{encoded_audio.encoded_data.begin(),
-                           encoded_audio.encoded_data.end()};
+  //
+  // Don't use encoded_buffer.encoded_data.end() as the encoded data size could
+  // be smaller than the allocated encoded_data.
+  std::string encoded_data(
+      encoded_audio.encoded_data.begin(),
+      encoded_audio.encoded_data.begin() + encoded_audio.encoded_data_size);
   muxer_adapter_.OnEncodedAudio(encoded_audio.params, std::move(encoded_data),
                                 std::move(codec_description),
                                 encoded_audio.timestamp);
diff --git a/chromeos/ash/services/wifi_direct/BUILD.gn b/chromeos/ash/services/wifi_direct/BUILD.gn
new file mode 100644
index 0000000..b785ee3d
--- /dev/null
+++ b/chromeos/ash/services/wifi_direct/BUILD.gn
@@ -0,0 +1,39 @@
+# 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")
+
+assert(is_chromeos_ash, "Non-ChromeOS builds cannot depend on //chromeos/ash")
+
+static_library("wifi_direct") {
+  sources = [
+    "wifi_direct_connection.cc",
+    "wifi_direct_connection.h",
+    "wifi_direct_manager.cc",
+    "wifi_direct_manager.h",
+  ]
+
+  public_deps = [
+    "//base",
+    "//chromeos/ash/components/dbus/shill",
+    "//chromeos/ash/components/wifi_p2p",
+    "//chromeos/ash/services/wifi_direct/public/mojom",
+  ]
+
+  deps = [ "//components/device_event_log" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+
+  sources = [ "wifi_direct_manager_unittest.cc" ]
+
+  deps = [
+    ":wifi_direct",
+    "//ash/constants",
+    "//base/test:test_support",
+    "//chromeos/ash/components/dbus/shill:test_support",
+    "//testing/gtest",
+  ]
+}
diff --git a/chromeos/ash/services/wifi_direct/OWNERS b/chromeos/ash/services/wifi_direct/OWNERS
new file mode 100644
index 0000000..32111e4
--- /dev/null
+++ b/chromeos/ash/services/wifi_direct/OWNERS
@@ -0,0 +1,3 @@
+jiajunz@google.com
+nikhilcn@google.com
+khorimoto@google.com
\ No newline at end of file
diff --git a/chromeos/ash/services/wifi_direct/public/mojom/BUILD.gn b/chromeos/ash/services/wifi_direct/public/mojom/BUILD.gn
new file mode 100644
index 0000000..ef892041
--- /dev/null
+++ b/chromeos/ash/services/wifi_direct/public/mojom/BUILD.gn
@@ -0,0 +1,13 @@
+# 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, "Non-ChromeOS builds cannot depend on //chromeos/ash")
+
+mojom("mojom") {
+  sources = [ "wifi_direct_manager.mojom" ]
+  public_deps = [ "//mojo/public/mojom/base" ]
+}
diff --git a/chromeos/ash/services/wifi_direct/public/mojom/OWNERS b/chromeos/ash/services/wifi_direct/public/mojom/OWNERS
new file mode 100644
index 0000000..61b5e28
--- /dev/null
+++ b/chromeos/ash/services/wifi_direct/public/mojom/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
\ No newline at end of file
diff --git a/chromeos/ash/services/wifi_direct/public/mojom/wifi_direct_manager.mojom b/chromeos/ash/services/wifi_direct/public/mojom/wifi_direct_manager.mojom
new file mode 100644
index 0000000..6e76b4f
--- /dev/null
+++ b/chromeos/ash/services/wifi_direct/public/mojom/wifi_direct_manager.mojom
@@ -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.
+
+module ash.wifi_direct.mojom;
+
+enum WifiDirectOperationResult {
+  kSuccess,
+  // Wifi direct is disallowed in platform per Manager.P2PAllowed.
+  kNotAllowed,
+  // Wifi direct operation is not supported in the platform.
+  kNotSupported,
+  // Creating Wifi direct interface is not possible with existing interfaces.
+  kConcurrencyNotSupported,
+  // The requested frequency is not supported.
+  kFrequencyNotSupported,
+  // Wifi direct group rejects the authentication attempt.
+  kAuthFailure,
+  // Didn't discover the Wifi direct group.
+  kGroupNotFound,
+  // Already connected to the Wifi direct group.
+  kAlreadyConnected,
+  kOperationInProgress,
+  kInvalidArguments,
+  // Wifi direct operation timed out.
+  kTimeout,
+  // Wifi direct operation response has an invalid result code.
+  kInvalidResultCode,
+  // Wifi direct group miss or has invalid properties.
+  kInvalidGroupProperties,
+  kUnknownFailure,
+};
+
+// WifiDirectManager provides Wifi direct management methods. An instance of
+// this interface is owned in the browser process in Ash.
+interface WifiDirectManager {
+  // Creates a WifiDirectConnection as group owner and returns a result along
+  // with a pending remote of WifiDirectConnection object (a NullRemote will be
+  // returned if the result is anything but kSuccess). Disconnecting from the
+  // remote object will invoke the disconnect handler in WifiDirectConnection
+  // that will in turn tear down the WiFi direct group. Callers should also
+  // register a disconnect handler on the remote side to be notified and handle
+  // the case where the Wifi direct group is disconnected by Shill internally.
+  // The ssid should be a UTF8 string that must match the requirements for a
+  // WiFi Direct ssid per WiFi Direct v1.9 3.2.1 (i.e. must begin with DIRECT-xy
+  // where x and y are random letters/numbers). The passphrase must be at least
+  // 8 characters long.
+  CreateWifiDirectGroup(string ssid, string password) =>
+    (WifiDirectOperationResult result,
+     pending_remote<WifiDirectConnection>? wifi_direct_connection);
+
+  // Connects to the Wifi Direct Group as group client and returns a result
+  // along with a pending remote of WifiDirectConnection object (a NullRemote
+  // will be returned if the result is anything but kSuccess). Disconnecting
+  // from the remote object will invoke the disconnect handler in
+  // WifiDirectConnection that will in turn disconnect to the WiFi direct group.
+  // Callers should also register a disconnect handler on the remote side to be
+  // notified and handle the case where the Wifi direct group is disconnected by
+  // Shill internally. If the frequency is provided, the operation will fail
+  // when the group is not found at the specified frequency. If the frequency
+  // is omitted, system will scan all supported channels to find the group.
+  ConnectToWifiDirectGroup(string ssid, string password, uint32? frequency) =>
+    (WifiDirectOperationResult result,
+     pending_remote<WifiDirectConnection>? wifi_direct_connection);
+};
+
+// WifiDirectConnection represents an active Wifi direct group that was created
+// or connected to from WifiDirectManager.
+interface WifiDirectConnection {
+  // Returns the frequency of the Wifi direct network group.
+  GetFrequency() => (uint32 frequency);
+};
\ No newline at end of file
diff --git a/chromeos/ash/services/wifi_direct/wifi_direct_connection.cc b/chromeos/ash/services/wifi_direct/wifi_direct_connection.cc
new file mode 100644
index 0000000..c3ba639
--- /dev/null
+++ b/chromeos/ash/services/wifi_direct/wifi_direct_connection.cc
@@ -0,0 +1,44 @@
+// 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/ash/services/wifi_direct/wifi_direct_connection.h"
+
+#include "mojo/public/cpp/bindings/pending_remote.h"
+
+namespace ash::wifi_direct {
+
+// static
+WifiDirectConnection::InstanceWithPendingRemotePair
+WifiDirectConnection::Create(int shill_id,
+                             uint32_t frequency,
+                             base::OnceClosure disconnect_handler) {
+  // Use base::WrapUnique(new WifiDirectConnection(...)) instead of
+  // std::make_unique<WifiDirectConnection> to access a private constructor.
+  std::unique_ptr<WifiDirectConnection> wifi_direct_connection =
+      base::WrapUnique(new WifiDirectConnection(shill_id, frequency));
+
+  return std::make_pair(
+      std::move(wifi_direct_connection),
+      wifi_direct_connection->CreateRemote(std::move(disconnect_handler)));
+}
+
+WifiDirectConnection::WifiDirectConnection(int shill_id, uint32_t frequency)
+    : shill_id_(shill_id), frequency_(frequency) {}
+
+WifiDirectConnection::~WifiDirectConnection() = default;
+
+void WifiDirectConnection::GetFrequency(GetFrequencyCallback callback) {
+  std::move(callback).Run(frequency_);
+}
+
+mojo::PendingRemote<mojom::WifiDirectConnection>
+WifiDirectConnection::CreateRemote(base::OnceClosure disconnect_handler) {
+  // Only one mojo::PendingRemote should be created per instance.
+  CHECK(!receiver_.is_bound());
+  auto pending_remote = receiver_.BindNewPipeAndPassRemote();
+  receiver_.set_disconnect_handler(std::move(disconnect_handler));
+  return pending_remote;
+}
+
+}  // namespace ash::wifi_direct
diff --git a/chromeos/ash/services/wifi_direct/wifi_direct_connection.h b/chromeos/ash/services/wifi_direct/wifi_direct_connection.h
new file mode 100644
index 0000000..94a0fc9
--- /dev/null
+++ b/chromeos/ash/services/wifi_direct/wifi_direct_connection.h
@@ -0,0 +1,50 @@
+// 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_ASH_SERVICES_WIFI_DIRECT_WIFI_DIRECT_CONNECTION_H_
+#define CHROMEOS_ASH_SERVICES_WIFI_DIRECT_WIFI_DIRECT_CONNECTION_H_
+
+#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "chromeos/ash/services/wifi_direct/public/mojom/wifi_direct_manager.mojom.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+
+namespace ash::wifi_direct {
+
+// Implementation of mojom::WifiDirectConnection. This class represents an
+// active Wifi direct connection on the device. It could either be created by
+// a group owner or connected by a group client.
+class WifiDirectConnection : public mojom::WifiDirectConnection {
+ public:
+  using InstanceWithPendingRemotePair =
+      std::pair<std::unique_ptr<WifiDirectConnection>,
+                mojo::PendingRemote<mojom::WifiDirectConnection>>;
+
+  static InstanceWithPendingRemotePair Create(
+      int shill_id,
+      uint32_t frequency,
+      base::OnceClosure disconnect_handler);
+
+  WifiDirectConnection(const WifiDirectConnection&) = delete;
+  WifiDirectConnection& operator=(const WifiDirectConnection&) = delete;
+  ~WifiDirectConnection() override;
+
+  int get_shill_id() { return shill_id_; }
+
+  // mojom::WifiDirectConnection
+  void GetFrequency(GetFrequencyCallback callback) override;
+
+ private:
+  WifiDirectConnection(int shill_id, uint32_t frequency);
+  mojo::PendingRemote<mojom::WifiDirectConnection> CreateRemote(
+      base::OnceClosure disconnect_handler);
+
+  mojo::Receiver<mojom::WifiDirectConnection> receiver_{this};
+  int shill_id_;
+  uint32_t frequency_;
+};
+
+}  // namespace ash::wifi_direct
+
+#endif  // CHROMEOS_ASH_SERVICES_WIFI_DIRECT_WIFI_DIRECT_CONNECTION_H_
diff --git a/chromeos/ash/services/wifi_direct/wifi_direct_manager.cc b/chromeos/ash/services/wifi_direct/wifi_direct_manager.cc
new file mode 100644
index 0000000..1dd36ad
--- /dev/null
+++ b/chromeos/ash/services/wifi_direct/wifi_direct_manager.cc
@@ -0,0 +1,133 @@
+// 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/ash/services/wifi_direct/wifi_direct_manager.h"
+
+#include "chromeos/ash/services/wifi_direct/wifi_direct_connection.h"
+#include "components/device_event_log/device_event_log.h"
+
+namespace ash::wifi_direct {
+
+using wifi_direct::mojom::WifiDirectOperationResult;
+
+namespace {
+
+WifiDirectOperationResult GetMojoOperationResult(
+    WifiP2PController::OperationResult result) {
+  switch (result) {
+    case WifiP2PController::OperationResult::kSuccess:
+      return WifiDirectOperationResult::kSuccess;
+    case WifiP2PController::OperationResult::kNotAllowed:
+      return WifiDirectOperationResult::kNotAllowed;
+    case WifiP2PController::OperationResult::kNotSupported:
+      return WifiDirectOperationResult::kNotSupported;
+    case WifiP2PController::OperationResult::kConcurrencyNotSupported:
+      return WifiDirectOperationResult::kConcurrencyNotSupported;
+    case WifiP2PController::OperationResult::kFrequencyNotSupported:
+      return WifiDirectOperationResult::kFrequencyNotSupported;
+    case WifiP2PController::OperationResult::kAuthFailure:
+      return WifiDirectOperationResult::kAuthFailure;
+    case WifiP2PController::OperationResult::kGroupNotFound:
+      return WifiDirectOperationResult::kGroupNotFound;
+    case WifiP2PController::OperationResult::kAlreadyConnected:
+      return WifiDirectOperationResult::kAlreadyConnected;
+    case WifiP2PController::OperationResult::kOperationInProgress:
+      return WifiDirectOperationResult::kOperationInProgress;
+    case WifiP2PController::OperationResult::kInvalidArguments:
+      return WifiDirectOperationResult::kInvalidArguments;
+    case WifiP2PController::OperationResult::kTimeout:
+      return WifiDirectOperationResult::kTimeout;
+    case WifiP2PController::OperationResult::kInvalidResultCode:
+      return WifiDirectOperationResult::kInvalidResultCode;
+    case WifiP2PController::OperationResult::kInvalidGroupProperties:
+      return WifiDirectOperationResult::kInvalidGroupProperties;
+    case WifiP2PController::OperationResult::kOperationFailed:
+    case WifiP2PController::OperationResult::kDBusError:
+      return WifiDirectOperationResult::kUnknownFailure;
+  }
+}
+
+}  // namespace
+
+WifiDirectManager::WifiDirectManager() {
+  DCHECK(WifiP2PController::IsInitialized());
+}
+
+WifiDirectManager::~WifiDirectManager() = default;
+
+void WifiDirectManager::BindPendingReceiver(
+    mojo::PendingReceiver<mojom::WifiDirectManager> pending_receiver) {
+  receivers_.Add(this, std::move(pending_receiver));
+}
+
+void WifiDirectManager::CreateWifiDirectGroup(
+    const std::string& ssid,
+    const std::string& passphrase,
+    CreateWifiDirectGroupCallback callback) {
+  WifiP2PController::Get()->CreateWifiP2PGroup(
+      ssid, passphrase,
+      base::BindOnce(&WifiDirectManager::OnCreateOrConnectWifiDirectGroup,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void WifiDirectManager::ConnectToWifiDirectGroup(
+    const std::string& ssid,
+    const std::string& passphrase,
+    std::optional<uint32_t> frequency,
+    ConnectToWifiDirectGroupCallback callback) {
+  WifiP2PController::Get()->ConnectToWifiP2PGroup(
+      ssid, passphrase, frequency,
+      base::BindOnce(&WifiDirectManager::OnCreateOrConnectWifiDirectGroup,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void WifiDirectManager::OnCreateOrConnectWifiDirectGroup(
+    CreateWifiDirectGroupCallback callback,
+    WifiP2PController::OperationResult result,
+    std::optional<WifiP2PController::WifiDirectConnectionMetadata> metadata) {
+  WifiDirectOperationResult mojo_result = GetMojoOperationResult(result);
+  if (mojo_result != WifiDirectOperationResult::kSuccess) {
+    std::move(callback).Run(mojo_result, mojo::NullRemote());
+    return;
+  }
+
+  CHECK(metadata);
+  const int shill_id = metadata->shill_id;
+  NET_LOG(EVENT) << "Creating Wifi direct connection with Shill id: "
+                 << shill_id;
+
+  // TODO: set disconnect handler when Destroy/Disconnect group is implemented.
+  auto wifi_direct_connection_pair = WifiDirectConnection::Create(
+      shill_id, metadata->frequency,
+      base::BindOnce(&WifiDirectManager::OnClientRequestedDisconnection,
+                     weak_ptr_factory_.GetWeakPtr(), shill_id));
+  if (base::Contains(shill_id_to_wifi_direct_connection_, shill_id)) {
+    NET_LOG(ERROR) << "Found an existing Wifi direct connection with Shill id: "
+                   << shill_id;
+  }
+
+  shill_id_to_wifi_direct_connection_.insert_or_assign(
+      shill_id, std::move(wifi_direct_connection_pair.first));
+  std::move(callback).Run(WifiDirectOperationResult::kSuccess,
+                          std::move(wifi_direct_connection_pair.second));
+}
+
+void WifiDirectManager::OnClientRequestedDisconnection(int shill_id) {
+  NET_LOG(EVENT)
+      << "Request diconnection for the Wifi direct group with Shill id: "
+      << shill_id;
+  const auto it = shill_id_to_wifi_direct_connection_.find(shill_id);
+  if (it == shill_id_to_wifi_direct_connection_.end()) {
+    NET_LOG(ERROR) << "Couldn't find the Wifi direct connection with shill id: "
+                   << shill_id << " in map";
+    return;
+  }
+  shill_id_to_wifi_direct_connection_.erase(it);
+}
+
+size_t WifiDirectManager::GetConnectionsCountForTesting() const {
+  return shill_id_to_wifi_direct_connection_.size();
+}
+
+}  // namespace ash::wifi_direct
diff --git a/chromeos/ash/services/wifi_direct/wifi_direct_manager.h b/chromeos/ash/services/wifi_direct/wifi_direct_manager.h
new file mode 100644
index 0000000..3b663f00
--- /dev/null
+++ b/chromeos/ash/services/wifi_direct/wifi_direct_manager.h
@@ -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.
+
+#ifndef CHROMEOS_ASH_SERVICES_WIFI_DIRECT_WIFI_DIRECT_MANAGER_H_
+#define CHROMEOS_ASH_SERVICES_WIFI_DIRECT_WIFI_DIRECT_MANAGER_H_
+
+#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "chromeos/ash/components/wifi_p2p/wifi_p2p_controller.h"
+#include "chromeos/ash/services/wifi_direct/public/mojom/wifi_direct_manager.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+
+namespace ash::wifi_direct {
+
+class WifiDirectConnection;
+
+// Implementation of mojom::WifiDirectManager. This class is responsible for:
+// 1. create Wifi direct group.
+// 2. connect to Wifi direct group.
+// 3. own the WifiDirectConnection instance.
+// 4. TODO: destroy Wifi direct group.
+// 5. TODO: disconnect Wifi direct group.
+// 6. TODO: observe on WifiP2PController to handle Wifi direct group
+// disconnections notified by Shill.
+class WifiDirectManager : public mojom::WifiDirectManager {
+ public:
+  WifiDirectManager();
+
+  WifiDirectManager(const WifiDirectManager&) = delete;
+  WifiDirectManager& operator=(const WifiDirectManager&) = delete;
+
+  ~WifiDirectManager() override;
+
+  // Binds a PendingReceiver to this instance. Clients wishing to use the
+  // WifiDirectManager API should use this function as an entrypoint.
+  void BindPendingReceiver(
+      mojo::PendingReceiver<mojom::WifiDirectManager> pending_receiver);
+
+  // mojom::WifiDirectManager
+  void CreateWifiDirectGroup(const std::string& ssid,
+                             const std::string& passphrase,
+                             CreateWifiDirectGroupCallback callback) override;
+  void ConnectToWifiDirectGroup(
+      const std::string& ssid,
+      const std::string& passphrase,
+      std::optional<uint32_t> frequency,
+      ConnectToWifiDirectGroupCallback callback) override;
+
+  size_t GetConnectionsCountForTesting() const;
+
+ private:
+  void OnCreateOrConnectWifiDirectGroup(
+      CreateWifiDirectGroupCallback callback,
+      WifiP2PController::OperationResult result,
+      std::optional<WifiP2PController::WifiDirectConnectionMetadata> metadata);
+  void OnClientRequestedDisconnection(int shill_id);
+
+  mojo::ReceiverSet<mojom::WifiDirectManager> receivers_;
+  base::flat_map<int, std::unique_ptr<WifiDirectConnection>>
+      shill_id_to_wifi_direct_connection_;
+
+  base::WeakPtrFactory<WifiDirectManager> weak_ptr_factory_{this};
+};
+
+}  // namespace ash::wifi_direct
+
+#endif  // CHROMEOS_ASH_SERVICES_WIFI_DIRECT_WIFI_DIRECT_MANAGER_H_
diff --git a/chromeos/ash/services/wifi_direct/wifi_direct_manager_unittest.cc b/chromeos/ash/services/wifi_direct/wifi_direct_manager_unittest.cc
new file mode 100644
index 0000000..bcb221a
--- /dev/null
+++ b/chromeos/ash/services/wifi_direct/wifi_direct_manager_unittest.cc
@@ -0,0 +1,162 @@
+// 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/ash/services/wifi_direct/wifi_direct_manager.h"
+
+#include "ash/constants/ash_features.h"
+#include "base/test/bind.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "base/values.h"
+#include "chromeos/ash/components/dbus/shill/fake_shill_manager_client.h"
+#include "chromeos/ash/components/dbus/shill/shill_clients.h"
+#include "chromeos/ash/components/dbus/shill/shill_manager_client.h"
+#include "chromeos/ash/components/wifi_p2p/wifi_p2p_controller.h"
+#include "chromeos/ash/services/wifi_direct/public/mojom/wifi_direct_manager.mojom-test-utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
+
+namespace ash::wifi_direct {
+
+using wifi_direct::mojom::WifiDirectOperationResult;
+
+class WifiDirectManagerTest : public testing::Test {
+ public:
+  struct WifiP2POperationTestResult {
+    WifiDirectOperationResult result;
+    mojo::PendingRemote<mojom::WifiDirectConnection> wifi_direct_connection;
+  };
+
+  WifiDirectManagerTest() = default;
+  WifiDirectManagerTest(const WifiDirectManagerTest&) = delete;
+  WifiDirectManagerTest& operator=(const WifiDirectManagerTest&) = delete;
+  ~WifiDirectManagerTest() override = default;
+
+  void SetUp() override {
+    shill_clients::InitializeFakes();
+    feature_list_.InitAndEnableFeature(features::kWifiDirect);
+    WifiP2PController::Initialize();
+    wifi_direct_manager_ = std::make_unique<WifiDirectManager>();
+  }
+
+  void TearDown() override {
+    wifi_direct_manager_.reset();
+    WifiP2PController::Shutdown();
+    shill_clients::Shutdown();
+  }
+
+  WifiP2POperationTestResult CreateWifiDirectGroup(
+      const std::string& ssid,
+      const std::string& passphrase) {
+    auto wifi_direct_manager_async_waiter =
+        mojom::WifiDirectManagerAsyncWaiter(wifi_direct_manager_.get());
+    WifiP2POperationTestResult test_result;
+    wifi_direct_manager_async_waiter.CreateWifiDirectGroup(
+        ssid, passphrase, &test_result.result,
+        &test_result.wifi_direct_connection);
+    return test_result;
+  }
+
+  WifiP2POperationTestResult ConnectToWifiDirectGroup(
+      const std::string& ssid,
+      const std::string& passphrase,
+      std::optional<uint32_t> frequency) {
+    auto wifi_direct_manager_async_waiter =
+        mojom::WifiDirectManagerAsyncWaiter(wifi_direct_manager_.get());
+    WifiP2POperationTestResult test_result;
+    wifi_direct_manager_async_waiter.ConnectToWifiDirectGroup(
+        ssid, passphrase, frequency, &test_result.result,
+        &test_result.wifi_direct_connection);
+    return test_result;
+  }
+
+  uint32_t GetFrequency(
+      const mojo::Remote<mojom::WifiDirectConnection>& wifi_direct_connection) {
+    uint32_t frequency;
+    auto wifi_direct_connection_async_waiter =
+        mojom::WifiDirectConnectionAsyncWaiter(wifi_direct_connection.get());
+    wifi_direct_connection_async_waiter.GetFrequency(&frequency);
+    return frequency;
+  }
+
+  void ExpectConnectionsCount(size_t expected_connections_count) {
+    EXPECT_EQ(expected_connections_count,
+              wifi_direct_manager_->GetConnectionsCountForTesting());
+  }
+
+ private:
+  base::test::TaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+  base::test::ScopedFeatureList feature_list_;
+  std::unique_ptr<WifiDirectManager> wifi_direct_manager_;
+};
+
+TEST_F(WifiDirectManagerTest, CreateWifiDirectGroupSuccess) {
+  ShillManagerClient::Get()
+      ->GetTestInterface()
+      ->SetSimulateCreateP2PGroupResult(FakeShillSimulatedResult::kSuccess,
+                                        shill::kCreateP2PGroupResultSuccess);
+  WifiP2POperationTestResult result_arguments =
+      CreateWifiDirectGroup("DIRECT-1a", "passphrase");
+  EXPECT_EQ(result_arguments.result, WifiDirectOperationResult::kSuccess);
+  ASSERT_TRUE(result_arguments.wifi_direct_connection.is_valid());
+
+  mojo::Remote<mojom::WifiDirectConnection> wifi_direct_connection(
+      std::move(result_arguments.wifi_direct_connection));
+  ExpectConnectionsCount(1);
+  EXPECT_EQ(1000u, GetFrequency(wifi_direct_connection));
+  // Request disconnection from client side.
+  wifi_direct_connection.reset();
+  // Wait for the disconnect callback finish running.
+  base::RunLoop().RunUntilIdle();
+  ExpectConnectionsCount(0);
+}
+
+TEST_F(WifiDirectManagerTest, CreateWifiDirectGroupFailure_InvalidArguments) {
+  ShillManagerClient::Get()
+      ->GetTestInterface()
+      ->SetSimulateCreateP2PGroupResult(
+          FakeShillSimulatedResult::kSuccess,
+          shill::kCreateP2PGroupResultNotSupported);
+  WifiP2POperationTestResult result_arguments =
+      CreateWifiDirectGroup("DIRECT-1a", "passphrase");
+  EXPECT_EQ(result_arguments.result, WifiDirectOperationResult::kNotSupported);
+  EXPECT_FALSE(result_arguments.wifi_direct_connection.is_valid());
+}
+
+TEST_F(WifiDirectManagerTest, ConnectToWifiDirectGroupSuccess) {
+  ShillManagerClient::Get()
+      ->GetTestInterface()
+      ->SetSimulateConnectToP2PGroupResult(
+          FakeShillSimulatedResult::kSuccess,
+          shill::kConnectToP2PGroupResultSuccess);
+  WifiP2POperationTestResult result_arguments =
+      ConnectToWifiDirectGroup("DIRECT-1a", "passphrase", 5200u);
+  EXPECT_EQ(result_arguments.result, WifiDirectOperationResult::kSuccess);
+  ASSERT_TRUE(result_arguments.wifi_direct_connection.is_valid());
+
+  mojo::Remote<mojom::WifiDirectConnection> wifi_direct_connection(
+      std::move(result_arguments.wifi_direct_connection));
+  ExpectConnectionsCount(1);
+  EXPECT_EQ(5200u, GetFrequency(wifi_direct_connection));
+  // Request disconnection from client side.
+  wifi_direct_connection.reset();
+  // Wait for the disconnect callback finish running.
+  base::RunLoop().RunUntilIdle();
+  ExpectConnectionsCount(0);
+}
+
+TEST_F(WifiDirectManagerTest, ConnectToWifiDirectGroupFailure_InvalidResult) {
+  ShillManagerClient::Get()
+      ->GetTestInterface()
+      ->SetSimulateConnectToP2PGroupResult(FakeShillSimulatedResult::kSuccess,
+                                           "invalid_result");
+  WifiP2POperationTestResult result_arguments =
+      ConnectToWifiDirectGroup("DIRECT-1a", "passphrase", 5200u);
+  EXPECT_EQ(result_arguments.result,
+            WifiDirectOperationResult::kInvalidResultCode);
+  EXPECT_FALSE(result_arguments.wifi_direct_connection.is_valid());
+}
+
+}  // namespace ash::wifi_direct
diff --git a/chromeos/crosapi/mojom/app_service_types.mojom b/chromeos/crosapi/mojom/app_service_types.mojom
index 8c1e343b..e3ab0fd9 100644
--- a/chromeos/crosapi/mojom/app_service_types.mojom
+++ b/chromeos/crosapi/mojom/app_service_types.mojom
@@ -648,7 +648,7 @@
 [Stable]
 struct InstallAppParams {
   // Represents the origin of the installation.
-  // Next version: 2
+  // Next version: 3
   [Stable, Extensible]
   enum Surface {
     [Default] kUnknown = 0,
@@ -657,6 +657,7 @@
     [MinVersion=1] kAppInstallUriMall = 3,
     [MinVersion=1] kAppInstallUriGetit = 4,
     [MinVersion=1] kAppInstallUriLauncher = 5,
+    [MinVersion=2] kAppInstallUriPeripherals = 6,
   };
   Surface surface@0;
 
diff --git a/chromeos/ui/frame/multitask_menu/multitask_menu_nudge_controller.cc b/chromeos/ui/frame/multitask_menu/multitask_menu_nudge_controller.cc
index 5af0c87..7982bb3f 100644
--- a/chromeos/ui/frame/multitask_menu/multitask_menu_nudge_controller.cc
+++ b/chromeos/ui/frame/multitask_menu/multitask_menu_nudge_controller.cc
@@ -135,13 +135,10 @@
 #endif
 }
 
-MultitaskMenuNudgeController::MultitaskMenuNudgeController() {
-  display::Screen::GetScreen()->AddObserver(this);
-}
+MultitaskMenuNudgeController::MultitaskMenuNudgeController() = default;
 
 MultitaskMenuNudgeController::~MultitaskMenuNudgeController() {
   DismissNudge();
-  display::Screen::GetScreen()->RemoveObserver(this);
 }
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -201,6 +198,7 @@
 
   window_ = nullptr;
   window_observation_.Reset();
+  widget_observation_.Reset();
 
   anchor_view_ = nullptr;
   pulse_layer_.reset();
@@ -252,15 +250,6 @@
   }
 }
 
-void MultitaskMenuNudgeController::OnWindowBoundsChanged(
-    aura::Window* window,
-    const gfx::Rect& old_bounds,
-    const gfx::Rect& new_bounds,
-    ui::PropertyChangeReason reason) {
-  CHECK_EQ(window_, window);
-  UpdateWidgetAndPulse();
-}
-
 void MultitaskMenuNudgeController::OnWindowTargetTransformChanging(
     aura::Window* window,
     const gfx::Transform& new_transform) {
@@ -299,6 +288,13 @@
   DismissNudge();
 }
 
+void MultitaskMenuNudgeController::OnWidgetBoundsChanged(
+    views::Widget* widget,
+    const gfx::Rect& new_bounds) {
+  CHECK_EQ(window_, widget->GetNativeWindow());
+  UpdateWidgetAndPulse();
+}
+
 void MultitaskMenuNudgeController::OnDisplayTabletStateChanged(
     display::TabletState state) {
   switch (state) {
@@ -391,6 +387,10 @@
   // trigger some window observations.
   window_observation_.Observe(window_.get());
 
+  views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window_);
+  CHECK(widget);
+  widget_observation_.Observe(widget);
+
   if (!tablet_mode) {
     // Create the layer which pulses on the maximize/restore button.
     pulse_layer_ = std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR);
diff --git a/chromeos/ui/frame/multitask_menu/multitask_menu_nudge_controller.h b/chromeos/ui/frame/multitask_menu/multitask_menu_nudge_controller.h
index 2576a79..b3bdca01 100644
--- a/chromeos/ui/frame/multitask_menu/multitask_menu_nudge_controller.h
+++ b/chromeos/ui/frame/multitask_menu/multitask_menu_nudge_controller.h
@@ -15,6 +15,7 @@
 #include "ui/display/display_observer.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/unique_widget_ptr.h"
+#include "ui/views/widget/widget_observer.h"
 
 class PrefRegistrySimple;
 
@@ -32,6 +33,7 @@
 // Controller for showing the user education nudge for the multitask menu.
 class COMPONENT_EXPORT(CHROMEOS_UI_FRAME) MultitaskMenuNudgeController
     : public aura::WindowObserver,
+      public views::WidgetObserver,
       public display::DisplayObserver {
  public:
   // `tablet_mode` refers to the tablet state when the prefs are fetched. If
@@ -93,16 +95,16 @@
   void OnWindowParentChanged(aura::Window* window,
                              aura::Window* parent) override;
   void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
-  void OnWindowBoundsChanged(aura::Window* window,
-                             const gfx::Rect& old_bounds,
-                             const gfx::Rect& new_bounds,
-                             ui::PropertyChangeReason reason) override;
   void OnWindowTargetTransformChanging(
       aura::Window* window,
       const gfx::Transform& new_transform) override;
   void OnWindowStackingChanged(aura::Window* window) override;
   void OnWindowDestroying(aura::Window* window) override;
 
+  // views::WidgetObserver:
+  void OnWidgetBoundsChanged(views::Widget* widget,
+                             const gfx::Rect& new_bounds) override;
+
   // display::DisplayObserver:
   void OnDisplayTabletStateChanged(display::TabletState state) override;
 
@@ -160,6 +162,10 @@
 
   base::ScopedObservation<aura::Window, aura::WindowObserver>
       window_observation_{this};
+  base::ScopedObservation<views::Widget, views::WidgetObserver>
+      widget_observation_{this};
+
+  display::ScopedDisplayObserver display_observer_{this};
 
   base::WeakPtrFactory<MultitaskMenuNudgeController> weak_ptr_factory_{this};
 };
diff --git a/clank b/clank
index 8b5df65..fbc5a9e 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 8b5df658aa105d15f72f53d23d0cc4420075ceb8
+Subproject commit fbc5a9e586cb0f8b580be2091f80cf84529ef8ee
diff --git a/components/autofill/core/browser/single_field_form_fill_router.cc b/components/autofill/core/browser/single_field_form_fill_router.cc
index 9bab63fd..573917b9 100644
--- a/components/autofill/core/browser/single_field_form_fill_router.cc
+++ b/components/autofill/core/browser/single_field_form_fill_router.cc
@@ -103,7 +103,7 @@
   } else if (iban_manager_ && popup_item_id == PopupItemId::kIbanEntry) {
     iban_manager_->OnRemoveCurrentSingleFieldSuggestion(field_name, value,
                                                         popup_item_id);
-  } else {
+  } else if (popup_item_id == PopupItemId::kAutocompleteEntry) {
     autocomplete_history_manager_->OnRemoveCurrentSingleFieldSuggestion(
         field_name, value, popup_item_id);
   }
@@ -119,7 +119,7 @@
         value, popup_item_id);
   } else if (iban_manager_ && popup_item_id == PopupItemId::kIbanEntry) {
     iban_manager_->OnSingleFieldSuggestionSelected(value, popup_item_id);
-  } else {
+  } else if (popup_item_id == PopupItemId::kAutocompleteEntry) {
     autocomplete_history_manager_->OnSingleFieldSuggestionSelected(
         value, popup_item_id);
   }
diff --git a/components/autofill_payments_strings.grdp b/components/autofill_payments_strings.grdp
index 33d063d..62062ea9 100644
--- a/components/autofill_payments_strings.grdp
+++ b/components/autofill_payments_strings.grdp
@@ -1127,7 +1127,7 @@
       Card benefits
     </message>
     <message name="IDS_AUTOFILL_SETTINGS_PAGE_CARD_BENEFITS_TOGGLE_SUBLABEL_WITH_LEARN_LINK" desc="Sublabel for the payments settings page card benefits toggle, including a hyperlinked text to learn about card benefits.">
-      See info that helps you choose which card to pay with. <ph name="CARD_BENEFIT_HELP_LINK_BEGIN">&lt;a href="#" aria-description="$1"&gt;</ph>Learn about card benefits<ph name="CARD_BENEFIT_HELP_LINK_END">&lt;/a&gt;</ph>
+      Show which rewards and benefits are available for your cards at checkout <ph name="CARD_BENEFIT_HELP_LINK_BEGIN">&lt;a href="#" aria-description="$1"&gt;</ph>Learn about card benefits<ph name="CARD_BENEFIT_HELP_LINK_END">&lt;/a&gt;</ph>
     </message>
     <message name="IDS_AUTOFILL_SETTINGS_PAGE_BULK_REMOVE_CVC_TITLE" desc="Title for the modal dialog when the user is trying to bulk remove/delete all the CVCs stored locally and on Google servers.">
       Delete saved security codes?
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SETTINGS_PAGE_CARD_BENEFITS_TOGGLE_SUBLABEL_WITH_LEARN_LINK.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SETTINGS_PAGE_CARD_BENEFITS_TOGGLE_SUBLABEL_WITH_LEARN_LINK.png.sha1
index f76021a..263f3a9 100644
--- a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SETTINGS_PAGE_CARD_BENEFITS_TOGGLE_SUBLABEL_WITH_LEARN_LINK.png.sha1
+++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SETTINGS_PAGE_CARD_BENEFITS_TOGGLE_SUBLABEL_WITH_LEARN_LINK.png.sha1
@@ -1 +1 @@
-a85b0485129b1f199b83bf77d49342d31447da85
\ No newline at end of file
+265fe5d08774d8efe2690df05f0fd76e3e9a9c45
\ No newline at end of file
diff --git a/components/embedder_support/BUILD.gn b/components/embedder_support/BUILD.gn
index 212f149..fda20764 100644
--- a/components/embedder_support/BUILD.gn
+++ b/components/embedder_support/BUILD.gn
@@ -33,6 +33,7 @@
     "//components/prefs",
     "//components/version_info",
     "//content/public/browser",
+    "//services/device/public/cpp/geolocation:buildflags",
   ]
 }
 
diff --git a/components/embedder_support/DEPS b/components/embedder_support/DEPS
index c658fe3..b5fd3d1 100644
--- a/components/embedder_support/DEPS
+++ b/components/embedder_support/DEPS
@@ -10,6 +10,7 @@
   "+content/public/browser",
   "+content/public/common",
   "+net",
+  "+services/device/public/cpp/geolocation/buildflags.h",
   "+third_party/blink/public/common",
   "+third_party/blink/public/mojom/worker/shared_worker_info.mojom.h",
   "+third_party/re2",
diff --git a/components/embedder_support/permission_context_utils.cc b/components/embedder_support/permission_context_utils.cc
index 9c0ec65..063b8e6 100644
--- a/components/embedder_support/permission_context_utils.cc
+++ b/components/embedder_support/permission_context_utils.cc
@@ -26,9 +26,9 @@
 #include "components/permissions/contexts/nfc_permission_context_android.h"
 #endif  // BUILDFLAG(IS_ANDROID)
 
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 #include "components/permissions/contexts/geolocation_permission_context_system.h"
-#endif
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 
 namespace embedder_support {
 
@@ -78,7 +78,7 @@
           browser_context,
           std::move(delegates.geolocation_permission_context_delegate),
           is_regular_profile);
-#elif BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#elif BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
   permission_contexts[ContentSettingsType::GEOLOCATION] =
       std::make_unique<permissions::GeolocationPermissionContextSystem>(
           browser_context,
@@ -88,7 +88,7 @@
       std::make_unique<permissions::GeolocationPermissionContext>(
           browser_context,
           std::move(delegates.geolocation_permission_context_delegate));
-#endif
+#endif  // BUILDFLAG(IS_ANDROID)
   permission_contexts[ContentSettingsType::KEYBOARD_LOCK] =
       std::make_unique<permissions::KeyboardLockPermissionContext>(
           browser_context);
diff --git a/components/embedder_support/permission_context_utils.h b/components/embedder_support/permission_context_utils.h
index e95dde83..4b8d4ac 100644
--- a/components/embedder_support/permission_context_utils.h
+++ b/components/embedder_support/permission_context_utils.h
@@ -11,16 +11,17 @@
 #include "components/permissions/contexts/geolocation_permission_context.h"
 #include "components/permissions/contexts/nfc_permission_context.h"
 #include "components/permissions/permission_manager.h"
+#include "services/device/public/cpp/geolocation/buildflags.h"
 
 namespace content {
 class BrowserContext;
 }  // namespace content
 
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 namespace device {
 class GeolocationSystemPermissionManager;
 }  // namespace device
-#endif  // BUILDFLAG(IS_MAC)
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 
 namespace webrtc {
 class MediaStreamDeviceEnumerator;
@@ -40,10 +41,10 @@
       camera_pan_tilt_zoom_permission_context_delegate;
   std::unique_ptr<permissions::GeolocationPermissionContext::Delegate>
       geolocation_permission_context_delegate;
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
   raw_ptr<device::GeolocationSystemPermissionManager>
       geolocation_system_permission_manager;
-#endif
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
   raw_ptr<webrtc::MediaStreamDeviceEnumerator> media_stream_device_enumerator;
   std::unique_ptr<permissions::NfcPermissionContext::Delegate>
       nfc_permission_context_delegate;
diff --git a/components/exo/buffer.cc b/components/exo/buffer.cc
index 2a2cc85..a941a1ba 100644
--- a/components/exo/buffer.cc
+++ b/components/exo/buffer.cc
@@ -60,10 +60,6 @@
              "AlwaysUseMappableSIForExoBuffer",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-const bool kIsMappableSIEnabled =
-    base::FeatureList::IsEnabled(kAlwaysUseMappableSIForExoBuffer) &&
-    media::IsMultiPlaneFormatForHardwareVideoEnabled();
-
 // The amount of time before we wait for release queries using
 // GetQueryObjectuivEXT(GL_QUERY_RESULT_EXT).
 const int kWaitForReleaseDelayMs = 500;
@@ -73,6 +69,9 @@
 const bool kDefaultUseZeroCopy = true;
 const bool kDefaultIsOverlayCandidate = false;
 const bool kDefaultYInvert = false;
+
+// Default usage in order to create a mappable shared image and get a
+// GpuMemoryBufferHandle from it.
 const uint32_t kDefaultMappableSIUsage = gpu::SHARED_IMAGE_USAGE_DISPLAY_READ;
 
 // Gets the color type of |format| for creating bitmap. If it returns
@@ -193,7 +192,8 @@
   Texture(scoped_refptr<viz::RasterContextProvider> context_provider,
           gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
           gfx::GpuMemoryBuffer* gpu_memory_buffer,
-          gpu::ClientSharedImage* mappable_shared_image,
+          gfx::GpuMemoryBufferHandle* gpu_memory_buffer_handle,
+          const gfx::BufferFormat buffer_format,
           const gfx::Size& size,
           gfx::ColorSpace color_space,
           unsigned query_type,
@@ -252,8 +252,17 @@
   const void* GetBufferId() const;
 
   const raw_ptr<gfx::GpuMemoryBuffer, DanglingUntriaged> gpu_memory_buffer_;
-  const raw_ptr<gpu::ClientSharedImage, DanglingUntriaged>
-      mappable_shared_image_;
+
+  // Note that |gpu_memory_buffer_handle_| is used instead of
+  // |gpu_memory_buffer_| when MappableSI is enabled.
+  // Note that the owning reference to this pointers is ::Buffer which can be
+  // destroyed before it when ::Buffer::Texture is destroyed via
+  // ::Buffer::Texture::ReleaseSharedImage(). This causes pointer to dangle. But
+  // this pointer is safe to dangle as we never access it during
+  // ::Buffer::Texture destructor and is also never accessed after the owning
+  // object ::Buffer is destroyed.
+  const raw_ptr<gfx::GpuMemoryBufferHandle, DisableDanglingPtrDetection>
+      gpu_memory_buffer_handle_;
   const gfx::Size size_;
   scoped_refptr<viz::RasterContextProvider> context_provider_;
   const unsigned query_type_;
@@ -263,6 +272,7 @@
   const base::TimeDelta wait_for_release_delay_;
   base::TimeTicks wait_for_release_time_;
   bool wait_for_release_pending_ = false;
+  const bool is_mappable_si_enabled_;
   base::WeakPtrFactory<Texture> weak_ptr_factory_{this};
 };
 
@@ -272,10 +282,13 @@
     gfx::ColorSpace color_space,
     gpu::SyncToken& sync_token_out)
     : gpu_memory_buffer_(nullptr),
-      mappable_shared_image_(nullptr),
+      gpu_memory_buffer_handle_(nullptr),
       size_(size),
       context_provider_(std::move(context_provider)),
-      query_type_(GL_COMMANDS_COMPLETED_CHROMIUM) {
+      query_type_(GL_COMMANDS_COMPLETED_CHROMIUM),
+      is_mappable_si_enabled_(
+          base::FeatureList::IsEnabled(kAlwaysUseMappableSIForExoBuffer) &&
+          media::IsMultiPlaneFormatForHardwareVideoEnabled()) {
   gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
 
   // These SharedImages are used over the raster interface as both the source
@@ -304,7 +317,8 @@
     scoped_refptr<viz::RasterContextProvider> context_provider,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     gfx::GpuMemoryBuffer* gpu_memory_buffer,
-    gpu::ClientSharedImage* mappable_shared_image,
+    gfx::GpuMemoryBufferHandle* gpu_memory_buffer_handle,
+    const gfx::BufferFormat buffer_format,
     const gfx::Size& size,
     gfx::ColorSpace color_space,
     unsigned query_type,
@@ -312,15 +326,18 @@
     bool is_overlay_candidate,
     gpu::SyncToken& sync_token_out)
     : gpu_memory_buffer_(gpu_memory_buffer),
-      mappable_shared_image_(mappable_shared_image),
+      gpu_memory_buffer_handle_(gpu_memory_buffer_handle),
       size_(size),
       context_provider_(std::move(context_provider)),
       query_type_(query_type),
-      wait_for_release_delay_(wait_for_release_delay) {
+      wait_for_release_delay_(wait_for_release_delay),
+      is_mappable_si_enabled_(
+          base::FeatureList::IsEnabled(kAlwaysUseMappableSIForExoBuffer) &&
+          media::IsMultiPlaneFormatForHardwareVideoEnabled()) {
   // Adding checks to avoid running into issues until the feature is fully
   // enabled.
-  CHECK((kIsMappableSIEnabled && mappable_shared_image_) ||
-        (!kIsMappableSIEnabled && gpu_memory_buffer));
+  CHECK((is_mappable_si_enabled_ && !gpu_memory_buffer_handle_->is_null()) ||
+        (!is_mappable_si_enabled_ && gpu_memory_buffer));
 
   gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
 
@@ -335,15 +352,15 @@
     usage |= gpu::SHARED_IMAGE_USAGE_SCANOUT;
   }
 
-  if (kIsMappableSIEnabled) {
+  if (is_mappable_si_enabled_) {
     shared_image_ = sii->CreateSharedImage(
-        {mappable_shared_image_->format(), size_, color_space, usage,
+        {GetSharedImageFormat(buffer_format), size_, color_space, usage,
          gpu::kExoTextureLabelPrefix},
-        mappable_shared_image_->CloneGpuMemoryBufferHandle());
+        gpu_memory_buffer_handle_->Clone());
   } else if (media::IsMultiPlaneFormatForHardwareVideoEnabled()) {
-    auto si_format = GetSharedImageFormat(gpu_memory_buffer_->GetFormat());
     shared_image_ = sii->CreateSharedImage(
-        {si_format, size_, color_space, usage, gpu::kExoTextureLabelPrefix},
+        {GetSharedImageFormat(buffer_format), size_, color_space, usage,
+         gpu::kExoTextureLabelPrefix},
         gpu_memory_buffer_->CloneHandle());
   } else {
     shared_image_ = sii->CreateSharedImage(
@@ -555,8 +572,9 @@
 }
 
 const void* Buffer::Texture::GetBufferId() const {
-  return kIsMappableSIEnabled ? static_cast<const void*>(mappable_shared_image_)
-                              : static_cast<const void*>(gpu_memory_buffer_);
+  return is_mappable_si_enabled_
+             ? static_cast<const void*>(gpu_memory_buffer_handle_)
+             : static_cast<const void*>(gpu_memory_buffer_);
 }
 
 Buffer::BufferRelease::BufferRelease(
@@ -592,7 +610,7 @@
                bool is_overlay_candidate,
                bool y_invert)
     : gpu_memory_buffer_(std::move(gpu_memory_buffer)),
-      mappable_shared_image_(nullptr),
+      gpu_memory_buffer_handle_(gfx::GpuMemoryBufferHandle()),
       buffer_format_(gpu_memory_buffer_ ? gpu_memory_buffer_->GetFormat()
                                         : gfx::BufferFormat::RGBA_8888),
       size_(gpu_memory_buffer_ ? gpu_memory_buffer_->GetSize()
@@ -601,34 +619,34 @@
       use_zero_copy_(use_zero_copy),
       is_overlay_candidate_(is_overlay_candidate),
       y_invert_(y_invert),
-      wait_for_release_delay_(base::Milliseconds(kWaitForReleaseDelayMs)) {}
+      wait_for_release_delay_(base::Milliseconds(kWaitForReleaseDelayMs)),
+      is_mappable_si_enabled_(
+          base::FeatureList::IsEnabled(kAlwaysUseMappableSIForExoBuffer) &&
+          media::IsMultiPlaneFormatForHardwareVideoEnabled()) {}
 
-Buffer::Buffer(scoped_refptr<gpu::ClientSharedImage> mappable_shared_image,
+Buffer::Buffer(gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle,
                gfx::BufferFormat buffer_format,
+               gfx::Size size,
+               gfx::BufferUsage buffer_usage,
                unsigned query_type,
                bool use_zero_copy,
                bool is_overlay_candidate,
                bool y_invert)
     : gpu_memory_buffer_(nullptr),
-      mappable_shared_image_(std::move(mappable_shared_image)),
+      gpu_memory_buffer_handle_(std::move(gpu_memory_buffer_handle)),
       buffer_format_(buffer_format),
-      size_(mappable_shared_image_->size()),
+      size_(size),
+      buffer_usage_(buffer_usage),
       query_type_(query_type),
       use_zero_copy_(use_zero_copy),
       is_overlay_candidate_(is_overlay_candidate),
       y_invert_(y_invert),
-      wait_for_release_delay_(base::Milliseconds(kWaitForReleaseDelayMs)) {}
+      wait_for_release_delay_(base::Milliseconds(kWaitForReleaseDelayMs)),
+      is_mappable_si_enabled_(
+          base::FeatureList::IsEnabled(kAlwaysUseMappableSIForExoBuffer) &&
+          media::IsMultiPlaneFormatForHardwareVideoEnabled()) {}
 
-Buffer::~Buffer() {
-  // Note that currently ClientSharedImage does not automatically deletes the
-  // shared image mailbox when ref count goes to 0. So client need to explicitly
-  // delete it.
-  auto* sii = GetSharedImageInterface();
-  if (sii && mappable_shared_image_) {
-    sii->DestroySharedImage(gpu::SyncToken(),
-                            std::move(mappable_shared_image_));
-  }
-}
+Buffer::~Buffer() {}
 
 // static
 std::unique_ptr<Buffer> Buffer::CreateBufferFromGMBHandle(
@@ -640,22 +658,13 @@
     bool use_zero_copy,
     bool is_overlay_candidate,
     bool y_invert) {
-  if (kIsMappableSIEnabled) {
-    scoped_refptr<gpu::ClientSharedImage> shared_image;
-    auto* sii = GetSharedImageInterface();
-    if (sii) {
-      shared_image = sii->CreateSharedImage(
-          {GetSharedImageFormat(buffer_format), buffer_size, gfx::ColorSpace(),
-           kDefaultMappableSIUsage, "ExoBufferCreateBufferFromGMBHandle"},
-          gpu::kNullSurfaceHandle, buffer_usage, std::move(buffer_handle));
-    }
-    if (!shared_image) {
-      LOG(ERROR) << "Failed to create a shared image.";
-      return nullptr;
-    }
-    return base::WrapUnique(new Buffer(std::move(shared_image), buffer_format,
-                                       query_type, use_zero_copy,
-                                       is_overlay_candidate, y_invert));
+  const bool is_mappable_si_enabled =
+      base::FeatureList::IsEnabled(kAlwaysUseMappableSIForExoBuffer) &&
+      media::IsMultiPlaneFormatForHardwareVideoEnabled();
+  if (is_mappable_si_enabled) {
+    return base::WrapUnique(new Buffer(
+        std::move(buffer_handle), buffer_format, buffer_size, buffer_usage,
+        query_type, use_zero_copy, is_overlay_candidate, y_invert));
   }
 
   gpu::GpuMemoryBufferSupport gpu_memory_buffer_support;
@@ -685,22 +694,50 @@
     gpu::SurfaceHandle surface_handle,
     base::WaitableEvent* shutdown_event,
     bool is_overlay_candidate) {
-  if (kIsMappableSIEnabled) {
+  const bool is_mappable_si_enabled =
+      base::FeatureList::IsEnabled(kAlwaysUseMappableSIForExoBuffer) &&
+      media::IsMultiPlaneFormatForHardwareVideoEnabled();
+  if (is_mappable_si_enabled) {
     scoped_refptr<gpu::ClientSharedImage> shared_image;
     auto* sii = GetSharedImageInterface();
     if (sii) {
+      // Note that we are creating this mappable shared image only to get a
+      // GMBHandle from it and use below to create ::Buffer.
+      // TODO(vikassoni) : Once MultiPlanarSI and MappableSI is fully launced
+      // and we remove legacy code paths, refactor ::Buffer and
+      // ::Buffer::Texture to use this MappableSI created below directly in
+      // ::Buffer::Texture instead of creating new SI in it.
+      // ::Buffer will keep a GMB handle as well as MappableSI when handles
+      // comes externally via ::CreateBufferFromGMBHandle whereas only
+      // MappableSI for ::CreateBuffer calls. ::Buffer also needs to handle
+      // context loss since its using a SI.
+      // Currently creating ::Buffer from MappableSI below and then using that
+      // ::Buffer to create
+      // ::Buffer::Texture does not work well as the ::Buffer does not implement
+      // ContextLostObserver like ::Buffer::Texture. Even if ::Buffer does
+      // implement ContextLostObserver and destroys the MappableSI correctly, it
+      // still needs to recreate it when contexts are recreated. This behaviour
+      // will be different from using |gpu_memory_buffer_| currently as it does
+      // not need to be destroyed and recreated on context loss.
       shared_image = sii->CreateSharedImage(
           {GetSharedImageFormat(buffer_format), buffer_size, gfx::ColorSpace(),
            kDefaultMappableSIUsage, "ExoBufferCreateBuffer"},
           surface_handle, buffer_usage);
     }
     if (!shared_image) {
-      LOG(ERROR) << "Failed to create a shared image.";
+      LOG(ERROR) << "Failed to create a mappable shared image.";
       return nullptr;
     }
-    return base::WrapUnique(new Buffer(std::move(shared_image), buffer_format,
-                                       kDefaultQueryType, kDefaultUseZeroCopy,
-                                       is_overlay_candidate, kDefaultYInvert));
+    std::unique_ptr<Buffer> buffer = base::WrapUnique(
+        new Buffer(shared_image->CloneGpuMemoryBufferHandle(), buffer_format,
+                   buffer_size, buffer_usage, kDefaultQueryType,
+                   kDefaultUseZeroCopy, is_overlay_candidate, kDefaultYInvert));
+
+    // Destroy the |shared_image| as it will no longer be used. Note that the
+    // underlying handle is already cloned above and will not be destroyed by
+    // destroying the |shared_image|.
+    sii->DestroySharedImage(gpu::SyncToken(), std::move(shared_image));
+    return buffer;
   }
 
   auto gpu_memory_buffer =
@@ -776,8 +813,8 @@
   if (!contents_texture_) {
     contents_texture_ = std::make_unique<Texture>(
         context_provider, context_factory->GetGpuMemoryBufferManager(),
-        gpu_memory_buffer_.get(), mappable_shared_image_.get(), size_,
-        color_space, query_type_, wait_for_release_delay_,
+        gpu_memory_buffer_.get(), &gpu_memory_buffer_handle_, buffer_format_,
+        size_, color_space, query_type_, wait_for_release_delay_,
         is_overlay_candidate_, resource->mailbox_holder.sync_token);
   }
   Texture* contents_texture = contents_texture_.get();
@@ -796,8 +833,12 @@
   // require a secure output.
   if (secure_output_only &&
       protected_buffer_state_ == ProtectedBufferState::UNKNOWN &&
-      gpu_memory_buffer_ && protected_native_pixmap_query) {
-    gfx::GpuMemoryBufferHandle gmb_handle = gpu_memory_buffer_->CloneHandle();
+      ((is_mappable_si_enabled_ && !gpu_memory_buffer_handle_.is_null()) ||
+       (!is_mappable_si_enabled_ && gpu_memory_buffer_)) &&
+      protected_native_pixmap_query) {
+    gfx::GpuMemoryBufferHandle gmb_handle =
+        is_mappable_si_enabled_ ? gpu_memory_buffer_handle_.Clone()
+                                : gpu_memory_buffer_->CloneHandle();
     if (!gmb_handle.native_pixmap_handle.planes.empty()) {
       base::ScopedFD pixmap_handle(HANDLE_EINTR(
           dup(gmb_handle.native_pixmap_handle.planes[0].fd.get())));
@@ -920,8 +961,8 @@
 // GMBs will go away and clients will end up using either GMBHandle or Mappable
 // shared image. Below method will be updated accordingly.
 const void* Buffer::GetBufferId() const {
-  return kIsMappableSIEnabled
-             ? static_cast<const void*>(mappable_shared_image_.get())
+  return is_mappable_si_enabled_
+             ? static_cast<const void*>(&gpu_memory_buffer_handle_)
              : static_cast<const void*>(gpu_memory_buffer_.get());
 }
 
@@ -1035,18 +1076,29 @@
   void* memory = nullptr;
   int stride = 0;
   std::unique_ptr<gpu::ClientSharedImage::ScopedMapping> mapping;
+  gpu::SharedImageInterface* sii = nullptr;
+  scoped_refptr<gpu::ClientSharedImage> shared_image;
 
   SkColorType color_type = GetColorTypeForBitmapCreation(GetFormat());
   if (color_type == SkColorType::kUnknown_SkColorType) {
     return bitmap;
   }
 
-  if (kIsMappableSIEnabled) {
-    if (!mappable_shared_image_) {
+  if (is_mappable_si_enabled_) {
+    sii = GetSharedImageInterface();
+    if (gpu_memory_buffer_handle_.is_null() || !sii) {
       return bitmap;
     }
 
-    mapping = mappable_shared_image_->Map();
+    // We only need to create this shared image in order to Map the
+    // |gpu_memory_buffer_handle_| to cpu visible memory.
+    shared_image = sii->CreateSharedImage(
+        {GetSharedImageFormat(buffer_format_), size_, gfx::ColorSpace(),
+         kDefaultMappableSIUsage, "ExoBufferCreateBitmap"},
+        gpu::kNullSurfaceHandle, buffer_usage_,
+        gpu_memory_buffer_handle_.Clone());
+
+    mapping = shared_image->Map();
     if (!mapping) {
       DLOG(ERROR) << "Failed to map MappableSI.";
       return bitmap;
@@ -1076,7 +1128,13 @@
   bitmap.allocPixels(image_info);
   bitmap.writePixels(pixmap);
   bitmap.setImmutable();
-  kIsMappableSIEnabled ? mapping.reset() : gpu_memory_buffer_->Unmap();
+  if (is_mappable_si_enabled_) {
+    mapping.reset();
+    // Destroy this shared image as we no longer need it.
+    sii->DestroySharedImage(gpu::SyncToken(), std::move(shared_image));
+  } else {
+    gpu_memory_buffer_->Unmap();
+  }
 
   return bitmap;
 }
diff --git a/components/exo/buffer.h b/components/exo/buffer.h
index 76dd463..f517940 100644
--- a/components/exo/buffer.h
+++ b/components/exo/buffer.h
@@ -1,4 +1,5 @@
-
+// Copyright 2015 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_EXO_BUFFER_H_
@@ -140,8 +141,10 @@
          bool use_zero_copy,
          bool is_overlay_candidate,
          bool y_invert);
-  Buffer(scoped_refptr<gpu::ClientSharedImage> mappable_shared_image,
+  Buffer(gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle,
          gfx::BufferFormat buffer_format,
+         gfx::Size size,
+         gfx::BufferUsage buffer_usage,
          unsigned query_type,
          bool use_zero_copy,
          bool is_overlay_candidate,
@@ -210,17 +213,10 @@
 
   // Contains the content of this buffer instead of |gpu_memory_buffer_| when
   // MappableSI is enabled.
-  // TODO(https://issues.chromium.org/u/1/issues/329543541) : Once MappableSI is
-  // fully launched for Exo::Buffer, refactor code to use
-  // |mappable_shared_image_| in Buffer::Texture::Texture() instead of creating
-  // additional shared images out of it. Also update kDefaultMappableSIUsage
-  // accordingly which will likely match with existing SI usage in
-  // Buffer::Texture::Texture().
-  scoped_refptr<gpu::ClientSharedImage> mappable_shared_image_;
-
+  gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle_;
   const gfx::BufferFormat buffer_format_;
-
   const gfx::Size size_;
+  gfx::BufferUsage buffer_usage_;
 
   // Query type that must be used when releasing buffer from a texture.
   const unsigned query_type_;
@@ -275,6 +271,8 @@
   ProtectedBufferState protected_buffer_state_ = ProtectedBufferState::UNKNOWN;
 #endif  // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
 
+  const bool is_mappable_si_enabled_;
+
   base::WeakPtrFactory<Buffer> weak_ptr_factory_{this};
 };
 
diff --git a/components/metrics/content/subprocess_metrics_provider.h b/components/metrics/content/subprocess_metrics_provider.h
index a9230e0..4a24d41 100644
--- a/components/metrics/content/subprocess_metrics_provider.h
+++ b/components/metrics/content/subprocess_metrics_provider.h
@@ -55,6 +55,16 @@
       bool async = false,
       base::OnceClosure done_callback = base::DoNothing());
 
+  // Indicates subprocess to be monitored with unique id for later reference.
+  // Metrics reporting will read histograms from it and upload them to UMA.
+  void RegisterSubprocessAllocator(
+      int id,
+      std::unique_ptr<base::PersistentHistogramAllocator> allocator);
+
+  // Indicates that a subprocess has exited and is thus finished with the
+  // allocator it was using.
+  void DeregisterSubprocessAllocator(int id);
+
  private:
   friend class SubprocessMetricsProviderTest;
 
@@ -87,16 +97,6 @@
   // whole lifetime of the browser process.
   ~SubprocessMetricsProvider() override;
 
-  // Indicates subprocess to be monitored with unique id for later reference.
-  // Metrics reporting will read histograms from it and upload them to UMA.
-  void RegisterSubprocessAllocator(
-      int id,
-      std::unique_ptr<base::PersistentHistogramAllocator> allocator);
-
-  // Indicates that a subprocess has exited and is thus finished with the
-  // allocator it was using.
-  void DeregisterSubprocessAllocator(int id);
-
   // base::StatisticsRecorder::HistogramProvider:
   void MergeHistogramDeltas(bool async,
                             base::OnceClosure done_callback) override;
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal
index 5779125..bf065aa 160000
--- a/components/optimization_guide/internal
+++ b/components/optimization_guide/internal
@@ -1 +1 @@
-Subproject commit 5779125122f438c5f18b78f9d554a71da25b902f
+Subproject commit bf065aaf550359d584f16cb19becfbf5b6cda492
diff --git a/components/peripherals/logging/logging.h b/components/peripherals/logging/logging.h
index b6e03da2..d2c015d 100644
--- a/components/peripherals/logging/logging.h
+++ b/components/peripherals/logging/logging.h
@@ -10,7 +10,7 @@
 #include "base/logging.h"
 #include "components/peripherals/logging/log_buffer.h"
 
-// Use the PR_LOG() macro for all logging related to Cross Device Features so
+// Use the PR_LOG() macro for all logging related to Peripherals Features so
 // the debug page can reflect all logs related to this feature in the internal
 // debug WebUI (chrome://nearby-internals).
 #define PR_LOG(severity, feature)                                              \
diff --git a/components/permissions/BUILD.gn b/components/permissions/BUILD.gn
index 0cc1fb02..c3f90e9 100644
--- a/components/permissions/BUILD.gn
+++ b/components/permissions/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//device/vr/buildflags/buildflags.gni")
+import("//services/device/public/cpp/geolocation/buildflags.gni")
 
 source_set("permissions_common") {
   sources = [
@@ -148,7 +149,7 @@
   if (enable_vr) {
     deps += [ "//device/vr/public/cpp" ]
   }
-  if (is_mac || is_chromeos) {
+  if (os_level_geolocation_permission_supported) {
     sources += [
       "contexts/geolocation_permission_context_system.cc",
       "contexts/geolocation_permission_context_system.h",
diff --git a/components/permissions/contexts/geolocation_permission_context_unittest.cc b/components/permissions/contexts/geolocation_permission_context_unittest.cc
index a3d7d723..592fb69 100644
--- a/components/permissions/contexts/geolocation_permission_context_unittest.cc
+++ b/components/permissions/contexts/geolocation_permission_context_unittest.cc
@@ -57,6 +57,7 @@
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/test_utils.h"
 #include "content/public/test/web_contents_tester.h"
+#include "services/device/public/cpp/geolocation/buildflags.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/permissions/permission_utils.h"
 #include "url/origin.h"
@@ -68,10 +69,10 @@
 #include "components/prefs/pref_service.h"
 #endif
 
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 #include "components/permissions/contexts/geolocation_permission_context_system.h"
 #include "services/device/public/cpp/test/fake_geolocation_system_permission_manager.h"
-#endif
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 
 using content::MockRenderProcessHost;
 
@@ -199,10 +200,10 @@
   std::vector<std::unique_ptr<MockPermissionPromptFactory>>
       mock_permission_prompt_factories_;
 
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
   raw_ptr<device::FakeGeolocationSystemPermissionManager>
       fake_geolocation_system_permission_manager_;
-#endif
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 
   // A map between renderer child id and a pair represending the bridge id and
   // whether the requested permission was allowed.
@@ -361,7 +362,7 @@
   MockLocationSettings::SetLocationSettingsDialogStatus(false /* enabled */,
                                                         GRANTED);
   MockLocationSettings::ClearHasShownLocationSettingsDialog();
-#elif BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#elif BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
   auto fake_geolocation_system_permission_manager =
       std::make_unique<device::FakeGeolocationSystemPermissionManager>();
   fake_geolocation_system_permission_manager_ =
@@ -1192,7 +1193,7 @@
 }
 #endif  // BUILDFLAG(IS_ANDROID)
 
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 TEST_F(GeolocationPermissionContextTests,
        AllSystemAndSitePermissionCombinations) {
   GURL requesting_frame("https://www.example.com/geolocation");
@@ -1258,6 +1259,6 @@
   ASSERT_EQ(3, num_permission_updates_);
   geolocation_permission_context_->RemoveObserver(this);
 }
-#endif
+#endif  // BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED)
 
 }  // namespace permissions
diff --git a/components/permissions/permission_request.cc b/components/permissions/permission_request.cc
index 7afbc3b..09aa5a4 100644
--- a/components/permissions/permission_request.cc
+++ b/components/permissions/permission_request.cc
@@ -302,6 +302,9 @@
     case RequestType::kIdleDetection:
       message_id = IDS_IDLE_DETECTION_PERMISSION_FRAGMENT;
       break;
+    case RequestType::kKeyboardLock:
+      message_id = IDS_KEYBOARD_LOCK_PERMISSIONS_FRAGMENT;
+      break;
     case RequestType::kLocalFonts:
       message_id = IDS_FONT_ACCESS_PERMISSION_FRAGMENT;
       break;
@@ -317,6 +320,9 @@
     case RequestType::kNotifications:
       message_id = IDS_NOTIFICATION_PERMISSIONS_FRAGMENT;
       break;
+    case RequestType::kPointerLock:
+      message_id = IDS_POINTER_LOCK_PERMISSIONS_FRAGMENT;
+      break;
 #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
     case RequestType::kProtectedMediaIdentifier:
       message_id = IDS_PROTECTED_MEDIA_IDENTIFIER_PERMISSION_FRAGMENT;
diff --git a/components/permissions/permission_uma_util.cc b/components/permissions/permission_uma_util.cc
index 9db837c..c1b5db83 100644
--- a/components/permissions/permission_uma_util.cc
+++ b/components/permissions/permission_uma_util.cc
@@ -96,6 +96,10 @@
       return RequestTypeForUma::PERMISSION_GEOLOCATION;
     case RequestType::kIdleDetection:
       return RequestTypeForUma::PERMISSION_IDLE_DETECTION;
+#if !BUILDFLAG(IS_ANDROID)
+    case RequestType::kKeyboardLock:
+      return RequestTypeForUma::PERMISSION_KEYBOARD_LOCK;
+#endif
     case RequestType::kMicStream:
       return RequestTypeForUma::PERMISSION_MEDIASTREAM_MIC;
     case RequestType::kMidiSysex:
@@ -106,6 +110,10 @@
     case RequestType::kNfcDevice:
       return RequestTypeForUma::PERMISSION_NFC;
 #endif
+#if !BUILDFLAG(IS_ANDROID)
+    case RequestType::kPointerLock:
+      return RequestTypeForUma::PERMISSION_POINTER_LOCK;
+#endif
     case RequestType::kNotifications:
       return RequestTypeForUma::PERMISSION_NOTIFICATIONS;
 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
@@ -203,6 +211,10 @@
       return "WebPrinting";
     case RequestTypeForUma::PERMISSION_IDENTITY_PROVIDER:
       return "IdentityProvider";
+    case RequestTypeForUma::PERMISSION_KEYBOARD_LOCK:
+      return "KeyboardLock";
+    case RequestTypeForUma::PERMISSION_POINTER_LOCK:
+      return "PointerLock";
 
     case RequestTypeForUma::UNKNOWN:
     case RequestTypeForUma::PERMISSION_FLASH:
@@ -1324,6 +1336,14 @@
       base::UmaHistogramEnumeration("Permissions.Action.WebPrinting", action,
                                     PermissionAction::NUM);
       break;
+    case ContentSettingsType::POINTER_LOCK:
+      base::UmaHistogramEnumeration("Permissions.Action.PointerLock", action,
+                                    PermissionAction::NUM);
+      break;
+    case ContentSettingsType::KEYBOARD_LOCK:
+      base::UmaHistogramEnumeration("Permissions.Action.KeyboardLock", action,
+                                    PermissionAction::NUM);
+      break;
     // The user is not prompted for these permissions, thus there is no
     // permission action recorded for them.
     default:
diff --git a/components/permissions/permission_uma_util.h b/components/permissions/permission_uma_util.h
index a9120e6..fc889e3 100644
--- a/components/permissions/permission_uma_util.h
+++ b/components/permissions/permission_uma_util.h
@@ -96,6 +96,8 @@
   PERMISSION_SMART_CARD = 34,
   PERMISSION_WEB_PRINTING = 35,
   PERMISSION_IDENTITY_PROVIDER = 36,
+  PERMISSION_KEYBOARD_LOCK = 37,
+  PERMISSION_POINTER_LOCK = 38,
   // NUM must be the last value in the enum.
   NUM
 };
diff --git a/components/permissions/request_type.cc b/components/permissions/request_type.cc
index 6ea6e76d..a5a186f9 100644
--- a/components/permissions/request_type.cc
+++ b/components/permissions/request_type.cc
@@ -98,6 +98,10 @@
     case RequestType::kIdleDetection:
       return cr23 ? vector_icons::kDevicesChromeRefreshIcon
                   : vector_icons::kDevicesIcon;
+    case RequestType::kKeyboardLock:
+      // TODO: crbug.com/324147495 - Replace this placeholder icon with the
+      // actual icon.
+      return vector_icons::kTouchpadMouseIcon;
     case RequestType::kLocalFonts:
       return cr23 ? vector_icons::kFontDownloadChromeRefreshIcon
                   : vector_icons::kFontDownloadIcon;
@@ -113,6 +117,10 @@
     case RequestType::kNotifications:
       return cr23 ? vector_icons::kNotificationsChromeRefreshIcon
                   : vector_icons::kNotificationsIcon;
+    case RequestType::kPointerLock:
+      // TODO: crbug.com/324147495 - Replace this placeholder icon with the
+      // actual icon.
+      return vector_icons::kTouchpadMouseIcon;
 #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
     case RequestType::kProtectedMediaIdentifier:
       // This icon is provided by ChromePermissionsClient::GetOverrideIconId.
@@ -221,12 +229,20 @@
       return RequestType::kGeolocation;
     case ContentSettingsType::IDLE_DETECTION:
       return RequestType::kIdleDetection;
+#if !BUILDFLAG(IS_ANDROID)
+    case ContentSettingsType::KEYBOARD_LOCK:
+      return RequestType::kKeyboardLock;
+#endif
     case ContentSettingsType::MEDIASTREAM_MIC:
       return RequestType::kMicStream;
     case ContentSettingsType::MIDI_SYSEX:
       return RequestType::kMidiSysex;
     case ContentSettingsType::NOTIFICATIONS:
       return RequestType::kNotifications;
+#if !BUILDFLAG(IS_ANDROID)
+    case ContentSettingsType::POINTER_LOCK:
+      return RequestType::kPointerLock;
+#endif
 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
     case ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER:
       return RequestType::kProtectedMediaIdentifier;
@@ -297,6 +313,10 @@
       return ContentSettingsType::GEOLOCATION;
     case RequestType::kIdleDetection:
       return ContentSettingsType::IDLE_DETECTION;
+#if !BUILDFLAG(IS_ANDROID)
+    case RequestType::kKeyboardLock:
+      return ContentSettingsType::KEYBOARD_LOCK;
+#endif
     case RequestType::kMicStream:
       return ContentSettingsType::MEDIASTREAM_MIC;
     case RequestType::kMidiSysex:
@@ -307,6 +327,10 @@
 #endif
     case RequestType::kNotifications:
       return ContentSettingsType::NOTIFICATIONS;
+#if !BUILDFLAG(IS_ANDROID)
+    case RequestType::kPointerLock:
+      return ContentSettingsType::POINTER_LOCK;
+#endif
 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
     case RequestType::kProtectedMediaIdentifier:
       return ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER;
@@ -397,6 +421,8 @@
     case permissions::RequestType::kIdleDetection:
       return "idle_detection";
 #if !BUILDFLAG(IS_ANDROID)
+    case permissions::RequestType::kKeyboardLock:
+      return "keyboard_lock";
     case permissions::RequestType::kLocalFonts:
       return "local_fonts";
 #endif
@@ -412,6 +438,10 @@
 #endif
     case permissions::RequestType::kNotifications:
       return "notifications";
+#if !BUILDFLAG(IS_ANDROID)
+    case permissions::RequestType::kPointerLock:
+      return "pointer_lock";
+#endif
 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
     case permissions::RequestType::kProtectedMediaIdentifier:
       return "protected_media_identifier";
diff --git a/components/permissions/request_type.h b/components/permissions/request_type.h
index 60c8656..6443d5fb 100644
--- a/components/permissions/request_type.h
+++ b/components/permissions/request_type.h
@@ -49,6 +49,10 @@
   kNfcDevice,
 #endif
   kNotifications,
+#if !BUILDFLAG(IS_ANDROID)
+  kKeyboardLock,
+  kPointerLock,
+#endif
 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
   kProtectedMediaIdentifier,
 #endif
diff --git a/components/permissions_strings.grdp b/components/permissions_strings.grdp
index 7d322dc..e66bee61 100644
--- a/components/permissions_strings.grdp
+++ b/components/permissions_strings.grdp
@@ -134,6 +134,12 @@
   <message name="IDS_AR_PERMISSION_FRAGMENT" desc="Permission request shown if the user is visiting a site that wants to use AR. Follows a prompt: 'This site would like to:">
     Create a 3D map of your surroundings and track camera position
   </message>
+  <message name="IDS_KEYBOARD_LOCK_PERMISSIONS_FRAGMENT" desc="Permission request shown if the user is visiting a site that wants to lock the user's keyboard. When the keyboard is locked, any keyboard input usually handled by the browser or the OS is handled by the website instead. Follows a prompt: 'This site would like to:">
+    Lock your keyboard
+  </message>
+  <message name="IDS_POINTER_LOCK_PERMISSIONS_FRAGMENT" desc="Permission request shown if the user is visiting a site that wants to lock the user's mouse pointer. When the mouse pointer is locked, the cursor is hidden and its motions are handled by the website. Follows a prompt: 'This site would like to:">
+    Lock your mouse pointer
+  </message>
   <message name="IDS_STORAGE_ACCESS_PERMISSION_TWO_ORIGIN_PROMPT_TITLE" desc="The title of a dialog box that prompts the user to provide permission. In the description below, “www.myfavoritesite.com” and “Google Docs” are just used as examples. 1) “wants to” means “is asking permission to”2) “use info” means retrieve existing info and save additional info. 3) “they've saved about you”: Google Docs can only prompt the user for permission on www.myfavoritesite.com if the user has previously used Google Docs.A user might visit a site called www.myfavoritesite.com. That site might embed content and services from other sites. Embedded content can include things like text, images, audio, and services (for example, Google Docs). In this example, the dialog box is shown by Google Docs. The permission is to enable a connection between www.myfavoritesite.com and Google Docs and to allow Google Docs to access information that services has previously saved about the user. For example, Google Docs would need this permission to verify the user's identity and display the user's documents as they browse www.myfavoritesite.com.">
     <ph name="EMBEDDED_URL">$1<ex>google.com</ex></ph> wants to use info they've saved about you
   </message>
diff --git a/components/permissions_strings_grdp/IDS_KEYBOARD_LOCK_PERMISSIONS_FRAGMENT.png.sha1 b/components/permissions_strings_grdp/IDS_KEYBOARD_LOCK_PERMISSIONS_FRAGMENT.png.sha1
new file mode 100644
index 0000000..6302f84
--- /dev/null
+++ b/components/permissions_strings_grdp/IDS_KEYBOARD_LOCK_PERMISSIONS_FRAGMENT.png.sha1
@@ -0,0 +1 @@
+0c23fa9ba0177b36a3984139858e1c44d0b3885d
\ No newline at end of file
diff --git a/components/permissions_strings_grdp/IDS_POINTER_LOCK_PERMISSIONS_FRAGMENT.png.sha1 b/components/permissions_strings_grdp/IDS_POINTER_LOCK_PERMISSIONS_FRAGMENT.png.sha1
new file mode 100644
index 0000000..6302f84
--- /dev/null
+++ b/components/permissions_strings_grdp/IDS_POINTER_LOCK_PERMISSIONS_FRAGMENT.png.sha1
@@ -0,0 +1 @@
+0c23fa9ba0177b36a3984139858e1c44d0b3885d
\ No newline at end of file
diff --git a/components/policy/resources/templates/policy_definitions/Miscellaneous/EnterpriseBadgingTemporarySetting.yaml b/components/policy/resources/templates/policy_definitions/Miscellaneous/EnterpriseBadgingTemporarySetting.yaml
index f158d85..b3ff323 100644
--- a/components/policy/resources/templates/policy_definitions/Miscellaneous/EnterpriseBadgingTemporarySetting.yaml
+++ b/components/policy/resources/templates/policy_definitions/Miscellaneous/EnterpriseBadgingTemporarySetting.yaml
@@ -25,13 +25,13 @@
   name: hide_enterprise_badging

   value: 0

 - caption: Show enterprise badging on unmanaged devices only

-  name: show_enterprise_badging_managed_browsers

+  name: show_enterprise_badging_unmanaged_devices

   value: 1

 - caption: Show enterprise badging on all devices

-  name: show_enterprise_badging_managed_browsers

+  name: show_enterprise_badging_all_devices

   value: 2

 - caption: Show enterprise badging on managed devices only

-  name: show_enterprise_badging_managed_browsers

+  name: show_enterprise_badging_managed_devices

   value: 3

 owners:

 - ydago@chromium.org

diff --git a/components/remote_cocoa/app_shim/select_file_dialog_bridge.mm b/components/remote_cocoa/app_shim/select_file_dialog_bridge.mm
index a1a6a83..ae866bca 100644
--- a/components/remote_cocoa/app_shim/select_file_dialog_bridge.mm
+++ b/components/remote_cocoa/app_shim/select_file_dialog_bridge.mm
@@ -4,14 +4,14 @@
 
 #include "components/remote_cocoa/app_shim/select_file_dialog_bridge.h"
 
-#include <AppKit/AppKit.h>
+#import <AppKit/AppKit.h>
 #include <CoreServices/CoreServices.h>  // pre-macOS 11
-#include <Foundation/Foundation.h>
+#import <Foundation/Foundation.h>
 #import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>  // macOS 11
 #include <stddef.h>
 
 #include "base/apple/bridging.h"
-#include "base/apple/foundation_util.h"
+#import "base/apple/foundation_util.h"
 #include "base/apple/scoped_cftyperef.h"
 #include "base/files/file_util.h"
 #include "base/i18n/case_conversion.h"
@@ -21,21 +21,13 @@
 #include "base/threading/hang_watcher.h"
 #include "base/threading/thread_restrictions.h"
 #import "components/remote_cocoa/app_shim/native_widget_mac_nswindow.h"
-#include "ui/base/l10n/l10n_util_mac.h"
+#import "ui/base/l10n/l10n_util_mac.h"
 #include "ui/strings/grit/ui_strings.h"
 
 namespace {
 
 const int kFileTypePopupTag = 1234;
 
-// TODO(macOS 11): Remove this.
-CFStringRef CreateUTIFromExtension(const base::FilePath::StringType& ext) {
-  base::apple::ScopedCFTypeRef<CFStringRef> ext_cf(
-      base::SysUTF8ToCFStringRef(ext));
-  return UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
-                                               ext_cf.get(), nullptr);
-}
-
 NSString* GetDescriptionFromExtension(const base::FilePath::StringType& ext) {
   if (@available(macOS 11, *)) {
     UTType* type =
@@ -46,7 +38,12 @@
       return description;
     }
   } else {
-    base::apple::ScopedCFTypeRef<CFStringRef> uti(CreateUTIFromExtension(ext));
+    base::apple::ScopedCFTypeRef<CFStringRef> ext_cf =
+        base::SysUTF8ToCFStringRef(ext);
+    base::apple::ScopedCFTypeRef<CFStringRef> uti(
+        UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
+                                              ext_cf.get(),
+                                              /*inConformingToUTI=*/nullptr));
     NSString* description =
         base::apple::CFToNSOwnershipCast(UTTypeCopyDescription(uti.get()));
 
@@ -71,7 +68,7 @@
   label.translatesAutoresizingMaskIntoConstraints = NO;
   label.textColor = NSColor.secondaryLabelColor;
   if (base::mac::MacOSMajorVersion() >= 11) {
-    label.font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
+    label.font = [NSFont systemFontOfSize:NSFont.smallSystemFontSize];
   }
 
   // The popup.
@@ -179,28 +176,17 @@
 @interface ExtensionDropdownHandler : NSObject {
  @private
   // The file dialog to which this target object corresponds. Weak reference
-  // since the dialog_ will stay alive longer than this object.
-  NSSavePanel* _dialog;
-
-  // Two ivars serving the same purpose. While `_fileTypeLists` is for pre-macOS
-  // 11, and contains NSStrings with UTType identifiers, `_fileUTTypeLists` is
-  // for macOS 11 and later, and contains UTTypes. TODO(macOS 11): Clean this
-  // up.
+  // since the _dialog will stay alive longer than this object.
+  NSSavePanel* __weak _dialog;
 
   // An array where each item is an array of different extensions in an
   // extension group.
-  NSArray<NSArray<NSString*>*>* __strong _fileTypeLists;
-  NSArray<NSArray<UTType*>*>* __strong _fileUTTypeLists
-      API_AVAILABLE(macos(11.0));
+  NSArray<NSArray<NSString*>*>* __strong _fileExtensionLists;
 }
 
-// TODO(macOS 11): Remove this.
 - (instancetype)initWithDialog:(NSSavePanel*)dialog
-                 fileTypeLists:(NSArray<NSArray<NSString*>*>*)fileTypeLists;
-
-- (instancetype)initWithDialog:(NSSavePanel*)dialog
-               fileUTTypeLists:(NSArray<NSArray<UTType*>*>*)fileUTTypeLists
-    API_AVAILABLE(macos(11.0));
+            fileExtensionLists:
+                (NSArray<NSArray<NSString*>*>*)fileExtensionLists;
 
 - (void)popupAction:(id)sender;
 @end
@@ -210,7 +196,7 @@
 - (BOOL)panel:(id)sender validateURL:(NSURL*)url error:(NSError**)outError {
   // Refuse to accept users closing the dialog with a key repeat, since the key
   // may have been first pressed while the user was looking at insecure content.
-  // See https://crbug.com/637098.
+  // See https://crbug.com/40085079.
   if (NSApp.currentEvent.type == NSEventTypeKeyDown &&
       NSApp.currentEvent.ARepeat) {
     return NO;
@@ -223,49 +209,57 @@
 
 @implementation ExtensionDropdownHandler
 
-// TODO(macOS 11): Remove this.
 - (instancetype)initWithDialog:(NSSavePanel*)dialog
-                 fileTypeLists:(NSArray<NSArray<NSString*>*>*)fileTypeLists {
+            fileExtensionLists:
+                (NSArray<NSArray<NSString*>*>*)fileExtensionLists {
   if ((self = [super init])) {
     _dialog = dialog;
-    _fileTypeLists = fileTypeLists;
-  }
-  return self;
-}
-
-- (instancetype)initWithDialog:(NSSavePanel*)dialog
-               fileUTTypeLists:(NSArray<NSArray<UTType*>*>*)fileUTTypeLists
-    API_AVAILABLE(macos(11.0)) {
-  if ((self = [super init])) {
-    _dialog = dialog;
-    _fileUTTypeLists = fileUTTypeLists;
+    _fileExtensionLists = fileExtensionLists;
   }
   return self;
 }
 
 - (void)popupAction:(id)sender {
   NSUInteger index = [sender indexOfSelectedItem];
-  if (@available(macOS 11, *)) {
-    if (index < [_fileUTTypeLists count]) {
-      // For save dialogs, this causes the first item in the allowedContentTypes
-      // array to be used as the extension for the save panel.
-      _dialog.allowedContentTypes = [_fileUTTypeLists objectAtIndex:index];
-    } else {
-      // The user selected "All files" option. (Note that an empty array is "all
-      // types" and nil is an error.)
-      _dialog.allowedContentTypes = @[];
-    }
+
+  // When provided UTTypes, NSOpenPanel determines whether files are selectable
+  // by conformance, not by strict type matching. For example, with
+  // public.plain-text, not only .txt files will be selectable, but .js, .m3u,
+  // and .csv files will be as well. With public.zip-archive, not only .zip
+  // files will be selectable, but also .jar files and .xlsb files.
+  //
+  // While this can be great for normal viewing/editing apps, this is not
+  // desirable for Chromium, where the web platform requires strict type
+  // matching on the provided extensions, and files that have a conforming file
+  // type by accident of their implementation shouldn't qualify for selection.
+  //
+  // Unfortunately, there's no great way to do strict type matching with
+  // NSOpenPanel. Setting explicit extensions via -allowedFileTypes is
+  // deprecated, and there's no way to specify that strict type equality should
+  // be used for -allowedContentTypes (FB13721802).
+  //
+  // -[NSOpenSavePanelDelegate panel:shouldEnableURL:] could be used to enforce
+  // strict type matching, however its presence on the delegate means that all
+  // files in the file list start off being displayed as disabled, and slowly
+  // become enabled if they qualify. This is non-performant and quite a poor
+  // user experience.
+  //
+  // Therefore, use the deprecated API, because it's the only way to remain
+  // performant while achieving strict type matching.
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+  if (index < _fileExtensionLists.count) {
+    // For save dialogs, this causes the first item in the allowedFileTypes
+    // array to be used as the extension for the save panel.
+    _dialog.allowedFileTypes = _fileExtensionLists[index];
   } else {
-    if (index < [_fileTypeLists count]) {
-      // For save dialogs, this causes the first item in the allowedFileTypes
-      // array to be used as the extension for the save panel.
-      _dialog.allowedFileTypes = [_fileTypeLists objectAtIndex:index];
-    } else {
-      // The user selected "All files" option. (Note that nil is "all types" and
-      // an empty array is an error.)
-      _dialog.allowedFileTypes = nil;
-    }
+    // The user selected "All files" option. (Note that nil is "all types" and
+    // an empty array is an error, unlike with -allowedContentTypes, where an
+    // empty array is "all types" and nil is an error.)
+    _dialog.allowedFileTypes = nil;
   }
+#pragma clang diagnostic pop
 }
 
 @end
@@ -281,11 +275,12 @@
 SelectFileDialogBridge::~SelectFileDialogBridge() {
   // If we never executed our callback, then the panel never closed. Cancel it
   // now.
-  if (show_callback_)
+  if (show_callback_) {
     [panel_ cancel:panel_];
+  }
 
   // Balance the setDelegate called during Show.
-  [panel_ setDelegate:nil];
+  panel_.delegate = nil;
 }
 
 void SelectFileDialogBridge::Show(
@@ -307,15 +302,17 @@
   show_callback_ = std::move(callback);
   type_ = type;
   // Note: we need to retain the dialog as |owning_window_| can be null.
-  // (See https://crbug.com/29213 .)
-  if (type_ == SelectFileDialogType::kSaveAsFile)
+  // (See https://crbug.com/41052845.)
+  if (type_ == SelectFileDialogType::kSaveAsFile) {
     panel_ = [NSSavePanel savePanel];
-  else
+  } else {
     panel_ = [NSOpenPanel openPanel];
+  }
   g_last_created_panel_for_testing = panel_;
 
-  if (!title.empty())
+  if (!title.empty()) {
     panel_.message = base::SysUTF16ToNSString(title);
+  }
 
   NSString* default_dir = nil;
   NSString* default_filename = nil;
@@ -364,20 +361,21 @@
     }
 
     // The tag autosetter in macOS is not reliable (see
-    // https://crbug.com/1510399). Explicitly set the `showsTagField` property
+    // https://crbug.com/41482996). Explicitly set the `showsTagField` property
     // as a signal to macOS that we will handle all the file tagging; a
     // side-effect of setting the property to any value is that it turns off
     // the tag autosetter.
     panel_.showsTagField = YES;
   } else {
     // This does not use ObjCCast because the underlying object could be a
-    // non-exported AppKit type (https://crbug.com/995476).
+    // non-exported AppKit type (https://crbug.com/41477018).
     NSOpenPanel* open_dialog = static_cast<NSOpenPanel*>(panel_);
 
-    if (type_ == SelectFileDialogType::kOpenMultiFile)
+    if (type_ == SelectFileDialogType::kOpenMultiFile) {
       open_dialog.allowsMultipleSelection = YES;
-    else
+    } else {
       open_dialog.allowsMultipleSelection = NO;
+    }
 
     if (type_ == SelectFileDialogType::kFolder ||
         type_ == SelectFileDialogType::kUploadFolder ||
@@ -385,10 +383,11 @@
       open_dialog.canChooseFiles = NO;
       open_dialog.canChooseDirectories = YES;
 
-      if (type_ == SelectFileDialogType::kFolder)
+      if (type_ == SelectFileDialogType::kFolder) {
         open_dialog.canCreateDirectories = YES;
-      else
+      } else {
         open_dialog.canCreateDirectories = NO;
+      }
 
       NSString* prompt =
           (type_ == SelectFileDialogType::kUploadFolder)
@@ -403,10 +402,12 @@
     delegate_ = [[SelectFileDialogDelegate alloc] init];
     open_dialog.delegate = delegate_;
   }
-  if (default_dir)
+  if (default_dir) {
     panel_.directoryURL = [NSURL fileURLWithPath:default_dir];
-  if (default_filename)
+  }
+  if (default_filename) {
     panel_.nameFieldStringValue = default_filename;
+  }
 
   // Ensure that |callback| (rather than |this|) be retained by the block.
   auto ended_callback = base::BindRepeating(
@@ -435,10 +436,8 @@
   DCHECK(popup);
 
   // Create an array with each item corresponding to an array of different
-  // extensions in an extension group. TODO(macOS 11): Remove the first,
-  // uncomment the second.
-  NSMutableArray<NSArray<NSString*>*>* file_type_lists = [NSMutableArray array];
-  NSMutableArray /*<NSArray<UTType*>*>*/* file_uttype_lists =
+  // extensions in an extension group.
+  NSMutableArray<NSArray<NSString*>*>* file_extension_lists =
       [NSMutableArray array];
   int default_extension_index = -1;
   for (size_t i = 0; i < file_types->extensions.size(); ++i) {
@@ -460,63 +459,24 @@
     DCHECK_NE(0u, [type_description length]);
     [popup addItemWithTitle:type_description];
 
-    // Store different extensions in the current extension group. TODO(macOS
-    // 11): Remove the first, uncomment the second.
-    NSMutableArray<NSString*>* file_type_array = [NSMutableArray array];
-    NSMutableArray /*<UTType*>*/* file_uttype_array = [NSMutableArray array];
+    // Store different extensions in the current extension group.
+    NSMutableArray<NSString*>* file_extensions_array = [NSMutableArray array];
     for (const base::FilePath::StringType& ext : ext_list) {
       if (ext == default_extension) {
         default_extension_index = i;
       }
 
-      if (@available(macOS 11, *)) {
-        UTType* type =
-            [UTType typeWithFilenameExtension:base::SysUTF8ToNSString(ext)];
-        // If the extension string is invalid (e.g. contains dots), it's not a
-        // valid extension and `type` will be nil. In that case, invent a type
-        // that doesn't match any real files. When passed to the file picker, no
-        // files will be allowed to be selected. This matches the pre-UTTypes
-        // behavior in which an invalid specified type did not allow any files
-        // to be selected, and this matches Firefox and Safari behavior (see
-        // https://crbug.com/1423362#c17 for a test case).
-        if (!type) {
-          NSString* identifier =
-              [NSString stringWithFormat:@"org.chromium.not-a-real-type.%@",
-                                         [NSUUID UUID].UUIDString];
-          type = [UTType importedTypeWithIdentifier:identifier];
-        }
-
-        if (![file_uttype_array containsObject:type]) {
-          [file_uttype_array addObject:type];
-        }
-      } else {
-        // Crash reports suggest that CreateUTIFromExtension may return nil.
-        // Hence we nil check before adding to |file_type_set|. See
-        // crbug.com/630101 and rdar://27490414.
-        NSString* uti =
-            base::apple::CFToNSOwnershipCast(CreateUTIFromExtension(ext));
-        if (uti) {
-          if (![file_type_array containsObject:uti]) {
-            [file_type_array addObject:uti];
-          }
-        }
-
-        // Always allow the extension itself, in case the UTI doesn't map
-        // back to the original extension correctly. This occurs with dynamic
-        // UTIs on 10.7 and 10.8.
-        // See https://crbug.com/148840, https://openradar.appspot.com/12316273
-        NSString* ext_ns = base::SysUTF8ToNSString(ext);
-        if (![file_type_array containsObject:ext_ns]) {
-          [file_type_array addObject:ext_ns];
-        }
+      // See -[ExtensionDropdownHandler popupAction:] as to why file extensions
+      // are collected here rather than being converted to UTTypes.
+      // TODO(FB13721802): Use UTTypes when strict type matching can be
+      // specified.
+      NSString* ext_ns = base::SysUTF8ToNSString(ext);
+      if (![file_extensions_array containsObject:ext_ns]) {
+        [file_extensions_array addObject:ext_ns];
       }
     }
 
-    if (@available(macOS 11, *)) {
-      [file_uttype_lists addObject:file_uttype_array];
-    } else {
-      [file_type_lists addObject:file_type_array];
-    }
+    [file_extension_lists addObject:file_extensions_array];
   }
 
   if (file_types->include_all_files || file_types->extensions.empty()) {
@@ -529,15 +489,9 @@
     }
   }
 
-  if (@available(macOS 11, *)) {
-    extension_dropdown_handler_ =
-        [[ExtensionDropdownHandler alloc] initWithDialog:panel_
-                                         fileUTTypeLists:file_uttype_lists];
-  } else {
-    extension_dropdown_handler_ =
-        [[ExtensionDropdownHandler alloc] initWithDialog:panel_
-                                           fileTypeLists:file_type_lists];
-  }
+  extension_dropdown_handler_ =
+      [[ExtensionDropdownHandler alloc] initWithDialog:panel_
+                                    fileExtensionLists:file_extension_lists];
 
   // This establishes a weak reference to handler. Hence we persist it as part
   // of `dialog_data_list_`.
@@ -565,8 +519,9 @@
 }
 
 void SelectFileDialogBridge::OnPanelEnded(bool did_cancel) {
-  if (!show_callback_)
+  if (!show_callback_) {
     return;
+  }
 
   int index = 0;
   std::vector<base::FilePath> paths;
@@ -596,27 +551,29 @@
       }
     } else {
       // This does not use ObjCCast because the underlying object could be a
-      // non-exported AppKit type (https://crbug.com/995476).
+      // non-exported AppKit type (https://crbug.com/41477018).
       NSOpenPanel* open_panel = static_cast<NSOpenPanel*>(panel_);
 
       for (NSURL* url in open_panel.URLs) {
-        if (!url.isFileURL)
+        if (!url.isFileURL) {
           continue;
+        }
         NSString* path = url.path;
 
         // There is a bug in macOS where, despite a request to disallow file
         // selection, files/packages are able to be selected. If indeed file
         // selection was disallowed, drop any files selected.
-        // https://crbug.com/1357523, FB11405008
+        // https://crbug.com/40861123, FB11405008
         if (!open_panel.canChooseFiles) {
           BOOL is_directory;
           BOOL exists =
-              [[NSFileManager defaultManager] fileExistsAtPath:path
-                                                   isDirectory:&is_directory];
+              [NSFileManager.defaultManager fileExistsAtPath:path
+                                                 isDirectory:&is_directory];
           BOOL is_package =
-              [[NSWorkspace sharedWorkspace] isFilePackageAtPath:path];
-          if (!exists || !is_directory || is_package)
+              [NSWorkspace.sharedWorkspace isFilePackageAtPath:path];
+          if (!exists || !is_directory || is_package) {
             continue;
+          }
         }
 
         paths.push_back(base::apple::NSStringToFilePath(path));
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index 0131eaf..6fe8c2e 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -424,6 +424,8 @@
     sources += [
       "display/dc_layer_overlay.cc",
       "display/dc_layer_overlay.h",
+      "display/overlay_processor_delegated_support.cc",
+      "display/overlay_processor_delegated_support.h",
       "display/overlay_processor_win.cc",
       "display/overlay_processor_win.h",
       "display_embedder/output_device_backing.cc",
diff --git a/components/viz/service/display/overlay_processor_win.cc b/components/viz/service/display/overlay_processor_win.cc
index b281767..f848a5a 100644
--- a/components/viz/service/display/overlay_processor_win.cc
+++ b/components/viz/service/display/overlay_processor_win.cc
@@ -13,6 +13,7 @@
 #include "base/feature_list.h"
 #include "base/ranges/algorithm.h"
 #include "base/trace_event/trace_event.h"
+#include "base/types/expected.h"
 #include "components/viz/common/display/renderer_settings.h"
 #include "components/viz/common/features.h"
 #include "components/viz/common/quads/aggregated_render_pass_draw_quad.h"
@@ -22,6 +23,7 @@
 #include "components/viz/service/display/output_surface.h"
 #include "components/viz/service/display/overlay_candidate.h"
 #include "components/viz/service/display/overlay_candidate_factory.h"
+#include "components/viz/service/display/overlay_processor_delegated_support.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gl/gl_switches.h"
 
@@ -113,8 +115,6 @@
   return context;
 }
 
-DBG_FLAG_FBOOL("delegated.disable.delegation", disable_delegation)
-
 }  // anonymous namespace
 
 OverlayProcessorWin::OverlayProcessorWin(
@@ -168,69 +168,107 @@
     std::vector<gfx::Rect>* content_bounds) {
   TRACE_EVENT0("viz", "OverlayProcessorWin::ProcessForOverlays");
 
-  delegation_succeeded_last_frame_ = false;
+  DebugLogBeforeDelegation(*root_damage_rect,
+                           surface_damage_rect_list_in_root_space);
 
-  if (features::IsDelegatedCompositingEnabled() && !disable_delegation()) {
-    const bool is_full_delegated_compositing =
-        !base::FeatureList::IsEnabled(features::kDelegatedCompositingLimitToUi);
+  DelegationStatus status = ProcessOverlaysForDelegation(
+      resource_provider, render_passes, output_color_matrix,
+      render_pass_filters, render_pass_backdrop_filters,
+      surface_damage_rect_list_in_root_space, candidates, root_damage_rect);
 
-    OverlayCandidateFactory factory(
-        render_passes->back().get(), resource_provider,
-        &surface_damage_rect_list_in_root_space, &output_color_matrix,
-        gfx::RectF(render_passes->back()->output_rect), &render_pass_filters,
-        WindowsDelegatedOverlayContext());
-
-    std::optional<DelegatedCompositingResult> delegation_result =
-        TryDelegatedCompositing(is_full_delegated_compositing, *render_passes,
-                                factory, render_pass_backdrop_filters,
-                                resource_provider);
-
-    // TODO(crbug.com/1502717): Add a histogram to emit delegation status,
-    // similar to OverlayProcessorDelegated::ProcessForOverlays.
-
-    if (delegation_result) {
-      OverlayCandidateList delegated_candidates =
-          std::move(delegation_result.value().candidates);
-      PromotedRenderPassesInfo promoted_render_passes_info =
-          std::move(delegation_result.value().promoted_render_passes_info);
-
-      DBG_LOG_OPT("delegated.overlay.log", DBG_OPT_BLUE,
-                  "delegation success, candidates.size = %zu",
-                  delegated_candidates.size());
-
-      UpdatePromotedRenderPassProperties(*render_passes,
-                                         promoted_render_passes_info);
-
-      // We are not promoting videos from any render pass so this map should be
-      // empty.
-      frames_since_using_dc_layers_map_.clear();
-
-      // Set the z-order of the candidates, noting that |delegated_candidates|
-      // was pushed in front-to-back order.
-      for (size_t i = 0u; i < delegated_candidates.size(); i++) {
-        delegated_candidates[i].plane_z_order = delegated_candidates.size() - i;
-      }
-
-      // Set this to the full output rect unconditionally on success. This is
-      // unioned with the next frame's damage (via |GetAndResetOverlayDamage|)
-      // to fully damage the root surface if the next frame fails delegation.
-      // Since delegated compositing succeeded here, the previous frame's
-      // |overlay_damage_rect_| influence on |root_damage_rect| is cleared
-      // below.
-      // In the case of resize, we will be correctly damaged from another
-      // source.
-      overlay_damage_rect_ = render_passes->back()->output_rect;
-
-      delegation_succeeded_last_frame_ = true;
-      *candidates = std::move(delegated_candidates);
-      *root_damage_rect = gfx::Rect();
-      return;
-    }
-
-    DBG_LOG_OPT("delegated.overlay.log", DBG_OPT_RED,
-                "delegation failed this frame");
+  if (status != DelegationStatus::kFullDelegation) {
+    // Fall back to promoting overlays from the output surface plane.
+    ProcessOverlaysFromOutputSurfacePlane(
+        resource_provider, render_passes, output_color_matrix,
+        render_pass_filters, render_pass_backdrop_filters,
+        surface_damage_rect_list_in_root_space, output_surface_plane,
+        candidates, root_damage_rect);
   }
 
+  DebugLogAfterDelegation(status, *candidates, *root_damage_rect);
+
+  delegation_succeeded_last_frame_ =
+      status == DelegationStatus::kFullDelegation;
+}
+
+DelegationStatus OverlayProcessorWin::ProcessOverlaysForDelegation(
+    DisplayResourceProvider* resource_provider,
+    AggregatedRenderPassList* render_passes,
+    const SkM44& output_color_matrix,
+    const OverlayProcessorInterface::FilterOperationsMap& render_pass_filters,
+    const OverlayProcessorInterface::FilterOperationsMap&
+        render_pass_backdrop_filters,
+    const SurfaceDamageRectList& surface_damage_rect_list_in_root_space,
+    CandidateList* candidates,
+    gfx::Rect* root_damage_rect) {
+  if (!features::IsDelegatedCompositingEnabled() || ForceDisableDelegation()) {
+    return DelegationStatus::kCompositedFeatureDisabled;
+  }
+
+  const bool is_full_delegated_compositing =
+      !base::FeatureList::IsEnabled(features::kDelegatedCompositingLimitToUi);
+
+  OverlayCandidateFactory factory(
+      render_passes->back().get(), resource_provider,
+      &surface_damage_rect_list_in_root_space, &output_color_matrix,
+      gfx::RectF(render_passes->back()->output_rect), &render_pass_filters,
+      WindowsDelegatedOverlayContext());
+
+  base::expected<DelegatedCompositingResult, DelegationStatus>
+      delegation_result = TryDelegatedCompositing(
+          is_full_delegated_compositing, *render_passes, factory,
+          render_pass_backdrop_filters, resource_provider);
+
+  if (delegation_result.has_value()) {
+    OverlayCandidateList delegated_candidates =
+        std::move(delegation_result.value().candidates);
+    PromotedRenderPassesInfo promoted_render_passes_info =
+        std::move(delegation_result.value().promoted_render_passes_info);
+
+    UpdatePromotedRenderPassProperties(*render_passes,
+                                       promoted_render_passes_info);
+
+    // We are not promoting videos from any render pass so this map should be
+    // empty.
+    frames_since_using_dc_layers_map_.clear();
+
+    // Set the z-order of the candidates, noting that |delegated_candidates|
+    // was pushed in front-to-back order.
+    for (size_t i = 0u; i < delegated_candidates.size(); i++) {
+      delegated_candidates[i].plane_z_order = delegated_candidates.size() - i;
+    }
+
+    // Set this to the full output rect unconditionally on success. This is
+    // unioned with the next frame's damage (via |GetAndResetOverlayDamage|)
+    // to fully damage the root surface if the next frame fails delegation.
+    // Since delegated compositing succeeded here, the previous frame's
+    // |overlay_damage_rect_| influence on |root_damage_rect| is cleared
+    // below.
+    // In the case of resize, we will be correctly damaged from another
+    // source.
+    overlay_damage_rect_ = render_passes->back()->output_rect;
+
+    delegation_succeeded_last_frame_ = true;
+    *candidates = std::move(delegated_candidates);
+    *root_damage_rect = gfx::Rect();
+
+    return DelegationStatus::kFullDelegation;
+  } else {
+    return delegation_result.error();
+  }
+}
+
+void OverlayProcessorWin::ProcessOverlaysFromOutputSurfacePlane(
+    DisplayResourceProvider* resource_provider,
+    AggregatedRenderPassList* render_passes,
+    const SkM44& output_color_matrix,
+    const OverlayProcessorInterface::FilterOperationsMap& render_pass_filters,
+    const OverlayProcessorInterface::FilterOperationsMap&
+        render_pass_backdrop_filters,
+    const SurfaceDamageRectList& surface_damage_rect_list_in_root_space,
+    OutputSurfaceOverlayPlane* output_surface_plane,
+    CandidateList* candidates,
+    gfx::Rect* root_damage_rect) {
   auto* root_render_pass = render_passes->back().get();
   if (render_passes->back()->is_color_conversion_pass) {
     DCHECK_GT(render_passes->size(), 1u);
@@ -385,7 +423,8 @@
 OverlayProcessorWin::DelegatedCompositingResult::operator=(
     OverlayProcessorWin::DelegatedCompositingResult&&) = default;
 
-std::optional<OverlayProcessorWin::DelegatedCompositingResult>
+base::expected<OverlayProcessorWin::DelegatedCompositingResult,
+               DelegationStatus>
 OverlayProcessorWin::TryDelegatedCompositing(
     const bool is_full_delegated_compositing,
     const AggregatedRenderPassList& render_passes,
@@ -402,17 +441,13 @@
         "= %d",
         root_render_pass->copy_requests.size(),
         root_render_pass->video_capture_enabled);
-    return std::nullopt;
+    return base::unexpected(DelegationStatus::kCompositedCopyRequest);
   }
 
   if (root_render_pass->is_color_conversion_pass) {
-    // DWM cannot blend non-opaque HDR overlays in the extended sRGB color space
-    // that viz uses.
-    // TODO(crbug.com/1524141): Handle color conversion pass during overlay
-    // processing instead of surface aggregation so we can add it to opaque HDR
-    // overlays, e.g. web contents surfaces.
-    DBG_LOG_OPT("delegated.overlay.log", DBG_OPT_RED, "Frame has HDR content");
-    return std::nullopt;
+    // We don't expect to handle a color conversion pass (e.g. for frames with
+    // HDR content) with delegated compositing. See: crbug.com/41497086
+    return base::unexpected(DelegationStatus::kCompositedOther);
   }
 
   DelegatedCompositingResult result;
@@ -437,30 +472,24 @@
     }
 
     if (!dc_layer.has_value()) {
-      OverlayCandidate overlay;
-      auto res = factory.FromDrawQuad(quad, overlay);
-      if (res == OverlayCandidateFactory::CandidateStatus::kFailVisible) {
-        // These can be safely skipped.
-        continue;
+      if (auto candidate_result =
+              TryPromoteDrawQuadForDelegation(factory, quad);
+          candidate_result.has_value()) {
+        if (auto& candidate = candidate_result.value()) {
+          dc_layer = std::move(candidate);
+        } else {
+          // This quad can be intentionally skipped.
+          continue;
+        }
+      } else {
+        return base::unexpected(candidate_result.error());
       }
-
-      if (res != OverlayCandidateFactory::CandidateStatus::kSuccess) {
-        DBG_LOG_OPT("delegated.overlay.log", DBG_OPT_RED,
-                    "FromDrawQuad failed with status code = %d",
-                    static_cast<int>(res));
-        return std::nullopt;
-      }
-
-      dc_layer = std::make_optional(std::move(overlay));
     }
 
     if (factory.IsOccludedByFilteredQuad(
             dc_layer.value(), root_render_pass->quad_list.begin(),
             root_render_pass->quad_list.end(), render_pass_backdrop_filters)) {
-      DBG_LOG_OPT(
-          "delegated.overlay.log", DBG_OPT_RED,
-          "FromDrawQuad failed because of an occluding backdrop filter");
-      return std::nullopt;
+      return base::unexpected(DelegationStatus::kCompositedBackdropFilter);
     }
 
     // Store metadata on RPDQ overlays for post-processing in
@@ -482,7 +511,7 @@
     result.candidates.push_back(std::move(dc_layer).value());
   }
 
-  return std::make_optional(std::move(result));
+  return base::ok(std::move(result));
 }
 
 // static
diff --git a/components/viz/service/display/overlay_processor_win.h b/components/viz/service/display/overlay_processor_win.h
index 5e5ff439..19a98e3e 100644
--- a/components/viz/service/display/overlay_processor_win.h
+++ b/components/viz/service/display/overlay_processor_win.h
@@ -16,6 +16,7 @@
 #include "components/viz/service/display/dc_layer_overlay.h"
 #include "components/viz/service/display/output_surface.h"
 #include "components/viz/service/display/overlay_candidate.h"
+#include "components/viz/service/display/overlay_processor_delegated_support.h"
 #include "components/viz/service/display/overlay_processor_interface.h"
 #include "components/viz/service/viz_service_export.h"
 #include "gpu/ipc/common/surface_handle.h"
@@ -132,6 +133,37 @@
       AggregatedRenderPass* root_render_pass,
       const gfx::Rect& damage_rect);
 
+  // Promote a subset of quads from the root render pass using
+  // |DCLayerOverlayProcessor| while still intending to schedule the primary
+  // plane as its own overlay. This is the fallback for delegated compositing
+  // that still allows quads to be promoted e.g. for protected content or for
+  // performance reasons.
+  void ProcessOverlaysFromOutputSurfacePlane(
+      DisplayResourceProvider* resource_provider,
+      AggregatedRenderPassList* render_passes,
+      const SkM44& output_color_matrix,
+      const OverlayProcessorInterface::FilterOperationsMap& render_pass_filters,
+      const OverlayProcessorInterface::FilterOperationsMap&
+          render_pass_backdrop_filters,
+      const SurfaceDamageRectList& surface_damage_rect_list_in_root_space,
+      OutputSurfaceOverlayPlane* output_surface_plane,
+      CandidateList* candidates,
+      gfx::Rect* root_damage_rect);
+
+  // Try to promote all quads from the root render pass to overlay.
+  // In partially delegated compositing, RPDQs that represent surfaces will have
+  // quads promoted from their render passes using |DCLayerOverlayProcessor|.
+  DelegationStatus ProcessOverlaysForDelegation(
+      DisplayResourceProvider* resource_provider,
+      AggregatedRenderPassList* render_passes,
+      const SkM44& output_color_matrix,
+      const OverlayProcessorInterface::FilterOperationsMap& render_pass_filters,
+      const OverlayProcessorInterface::FilterOperationsMap&
+          render_pass_backdrop_filters,
+      const SurfaceDamageRectList& surface_damage_rect_list_in_root_space,
+      CandidateList* candidates,
+      gfx::Rect* root_damage_rect);
+
   // This struct holds information about the RPDQ overlays promoted during
   // delegated compositing. It references objects in the current frame and is
   // only valid while the render pass list's pointers are valid.
@@ -164,7 +196,8 @@
   // Attempt to promote all the quads in |root_render_pass|. Promoted quads will
   // be placed in |out_candidates| in front-to-back order. Returns true if all
   // quads were successfully promoted.
-  std::optional<DelegatedCompositingResult> TryDelegatedCompositing(
+  base::expected<DelegatedCompositingResult, DelegationStatus>
+  TryDelegatedCompositing(
       const bool is_full_delegated_compositing,
       const AggregatedRenderPassList& render_passes,
       const OverlayCandidateFactory& factory,
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc
index ae8df18..a17e49d 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -159,32 +159,48 @@
 }  // namespace
 
 SkiaOutputSurfaceImpl::ScopedPaint::ScopedPaint(
-    GrDeferredDisplayListRecorder* root_ddl_recorder)
-    : ddl_recorder_(root_ddl_recorder), canvas_(ddl_recorder_->getCanvas()) {}
+    GrDeferredDisplayListRecorder* root_ddl_recorder,
+    bool skip_draw_for_tests)
+    : ddl_recorder_(root_ddl_recorder), canvas_(ddl_recorder_->getCanvas()) {
+  Initialize(skip_draw_for_tests);
+}
 
 SkiaOutputSurfaceImpl::ScopedPaint::ScopedPaint(
     const GrSurfaceCharacterization& characterization,
-    const gpu::Mailbox& mailbox)
+    const gpu::Mailbox& mailbox,
+    bool skip_draw_for_tests)
     : mailbox_(mailbox) {
   ddl_recorder_storage_.emplace(characterization);
   ddl_recorder_ = &ddl_recorder_storage_.value();
   canvas_ = ddl_recorder_->getCanvas();
+  Initialize(skip_draw_for_tests);
 }
 
 SkiaOutputSurfaceImpl::ScopedPaint::ScopedPaint(
     skgpu::graphite::Recorder* recorder,
     const SkImageInfo& image_info,
     skgpu::graphite::TextureInfo texture_info,
-    const gpu::Mailbox& mailbox)
+    const gpu::Mailbox& mailbox,
+    bool skip_draw_for_tests)
     : graphite_recorder_(recorder), mailbox_(mailbox) {
   CHECK(graphite_recorder_);
   canvas_ = graphite_recorder_->makeDeferredCanvas(image_info, texture_info);
+  Initialize(skip_draw_for_tests);
 }
 
 SkiaOutputSurfaceImpl::ScopedPaint::~ScopedPaint() {
   CHECK(!canvas_);
 }
 
+void SkiaOutputSurfaceImpl::ScopedPaint::Initialize(bool skip_draw_for_tests) {
+  if (canvas_ && skip_draw_for_tests) {
+    auto image_info = canvas_->imageInfo();
+    no_draw_canvas_ = std::make_unique<SkNoDrawCanvas>(image_info.width(),
+                                                       image_info.height());
+    canvas_ = no_draw_canvas_.get();
+  }
+}
+
 sk_sp<GrDeferredDisplayList> SkiaOutputSurfaceImpl::ScopedPaint::DetachDDL() {
   canvas_ = nullptr;
   return ddl_recorder_->detach();
@@ -284,7 +300,9 @@
       display_compositor_controller_(display_controller),
       gpu_task_scheduler_(display_compositor_controller_->gpu_task_scheduler()),
       is_using_raw_draw_(features::IsUsingRawDraw()),
-      is_raw_draw_using_msaa_(features::IsRawDrawUsingMSAA()) {
+      is_raw_draw_using_msaa_(features::IsRawDrawUsingMSAA()),
+      skip_draw_for_tests_(base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableGLDrawingForTests)) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (is_using_raw_draw_) {
     auto* manager = dependency_->GetSharedImageManager();
@@ -460,10 +478,11 @@
         /*supports_multiplanar_rendering=*/false,
         /*supports_multiplanar_copy=*/false);
     CHECK(texture_info.isValid());
-    current_paint_.emplace(graphite_recorder_, image_info, texture_info);
+    current_paint_.emplace(graphite_recorder_, image_info, texture_info,
+                           gpu::Mailbox(), skip_draw_for_tests_);
   } else {
     reset_ddl_recorder_on_swap_ = true;
-    current_paint_.emplace(&root_ddl_recorder_.value());
+    current_paint_.emplace(&root_ddl_recorder_.value(), skip_draw_for_tests_);
   }
   return current_paint_->canvas();
 }
@@ -854,7 +873,7 @@
       return nullptr;
     }
     current_paint_.emplace(graphite_recorder_, image_info, texture_info,
-                           mailbox);
+                           mailbox, skip_draw_for_tests_);
   } else {
     GrSurfaceCharacterization characterization =
         CreateGrSurfaceCharacterizationRenderPass(
@@ -864,7 +883,7 @@
       DLOG(ERROR) << "BeginPaintRenderPass: invalid GrSurfaceCharacterization";
       return nullptr;
     }
-    current_paint_.emplace(characterization, mailbox);
+    current_paint_.emplace(characterization, mailbox, skip_draw_for_tests_);
   }
 
   // We are going to overwrite the render pass when it is not for overlay, so we
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.h b/components/viz/service/display_embedder/skia_output_surface_impl.h
index 227fafdc..5c28e89 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.h
@@ -36,6 +36,8 @@
 #include "third_party/skia/include/private/chromium/GrSurfaceCharacterization.h"
 #include "ui/gfx/presentation_feedback.h"
 
+class SkNoDrawCanvas;
+
 namespace gfx {
 namespace mojom {
 class DelegatedInkPointRenderer;
@@ -304,15 +306,18 @@
   class ScopedPaint {
    public:
     // Ganesh root surface
-    explicit ScopedPaint(GrDeferredDisplayListRecorder* root_ddl_recorder);
+    ScopedPaint(GrDeferredDisplayListRecorder* root_ddl_recorder,
+                bool skip_draw_for_tests);
     // Ganesh render pass (root or non-root)
     ScopedPaint(const GrSurfaceCharacterization& characterization,
-                const gpu::Mailbox& mailbox);
+                const gpu::Mailbox& mailbox,
+                bool skip_draw_for_tests);
     // Graphite (root or non-root)
     ScopedPaint(skgpu::graphite::Recorder* recorder,
                 const SkImageInfo& image_info,
                 skgpu::graphite::TextureInfo texture_info,
-                const gpu::Mailbox& mailbox = gpu::Mailbox());
+                const gpu::Mailbox& mailbox = gpu::Mailbox(),
+                bool skip_draw_for_tests = false);
     ~ScopedPaint();
 
     // SkCanvas for the current paint, retrieved from the DDL recorder for
@@ -329,6 +334,8 @@
     std::unique_ptr<skgpu::graphite::Recording> SnapRecording();
 
    private:
+    void Initialize(bool skip_draw_for_tests);
+
     // This is the DDL recorder being used for current paint when using Ganesh.
     raw_ptr<GrDeferredDisplayListRecorder> ddl_recorder_ = nullptr;
     // If we need new recorder for this Paint (i.e. it's not root render pass),
@@ -336,6 +343,8 @@
     std::optional<GrDeferredDisplayListRecorder> ddl_recorder_storage_;
     // Graphite recorder used for current paint.
     raw_ptr<skgpu::graphite::Recorder> graphite_recorder_ = nullptr;
+    // No draw canvas for tests.
+    std::unique_ptr<SkNoDrawCanvas> no_draw_canvas_;
     // SkCanvas for the current paint, retrieved from the DDL recorder for
     // Ganesh, or from the Graphite recorder.
     raw_ptr<SkCanvas> canvas_ = nullptr;
@@ -468,6 +477,7 @@
       representation_factory_;
   // The refresh interval from presentation feedback.
   base::TimeDelta refresh_interval_;
+  bool skip_draw_for_tests_;
 
   base::WeakPtr<SkiaOutputSurfaceImpl> weak_ptr_;
   base::WeakPtrFactory<SkiaOutputSurfaceImpl> weak_ptr_factory_{this};
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
index 3961940..713120e 100644
--- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
+++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
@@ -1469,8 +1469,10 @@
     // Note: The following is used by
     // chrome/browser/media/cast_mirroring_performance_browsertest.cc, in
     // addition to the usual runtime tracing
-    TRACE_EVENT_END("gpu.capture", CaptureTrack(frame->metadata()), "success",
-                    false);
+    if (frame) {
+      TRACE_EVENT_END("gpu.capture", CaptureTrack(frame->metadata()), "success",
+                      false);
+    }
     MaybeScheduleRefreshFrame();
     return;
   }
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 9d4172e..dfcda910 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -762,8 +762,6 @@
     "cookie_store/cookie_store_host.h",
     "cookie_store/cookie_store_manager.cc",
     "cookie_store/cookie_store_manager.h",
-    "coop_related_group.cc",
-    "coop_related_group.h",
     "data_url_loader_factory.cc",
     "data_url_loader_factory.h",
     "device/device_service.cc",
@@ -1367,8 +1365,6 @@
     "network/cookie_store_factory.cc",
     "network/cross_origin_embedder_policy_reporter.cc",
     "network/cross_origin_embedder_policy_reporter.h",
-    "network/cross_origin_opener_policy_reporter.cc",
-    "network/cross_origin_opener_policy_reporter.h",
     "network/http_cache_backend_file_operations_factory.cc",
     "network/http_cache_backend_file_operations_factory.h",
     "network/network_errors_listing_ui.cc",
@@ -1640,11 +1636,6 @@
     "renderer_host/concurrent_navigations_commit_deferring_condition.h",
     "renderer_host/cookie_utils.cc",
     "renderer_host/cookie_utils.h",
-    "renderer_host/coop_swap_result.h",
-    "renderer_host/cross_origin_opener_policy_access_report_manager.cc",
-    "renderer_host/cross_origin_opener_policy_access_report_manager.h",
-    "renderer_host/cross_origin_opener_policy_status.cc",
-    "renderer_host/cross_origin_opener_policy_status.h",
     "renderer_host/cross_process_frame_connector.cc",
     "renderer_host/cross_process_frame_connector.h",
     "renderer_host/cursor_manager.cc",
@@ -1954,6 +1945,15 @@
     "screenlock_monitor/screenlock_monitor_device_source.h",
     "screenlock_monitor/screenlock_monitor_source.cc",
     "screenlock_monitor/screenlock_monitor_source.h",
+    "security/coop/coop_related_group.cc",
+    "security/coop/coop_related_group.h",
+    "security/coop/coop_swap_result.h",
+    "security/coop/cross_origin_opener_policy_access_report_manager.cc",
+    "security/coop/cross_origin_opener_policy_access_report_manager.h",
+    "security/coop/cross_origin_opener_policy_reporter.cc",
+    "security/coop/cross_origin_opener_policy_reporter.h",
+    "security/coop/cross_origin_opener_policy_status.cc",
+    "security/coop/cross_origin_opener_policy_status.h",
     "service_process_host_impl.cc",
     "service_worker/embedded_worker_instance.cc",
     "service_worker/embedded_worker_instance.h",
diff --git a/content/browser/accessibility/accessibility_ipc_error_browsertest.cc b/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
index 7ea766c..e9681724 100644
--- a/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
+++ b/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
@@ -14,9 +14,9 @@
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "ui/accessibility/ax_common.h"
-#include "ui/accessibility/ax_event_notification_details.h"
 #include "ui/accessibility/ax_node.h"
 #include "ui/accessibility/ax_tree.h"
+#include "ui/accessibility/ax_updates_and_events.h"
 
 namespace content {
 
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index e164a66..c5e1bbb 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -52,6 +52,9 @@
 #endif  // !BUILDFLAG(HAS_PLATFORM_ACCESSIBILITY_SUPPORT)
 
 // static
+bool BrowserAccessibility::ignore_hovered_state_for_testing_ = false;
+
+// static
 BrowserAccessibility* BrowserAccessibility::FromAXPlatformNodeDelegate(
     ui::AXPlatformNodeDelegate* delegate) {
   if (!delegate || !delegate->IsWebContent())
@@ -1799,9 +1802,7 @@
 }
 
 bool BrowserAccessibility::ShouldIgnoreHoveredStateForTesting() {
-  BrowserAccessibilityStateImpl* accessibility_state =
-      BrowserAccessibilityStateImpl::GetInstance();
-  return accessibility_state->disable_hot_tracking_for_testing();
+  return ignore_hovered_state_for_testing_;
 }
 
 std::optional<int> BrowserAccessibility::GetPosInSet() const {
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index 09da79a..fd1a306 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -37,7 +37,7 @@
 
 namespace content {
 class BrowserAccessibilityManager;
-
+class DumpAccessibilityTestBase;
 // A `BrowserAccessibility` object represents one node in the accessibility tree
 // on the browser side. It wraps an `AXNode` and assists in exposing
 // web-specific information from the node. It's owned by a
@@ -475,6 +475,10 @@
   // starting point for tree dumps.
   friend class AccessibilityTreeFormatterUia;
 
+  // DumpAccessibilityTestBase needs to be able to set
+  // ignore_hovered_state_for_testing_ to avoid flaky tests.
+  friend class DumpAccessibilityTestBase;
+
  private:
   // Return the bounds after converting from this node's coordinate system
   // (which is relative to its nearest scrollable ancestor) to the coordinate
@@ -531,6 +535,14 @@
   // attribute originating from ARIA.
   static bool HasInvalidAttribute(const ui::TextAttributeList& attributes);
 
+  // Disable hover state - needed just to avoid flaky tests.
+  // Accessibility objects can have the "hot tracked" state set when
+  // the mouse is hovering over them, but this makes tests flaky because
+  // the test behaves differently when the mouse happens to be over an
+  // element.  This is a global switch to not use the "hot tracked" state
+  // in a test.
+  static bool ignore_hovered_state_for_testing_;
+
   // A unique ID, since node IDs are frame-local.
   // TODO(accessibility) We should be able to get rid of this, because node IDs
   // are actually local to the renderer process, and each renderer process has
diff --git a/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc b/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc
index a330ac7..6be148b 100644
--- a/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc
@@ -306,7 +306,7 @@
   g_object_unref(root_atk_object);
 
   text1.SetName(text1_name + text1_name);
-  ui::AXEventNotificationDetails event_bundle;
+  ui::AXUpdatesAndEvents event_bundle;
   event_bundle.updates.resize(1);
   event_bundle.updates[0].nodes.push_back(text1);
   event_bundle.updates[0].nodes.push_back(root);
diff --git a/content/browser/accessibility/browser_accessibility_mac_unittest.mm b/content/browser/accessibility/browser_accessibility_mac_unittest.mm
index 0822b45..e497ec57 100644
--- a/content/browser/accessibility/browser_accessibility_mac_unittest.mm
+++ b/content/browser/accessibility/browser_accessibility_mac_unittest.mm
@@ -18,8 +18,8 @@
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
-#include "ui/accessibility/ax_event_notification_details.h"
 #include "ui/accessibility/ax_tree_update.h"
+#include "ui/accessibility/ax_updates_and_events.h"
 #import "ui/base/test/cocoa_helper.h"
 
 namespace content {
@@ -113,7 +113,7 @@
     if (!manager_)
       return;
     root_.SetValue(value);
-    ui::AXEventNotificationDetails event_bundle;
+    ui::AXUpdatesAndEvents event_bundle;
     event_bundle.updates.resize(1);
     event_bundle.updates[0].nodes.push_back(root_);
     ASSERT_TRUE(manager_->OnAccessibilityEvents(event_bundle));
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
index a47d7298..f824bdc 100644
--- a/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -409,7 +409,7 @@
 }
 
 bool BrowserAccessibilityManager::OnAccessibilityEvents(
-    const ui::AXEventNotificationDetails& details) {
+    const ui::AXUpdatesAndEvents& details) {
   TRACE_EVENT0("accessibility",
                "BrowserAccessibilityManager::OnAccessibilityEvents");
   SCOPED_UMA_HISTOGRAM_TIMER_MICROS(
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h
index 821b750..b981e081 100644
--- a/content/browser/accessibility/browser_accessibility_manager.h
+++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -24,7 +24,6 @@
 #include "third_party/blink/public/web/web_ax_enums.h"
 #include "ui/accessibility/ax_action_data.h"
 #include "ui/accessibility/ax_action_handler_registry.h"
-#include "ui/accessibility/ax_event_notification_details.h"
 #include "ui/accessibility/ax_node.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/accessibility/ax_node_id_forward.h"
@@ -35,6 +34,7 @@
 #include "ui/accessibility/ax_tree_manager.h"
 #include "ui/accessibility/ax_tree_observer.h"
 #include "ui/accessibility/ax_tree_update.h"
+#include "ui/accessibility/ax_updates_and_events.h"
 #include "ui/accessibility/platform/ax_platform_node.h"
 #include "ui/accessibility/platform/ax_platform_tree_manager.h"
 #include "ui/accessibility/platform/ax_platform_tree_manager_delegate.h"
@@ -258,8 +258,7 @@
   // Called when the renderer process has notified us of tree changes. Returns
   // false in fatal-error conditions, in which case the caller should destroy
   // the manager.
-  virtual bool OnAccessibilityEvents(
-      const ui::AXEventNotificationDetails& details);
+  virtual bool OnAccessibilityEvents(const ui::AXUpdatesAndEvents& details);
 
   // Allows derived classes to do event pre-processing
   virtual void BeforeAccessibilityEvents();
diff --git a/content/browser/accessibility/browser_accessibility_manager_fuchsia_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_fuchsia_unittest.cc
index 8c1b20209..81d0d97 100644
--- a/content/browser/accessibility/browser_accessibility_manager_fuchsia_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_fuchsia_unittest.cc
@@ -353,7 +353,7 @@
   // Set focus to node 1, and check that the focus was updated from null to
   // node 1.
   {
-    ui::AXEventNotificationDetails event;
+    ui::AXUpdatesAndEvents event;
     ui::AXTreeUpdate updated_state;
     updated_state.tree_data.tree_id = tree_id;
     updated_state.has_tree_data = true;
@@ -378,7 +378,7 @@
   // Set focus to node 2, and check that focus was updated from node 1 to node
   // 2.
   {
-    ui::AXEventNotificationDetails event;
+    ui::AXUpdatesAndEvents event;
     ui::AXTreeUpdate updated_state;
     updated_state.tree_data.tree_id = tree_id;
     updated_state.has_tree_data = true;
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.h b/content/browser/accessibility/browser_accessibility_manager_mac.h
index fcddbf17..25309df 100644
--- a/content/browser/accessibility/browser_accessibility_manager_mac.h
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.h
@@ -15,7 +15,7 @@
 #import "content/browser/accessibility/browser_accessibility_cocoa.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/common/content_export.h"
-#include "ui/accessibility/ax_event_notification_details.h"
+#include "ui/accessibility/ax_updates_and_events.h"
 
 namespace ui {
 class AXPlatformTreeManagerDelegate;
@@ -57,8 +57,7 @@
       ax::mojom::AriaNotificationInterrupt interrupt_property,
       ax::mojom::AriaNotificationPriority priority_property) override;
 
-  bool OnAccessibilityEvents(
-      const ui::AXEventNotificationDetails& details) override;
+  bool OnAccessibilityEvents(const ui::AXUpdatesAndEvents& details) override;
 
   id GetParentView();
   id GetWindow();
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm
index d94fa884..ec784e17 100644
--- a/content/browser/accessibility/browser_accessibility_manager_mac.mm
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -477,7 +477,7 @@
 }
 
 bool BrowserAccessibilityManagerMac::OnAccessibilityEvents(
-    const ui::AXEventNotificationDetails& details) {
+    const ui::AXUpdatesAndEvents& details) {
   text_edits_.clear();
   return BrowserAccessibilityManager::OnAccessibilityEvents(details);
 }
diff --git a/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
index c0bb55b..aaeee7a0 100644
--- a/content/browser/accessibility/browser_accessibility_manager_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
@@ -18,8 +18,8 @@
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/accessibility/ax_common.h"
-#include "ui/accessibility/ax_event_notification_details.h"
 #include "ui/accessibility/ax_tree.h"
+#include "ui/accessibility/ax_updates_and_events.h"
 #include "ui/accessibility/platform/test_ax_platform_tree_manager_delegate.h"
 #include "ui/accessibility/test_ax_tree_update.h"
 
@@ -131,7 +131,7 @@
   node4.child_ids.push_back(5);
   ui::AXTreeUpdate update = MakeAXTreeUpdateForTesting(node4, node5);
   update.tree_data.tree_id = manager->GetTreeID();
-  ui::AXEventNotificationDetails events;
+  ui::AXUpdatesAndEvents events;
   events.updates = {update};
 
 #if defined(AX_FAIL_FAST_BUILD)
@@ -1161,7 +1161,7 @@
   update2.tree_data.tree_id = initial_state.tree_data.tree_id;
   update2.node_id_to_clear = root.id;
   update2.root_id = root2.id;
-  ui::AXEventNotificationDetails events2;
+  ui::AXUpdatesAndEvents events2;
   events2.updates = {update2};
   ASSERT_TRUE(manager->OnAccessibilityEvents(events2));
 
@@ -1212,7 +1212,7 @@
   update2.tree_data.tree_id = initial_state.tree_data.tree_id;
   update2.node_id_to_clear = root.id;
   update2.root_id = root2.id;
-  ui::AXEventNotificationDetails events2;
+  ui::AXUpdatesAndEvents events2;
   events2.updates = {update2};
   ASSERT_TRUE(manager->OnAccessibilityEvents(events2));
 
@@ -1250,7 +1250,7 @@
   tree_data.focus_id = button.id;
   update.has_tree_data = true;
   update.tree_data = tree_data;
-  ui::AXEventNotificationDetails events;
+  ui::AXUpdatesAndEvents events;
   events.updates = {update};
   ASSERT_TRUE(manager->OnAccessibilityEvents(events));
 
@@ -1282,7 +1282,7 @@
   manager->ax_tree()->AddObserver(&observer);
 
   // Update each of the children using separate AXTreeUpdates.
-  ui::AXEventNotificationDetails events;
+  ui::AXUpdatesAndEvents events;
   events.updates.resize(3);
   for (int i = 0; i < 3; i++) {
     ui::AXTreeUpdate update;
@@ -1435,7 +1435,7 @@
   popup_button.child_ids = {};
   ui::AXTreeUpdate update = MakeAXTreeUpdateForTesting(popup_button);
   update.tree_data.tree_id = manager->GetTreeID();
-  ui::AXEventNotificationDetails events;
+  ui::AXUpdatesAndEvents events;
   events.updates = {update};
   ASSERT_TRUE(manager->OnAccessibilityEvents(events));
 
diff --git a/content/browser/accessibility/browser_accessibility_state_impl.h b/content/browser/accessibility/browser_accessibility_state_impl.h
index d52e7f04..94cd08aa 100644
--- a/content/browser/accessibility/browser_accessibility_state_impl.h
+++ b/content/browser/accessibility/browser_accessibility_state_impl.h
@@ -111,18 +111,6 @@
   void OnUserInputEvent();
   void OnAccessibilityApiUsage();
 
-  // Accessibility objects can have the "hot tracked" state set when
-  // the mouse is hovering over them, but this makes tests flaky because
-  // the test behaves differently when the mouse happens to be over an
-  // element.  This is a global switch to not use the "hot tracked" state
-  // in a test.
-  void set_disable_hot_tracking_for_testing(bool disable_hot_tracking) {
-    disable_hot_tracking_ = disable_hot_tracking;
-  }
-  bool disable_hot_tracking_for_testing() const {
-    return disable_hot_tracking_;
-  }
-
   // Calls InitBackgroundTasks with short delays for scheduled tasks,
   // and then calls the given completion callback when done.
   void CallInitBackgroundTasksForTesting(base::RepeatingClosure done_callback);
@@ -183,9 +171,6 @@
   // --force-renderer-accessibility is used on the command line.
   bool allow_ax_mode_changes_ = true;
 
-  // Disable hot tracking, i.e. hover state - needed just to avoid flaky tests.
-  bool disable_hot_tracking_ = false;
-
   // Keeps track of whether caret browsing is enabled for the most
   // recently used profile.
   bool caret_browsing_enabled_ = false;
diff --git a/content/browser/accessibility/browser_accessibility_win_unittest.cc b/content/browser/accessibility/browser_accessibility_win_unittest.cc
index 96303f4..2f00be7 100644
--- a/content/browser/accessibility/browser_accessibility_win_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -239,7 +239,7 @@
   text2.id = 2;
   text2.role = ax::mojom::Role::kStaticText;
   text2.SetName("new text");
-  ui::AXEventNotificationDetails event_bundle;
+  ui::AXUpdatesAndEvents event_bundle;
   event_bundle.updates.resize(1);
   event_bundle.updates[0].nodes.push_back(text2);
   ASSERT_TRUE(manager->OnAccessibilityEvents(event_bundle));
@@ -302,7 +302,7 @@
   // Notify the BrowserAccessibilityManager that the div node and its children
   // were removed and ensure that only one BrowserAccessibility instance exists.
   root.child_ids.clear();
-  ui::AXEventNotificationDetails event_bundle;
+  ui::AXUpdatesAndEvents event_bundle;
   event_bundle.updates.resize(1);
   event_bundle.updates[0].nodes.push_back(root);
   ASSERT_TRUE(manager->OnAccessibilityEvents(event_bundle));
@@ -1034,7 +1034,7 @@
   tree1_2.AddStringAttribute(ax::mojom::StringAttribute::kInputType, "text");
 
   // Process a load complete.
-  ui::AXEventNotificationDetails event_bundle;
+  ui::AXUpdatesAndEvents event_bundle;
   event_bundle.updates.resize(1);
   event_bundle.updates[0].node_id_to_clear = root->GetId();
   event_bundle.updates[0].root_id = tree1_1.id;
@@ -3285,7 +3285,7 @@
   std::vector<int32_t> labelledby_ids = {3};
   child1.AddIntListAttribute(ax::mojom::IntListAttribute::kLabelledbyIds,
                              labelledby_ids);
-  ui::AXEventNotificationDetails event_bundle;
+  ui::AXUpdatesAndEvents event_bundle;
   event_bundle.updates.resize(1);
   event_bundle.updates[0].nodes.push_back(child1);
   ASSERT_TRUE(manager->OnAccessibilityEvents(event_bundle));
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
index 7ef6b12d..066abd6 100644
--- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc
+++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -381,10 +381,9 @@
     const base::FilePath file_path,
     const char* file_dir,
     const base::FilePath::StringType& expectations_qualifier) {
-  // Disable the "hot tracked" state (set when the mouse is hovering over
+  // Ignore the hovered state (set when the mouse is hovering over
   // an object) because it makes test output change based on the mouse position.
-  BrowserAccessibilityStateImpl::GetInstance()
-      ->set_disable_hot_tracking_for_testing(true);
+  BrowserAccessibility::ignore_hovered_state_for_testing_ = true;
 
   // Normally some accessibility events that would be fired are suppressed or
   // delayed, depending on what has focus or the type of event. For testing,
diff --git a/content/browser/android/java/gin_java_bridge_dispatcher_host.cc b/content/browser/android/java/gin_java_bridge_dispatcher_host.cc
index 4fb5a71..85bc2af 100644
--- a/content/browser/android/java/gin_java_bridge_dispatcher_host.cc
+++ b/content/browser/android/java/gin_java_bridge_dispatcher_host.cc
@@ -443,7 +443,7 @@
       }
       ++iter;
     } else {
-      objects_.erase(iter++);
+      iter = objects_.erase(iter);
     }
   }
 }
diff --git a/content/browser/browsing_instance.cc b/content/browser/browsing_instance.cc
index 720c4d0..8abbb6e 100644
--- a/content/browser/browsing_instance.cc
+++ b/content/browser/browsing_instance.cc
@@ -8,8 +8,8 @@
 #include "base/command_line.h"
 #include "base/containers/contains.h"
 #include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/coop_related_group.h"
 #include "content/browser/origin_agent_cluster_isolation_state.h"
+#include "content/browser/security/coop/coop_related_group.h"
 #include "content/browser/site_info.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/public/browser/browser_context.h"
diff --git a/content/browser/browsing_instance.h b/content/browser/browsing_instance.h
index f8b24d2f..c2150f0 100644
--- a/content/browser/browsing_instance.h
+++ b/content/browser/browsing_instance.h
@@ -14,8 +14,8 @@
 #include "base/lazy_instance.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
-#include "content/browser/coop_related_group.h"
 #include "content/browser/isolation_context.h"
+#include "content/browser/security/coop/coop_related_group.h"
 #include "content/browser/site_instance_group_manager.h"
 #include "content/browser/web_exposed_isolation_info.h"
 #include "content/common/content_export.h"
diff --git a/content/browser/child_process_host_impl.cc b/content/browser/child_process_host_impl.cc
index 6aba057..e5717d0 100644
--- a/content/browser/child_process_host_impl.cc
+++ b/content/browser/child_process_host_impl.cc
@@ -289,7 +289,8 @@
   return channel_->Send(message);
 }
 
-int ChildProcessHostImpl::GenerateChildProcessUniqueId() {
+// static
+int ChildProcessHost::GenerateChildProcessUniqueId() {
   // This function must be threadsafe.
   //
   // Historically, this function returned ids started with 1, so in several
diff --git a/content/browser/child_process_host_impl.h b/content/browser/child_process_host_impl.h
index a5cc2002..ca5b8176 100644
--- a/content/browser/child_process_host_impl.h
+++ b/content/browser/child_process_host_impl.h
@@ -50,17 +50,6 @@
 
   ~ChildProcessHostImpl() override;
 
-  // Returns a unique ID to identify a child process. On construction, this
-  // function will be used to generate the id_, but it is also used to generate
-  // IDs for the RenderProcessHost, which doesn't inherit from us, and whose IDs
-  // must be unique for all child processes.
-  //
-  // This function is threadsafe since RenderProcessHost is on the UI thread,
-  // but normally this will be used on the IO thread.
-  //
-  // This will never return ChildProcessHost::kInvalidUniqueID.
-  static int GenerateChildProcessUniqueId();
-
   // Derives a tracing process id from a child process id. Child process ids
   // cannot be used directly in child process for tracing due to security
   // reasons (see: discussion in crrev.com/1173263004). This method is meant to
diff --git a/content/browser/manifest/manifest_manager_host.cc b/content/browser/manifest/manifest_manager_host.cc
index 740f7067..68450b8 100644
--- a/content/browser/manifest/manifest_manager_host.cc
+++ b/content/browser/manifest/manifest_manager_host.cc
@@ -7,6 +7,7 @@
 #include <stdint.h>
 
 #include "base/functional/bind.h"
+#include "base/strings/strcat.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/public/common/content_client.h"
 #include "mojo/public/cpp/bindings/message.h"
@@ -119,12 +120,21 @@
   } else if (!blink::IsEmptyManifest(manifest)) {
     // `start_url`, `id`, and `scope` MUST be populated if the manifest is not
     // empty.
-    if (!manifest->start_url.is_valid() || !manifest->id.is_valid() ||
-        !manifest->scope.is_valid()) {
+    bool start_url_valid = manifest->start_url.is_valid();
+    bool id_valid = manifest->id.is_valid();
+    bool scope_valid = manifest->scope.is_valid();
+    if (!start_url_valid || !id_valid || !scope_valid) {
       manifest = blink::mojom::Manifest::New();
+      constexpr auto valid_to_string = [](bool b) -> std::string_view {
+        return b ? "valid" : "invalid";
+      };
       mojo::ReportBadMessage(
-          "RequestManifest's manifest must either be empty or populate the "
-          "the start_url, id, and scope.");
+          base::StrCat({"RequestManifest's manifest must "
+                        "either be empty or populate the "
+                        "the start_url (",
+                        valid_to_string(start_url_valid), "), id(",
+                        valid_to_string(id_valid), "), and scope (",
+                        valid_to_string(scope_valid), ")."}));
     }
   }
   std::move(callback).Run(url, std::move(manifest));
diff --git a/content/browser/renderer_host/browsing_context_state.h b/content/browser/renderer_host/browsing_context_state.h
index bfdd0c9a..62ec7fad 100644
--- a/content/browser/renderer_host/browsing_context_state.h
+++ b/content/browser/renderer_host/browsing_context_state.h
@@ -9,8 +9,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/safe_ref.h"
 #include "base/unguessable_token.h"
-#include "content/browser/coop_related_group.h"
 #include "content/browser/renderer_host/render_frame_proxy_host.h"
+#include "content/browser/security/coop/coop_related_group.h"
 #include "content/browser/site_instance_group.h"
 #include "content/public/browser/browsing_instance_id.h"
 #include "third_party/blink/public/mojom/frame/frame_replication_state.mojom-forward.h"
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index a6ea4763d..3c7d923 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -60,7 +60,6 @@
 #include "content/browser/loader/url_loader_factory_utils.h"
 #include "content/browser/navigation_or_document_handle.h"
 #include "content/browser/network/cross_origin_embedder_policy_reporter.h"
-#include "content/browser/network/cross_origin_opener_policy_reporter.h"
 #include "content/browser/network_service_instance_impl.h"
 #include "content/browser/origin_agent_cluster_isolation_state.h"
 #include "content/browser/origin_trials/origin_trials_utils.h"
@@ -95,6 +94,7 @@
 #include "content/browser/renderer_host/system_entropy_utils.h"
 #include "content/browser/runtime_feature_state/runtime_feature_state_document_data.h"
 #include "content/browser/scoped_active_url.h"
+#include "content/browser/security/coop/cross_origin_opener_policy_reporter.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_main_resource_handle.h"
 #include "content/browser/shared_storage/shared_storage_header_observer.h"
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index 79091c7..4b7effe 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -29,13 +29,13 @@
 #include "content/browser/navigation_subresource_loader_params.h"
 #include "content/browser/renderer_host/browsing_context_group_swap.h"
 #include "content/browser/renderer_host/commit_deferring_condition_runner.h"
-#include "content/browser/renderer_host/cross_origin_opener_policy_status.h"
 #include "content/browser/renderer_host/navigation_controller_impl.h"
 #include "content/browser/renderer_host/navigation_policy_container_builder.h"
 #include "content/browser/renderer_host/navigation_throttle_runner.h"
 #include "content/browser/renderer_host/navigation_type.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/scoped_view_transition_resources.h"
+#include "content/browser/security/coop/cross_origin_opener_policy_status.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/browser/webui/web_ui_controller_factory_registry.h"
 #include "content/browser/webui/web_ui_impl.h"
diff --git a/content/browser/renderer_host/render_frame_host_delegate.h b/content/browser/renderer_host/render_frame_host_delegate.h
index 2c7e863e..c449d46 100644
--- a/content/browser/renderer_host/render_frame_host_delegate.h
+++ b/content/browser/renderer_host/render_frame_host_delegate.h
@@ -99,8 +99,8 @@
 
 namespace ui {
 class ClipboardFormatType;
-struct AXEventNotificationDetails;
-struct AXLocationChangeNotificationDetails;
+struct AXUpdatesAndEvents;
+struct AXLocationChanges;
 }
 
 namespace content {
@@ -300,9 +300,9 @@
   // from a render frame, when the accessibility mode has the
   // ui::AXMode::kWebContents flag set.
   virtual void AccessibilityEventReceived(
-      const ui::AXEventNotificationDetails& details) {}
+      const ui::AXUpdatesAndEvents& details) {}
   virtual void AccessibilityLocationChangesReceived(
-      const std::vector<ui::AXLocationChangeNotificationDetails>& details) {}
+      const std::vector<ui::AXLocationChanges>& details) {}
 
   // Indicates an unrecoverable error in accessibility. Gracefully turns off
   // accessibility in all frames.
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 6f07d02..7c46bcbc 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -100,7 +100,6 @@
 #include "content/browser/navigation_or_document_handle.h"
 #include "content/browser/navigation_subresource_loader_params.h"
 #include "content/browser/network/cross_origin_embedder_policy_reporter.h"
-#include "content/browser/network/cross_origin_opener_policy_reporter.h"
 #include "content/browser/permissions/permission_controller_impl.h"
 #include "content/browser/permissions/permission_service_context.h"
 #include "content/browser/preloading/preloading_decider.h"
@@ -142,6 +141,7 @@
 #include "content/browser/renderer_host/view_transition_opt_in_state.h"
 #include "content/browser/runtime_feature_state/runtime_feature_state_document_data.h"
 #include "content/browser/scoped_active_url.h"
+#include "content/browser/security/coop/cross_origin_opener_policy_reporter.h"
 #include "content/browser/service_worker/service_worker_container_host.h"
 #include "content/browser/service_worker/service_worker_object_host.h"
 #include "content/browser/site_info.h"
@@ -282,8 +282,8 @@
 #include "ui/accessibility/accessibility_features.h"
 #include "ui/accessibility/ax_action_handler_registry.h"
 #include "ui/accessibility/ax_common.h"
-#include "ui/accessibility/ax_event_notification_details.h"
 #include "ui/accessibility/ax_tree_update.h"
+#include "ui/accessibility/ax_updates_and_events.h"
 #include "ui/base/ime/text_input_client.h"
 #include "ui/display/screen.h"
 #include "ui/events/event_constants.h"
@@ -7271,7 +7271,7 @@
 }
 
 void RenderFrameHostImpl::SendAccessibilityEventsToManager(
-    const ui::AXEventNotificationDetails& details) {
+    const ui::AXUpdatesAndEvents& details) {
   if (!browser_accessibility_manager_) {
     return;
   }
@@ -9726,7 +9726,7 @@
 
   GetOrCreateBrowserAccessibilityManager();
 
-  ui::AXEventNotificationDetails details;
+  ui::AXUpdatesAndEvents details;
   details.ax_tree_id = tree_id;
   details.events = std::move(updates_and_events->events);
   details.updates = std::move(updates_and_events->updates);
@@ -9815,10 +9815,10 @@
     manager->OnLocationChanges(changes);
 
   // Send the updates to the automation extension API.
-  std::vector<ui::AXLocationChangeNotificationDetails> details;
+  std::vector<ui::AXLocationChanges> details;
   details.reserve(changes.size());
   for (auto& change : changes) {
-    ui::AXLocationChangeNotificationDetails detail;
+    ui::AXLocationChanges detail;
     detail.id = change->id;
     detail.ax_tree_id = GetAXTreeID();
     detail.new_location = change->new_location;
@@ -11447,7 +11447,7 @@
     return;
   }
 
-  ui::AXEventNotificationDetails detail;
+  ui::AXUpdatesAndEvents detail;
   detail.ax_tree_id = GetAXTreeID();
   detail.updates.resize(1);
   detail.updates[0].has_tree_data = true;
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index 332eab59f..3de932b3 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -49,12 +49,10 @@
 #include "content/browser/browser_interface_broker_impl.h"
 #include "content/browser/buckets/bucket_context.h"
 #include "content/browser/can_commit_status.h"
-#include "content/browser/network/cross_origin_opener_policy_reporter.h"
 #include "content/browser/renderer_host/back_forward_cache_impl.h"
 #include "content/browser/renderer_host/back_forward_cache_metrics.h"
 #include "content/browser/renderer_host/browsing_context_state.h"
 #include "content/browser/renderer_host/code_cache_host_impl.h"
-#include "content/browser/renderer_host/cross_origin_opener_policy_access_report_manager.h"
 #include "content/browser/renderer_host/document_associated_data.h"
 #include "content/browser/renderer_host/frame_navigation_entry.h"
 #include "content/browser/renderer_host/keep_alive_handle_factory.h"
@@ -68,6 +66,8 @@
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/transient_allow_popup.h"
 #include "content/browser/renderer_host/transient_focus_source_user_activation.h"
+#include "content/browser/security/coop/cross_origin_opener_policy_access_report_manager.h"
+#include "content/browser/security/coop/cross_origin_opener_policy_reporter.h"
 #include "content/browser/site_instance_group.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/browser/storage_partition_impl.h"
@@ -613,8 +613,7 @@
   bool IsInactiveAndDisallowActivationForAXEvents(
       const std::vector<ui::AXEvent>& events);
 
-  void SendAccessibilityEventsToManager(
-      const ui::AXEventNotificationDetails& details);
+  void SendAccessibilityEventsToManager(const ui::AXUpdatesAndEvents& details);
 
   // Evict the RenderFrameHostImpl with |reason| that causes the eviction. This
   // constructs a flattened list of NotRestoredReasons and calls
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
index b498a82..70abee3 100644
--- a/content/browser/renderer_host/render_frame_host_manager.cc
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -31,7 +31,6 @@
 #include "build/build_config.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/devtools/render_frame_devtools_agent_host.h"
-#include "content/browser/network/cross_origin_opener_policy_reporter.h"
 #include "content/browser/preloading/prefetch/prefetch_features.h"
 #include "content/browser/process_lock.h"
 #include "content/browser/renderer_host/agent_scheduling_group_host.h"
@@ -57,6 +56,7 @@
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
 #include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
+#include "content/browser/security/coop/cross_origin_opener_policy_reporter.h"
 #include "content/browser/site_info.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/browser/webui/web_ui_controller_factory_registry.h"
diff --git a/content/browser/renderer_host/render_frame_host_manager.h b/content/browser/renderer_host/render_frame_host_manager.h
index b192812..f976113 100644
--- a/content/browser/renderer_host/render_frame_host_manager.h
+++ b/content/browser/renderer_host/render_frame_host_manager.h
@@ -20,12 +20,12 @@
 #include "base/types/expected.h"
 #include "content/browser/renderer_host/browsing_context_group_swap.h"
 #include "content/browser/renderer_host/browsing_context_state.h"
-#include "content/browser/renderer_host/cross_origin_opener_policy_status.h"
 #include "content/browser/renderer_host/navigation_discard_reason.h"
 #include "content/browser/renderer_host/navigation_request.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/should_swap_browsing_instance.h"
 #include "content/browser/renderer_host/stored_page.h"
+#include "content/browser/security/coop/cross_origin_opener_policy_status.h"
 #include "content/browser/site_instance_group.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/browser/web_exposed_isolation_info.h"
diff --git a/content/browser/security/README.md b/content/browser/security/README.md
new file mode 100644
index 0000000..390ba9e60
--- /dev/null
+++ b/content/browser/security/README.md
@@ -0,0 +1,4 @@
+This directory contains the browser-process implementation of security policies
+of the web platform.
+
+Note: this directory is still under construction.
diff --git a/content/browser/security/coop/DIR_METADATA b/content/browser/security/coop/DIR_METADATA
new file mode 100644
index 0000000..2bd59784
--- /dev/null
+++ b/content/browser/security/coop/DIR_METADATA
@@ -0,0 +1,9 @@
+monorail: {
+  component: "Blink>SecurityFeature>COOP"
+}
+
+buganizer_public: {
+  component_id: 1456645
+}
+
+team_email: "chrome-security-owp-team@google.com"
diff --git a/content/browser/security/coop/README.md b/content/browser/security/coop/README.md
new file mode 100644
index 0000000..5feb9e4
--- /dev/null
+++ b/content/browser/security/coop/README.md
@@ -0,0 +1,5 @@
+This directory contains classes needed by the browser process implementation of
+[Cross-Origin-Opener-Policy].
+
+
+[Cross-Origin-Opener-Policy]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy
diff --git a/content/browser/coop_related_group.cc b/content/browser/security/coop/coop_related_group.cc
similarity index 98%
rename from content/browser/coop_related_group.cc
rename to content/browser/security/coop/coop_related_group.cc
index cad812d..635e5a7 100644
--- a/content/browser/coop_related_group.cc
+++ b/content/browser/security/coop/coop_related_group.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/coop_related_group.h"
+#include "content/browser/security/coop/coop_related_group.h"
 
 #include "content/browser/browsing_instance.h"
 #include "content/browser/site_instance_impl.h"
diff --git a/content/browser/coop_related_group.h b/content/browser/security/coop/coop_related_group.h
similarity index 97%
rename from content/browser/coop_related_group.h
rename to content/browser/security/coop/coop_related_group.h
index 2c29190a..df9df99 100644
--- a/content/browser/coop_related_group.h
+++ b/content/browser/security/coop/coop_related_group.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 CONTENT_BROWSER_COOP_RELATED_GROUP_H_
-#define CONTENT_BROWSER_COOP_RELATED_GROUP_H_
+#ifndef CONTENT_BROWSER_SECURITY_COOP_COOP_RELATED_GROUP_H_
+#define CONTENT_BROWSER_SECURITY_COOP_COOP_RELATED_GROUP_H_
 
 #include <optional>
 #include <vector>
@@ -171,4 +171,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_COOP_RELATED_GROUP_H_;
+#endif  // CONTENT_BROWSER_SECURITY_COOP_COOP_RELATED_GROUP_H_;
diff --git a/content/browser/renderer_host/coop_swap_result.h b/content/browser/security/coop/coop_swap_result.h
similarity index 81%
rename from content/browser/renderer_host/coop_swap_result.h
rename to content/browser/security/coop/coop_swap_result.h
index df4eb1694..49399f5f 100644
--- a/content/browser/renderer_host/coop_swap_result.h
+++ b/content/browser/security/coop/coop_swap_result.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 CONTENT_BROWSER_RENDERER_HOST_COOP_SWAP_RESULT_H_
-#define CONTENT_BROWSER_RENDERER_HOST_COOP_SWAP_RESULT_H_
+#ifndef CONTENT_BROWSER_SECURITY_COOP_COOP_SWAP_RESULT_H_
+#define CONTENT_BROWSER_SECURITY_COOP_COOP_SWAP_RESULT_H_
 
 namespace content {
 
@@ -24,4 +24,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_RENDERER_HOST_COOP_SWAP_RESULT_H_
+#endif  // CONTENT_BROWSER_SECURITY_COOP_COOP_SWAP_RESULT_H_
diff --git a/content/browser/renderer_host/cross_origin_opener_policy_access_report_manager.cc b/content/browser/security/coop/cross_origin_opener_policy_access_report_manager.cc
similarity index 98%
rename from content/browser/renderer_host/cross_origin_opener_policy_access_report_manager.cc
rename to content/browser/security/coop/cross_origin_opener_policy_access_report_manager.cc
index 1473c494..2888d749 100644
--- a/content/browser/renderer_host/cross_origin_opener_policy_access_report_manager.cc
+++ b/content/browser/security/coop/cross_origin_opener_policy_access_report_manager.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/renderer_host/cross_origin_opener_policy_access_report_manager.h"
+#include "content/browser/security/coop/cross_origin_opener_policy_access_report_manager.h"
 
 #include <utility>
 
diff --git a/content/browser/renderer_host/cross_origin_opener_policy_access_report_manager.h b/content/browser/security/coop/cross_origin_opener_policy_access_report_manager.h
similarity index 89%
rename from content/browser/renderer_host/cross_origin_opener_policy_access_report_manager.h
rename to content/browser/security/coop/cross_origin_opener_policy_access_report_manager.h
index c625b20..900342fc 100644
--- a/content/browser/renderer_host/cross_origin_opener_policy_access_report_manager.h
+++ b/content/browser/security/coop/cross_origin_opener_policy_access_report_manager.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_RENDERER_HOST_CROSS_ORIGIN_OPENER_POLICY_ACCESS_REPORT_MANAGER_H_
-#define CONTENT_BROWSER_RENDERER_HOST_CROSS_ORIGIN_OPENER_POLICY_ACCESS_REPORT_MANAGER_H_
+#ifndef CONTENT_BROWSER_SECURITY_COOP_CROSS_ORIGIN_OPENER_POLICY_ACCESS_REPORT_MANAGER_H_
+#define CONTENT_BROWSER_SECURITY_COOP_CROSS_ORIGIN_OPENER_POLICY_ACCESS_REPORT_MANAGER_H_
 
 #include <string>
 
 #include "base/values.h"
-#include "content/browser/network/cross_origin_opener_policy_reporter.h"
-#include "content/browser/renderer_host/coop_swap_result.h"
+#include "content/browser/security/coop/cross_origin_opener_policy_reporter.h"
+#include "content/browser/security/coop/coop_swap_result.h"
 
 namespace content {
 
@@ -73,4 +73,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_RENDERER_HOST_CROSS_ORIGIN_OPENER_POLICY_ACCESS_REPORT_MANAGER_H_
+#endif  // CONTENT_BROWSER_SECURITY_COOP_CROSS_ORIGIN_OPENER_POLICY_ACCESS_REPORT_MANAGER_H_
diff --git a/content/browser/cross_origin_opener_policy_browsertest.cc b/content/browser/security/coop/cross_origin_opener_policy_browsertest.cc
similarity index 100%
rename from content/browser/cross_origin_opener_policy_browsertest.cc
rename to content/browser/security/coop/cross_origin_opener_policy_browsertest.cc
diff --git a/content/browser/network/cross_origin_opener_policy_reporter.cc b/content/browser/security/coop/cross_origin_opener_policy_reporter.cc
similarity index 98%
rename from content/browser/network/cross_origin_opener_policy_reporter.cc
rename to content/browser/security/coop/cross_origin_opener_policy_reporter.cc
index d1d2654..7434e590 100644
--- a/content/browser/network/cross_origin_opener_policy_reporter.cc
+++ b/content/browser/security/coop/cross_origin_opener_policy_reporter.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/network/cross_origin_opener_policy_reporter.h"
+#include "content/browser/security/coop/cross_origin_opener_policy_reporter.h"
 
 #include "base/memory/raw_ptr.h"
 #include "base/values.h"
diff --git a/content/browser/network/cross_origin_opener_policy_reporter.h b/content/browser/security/coop/cross_origin_opener_policy_reporter.h
similarity index 94%
rename from content/browser/network/cross_origin_opener_policy_reporter.h
rename to content/browser/security/coop/cross_origin_opener_policy_reporter.h
index a1525e80..35d8ced9 100644
--- a/content/browser/network/cross_origin_opener_policy_reporter.h
+++ b/content/browser/security/coop/cross_origin_opener_policy_reporter.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 CONTENT_BROWSER_NETWORK_CROSS_ORIGIN_OPENER_POLICY_REPORTER_H_
-#define CONTENT_BROWSER_NETWORK_CROSS_ORIGIN_OPENER_POLICY_REPORTER_H_
+#ifndef CONTENT_BROWSER_SECURITY_COOP_CROSS_ORIGIN_OPENER_POLICY_REPORTER_H_
+#define CONTENT_BROWSER_SECURITY_COOP_CROSS_ORIGIN_OPENER_POLICY_REPORTER_H_
 
 #include <string>
 
@@ -97,4 +97,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_NETWORK_CROSS_ORIGIN_OPENER_POLICY_REPORTER_H_
+#endif  // CONTENT_BROWSER_SECURITY_COOP_CROSS_ORIGIN_OPENER_POLICY_REPORTER_H_
diff --git a/content/browser/network/cross_origin_opener_policy_reporter_unittest.cc b/content/browser/security/coop/cross_origin_opener_policy_reporter_unittest.cc
similarity index 98%
rename from content/browser/network/cross_origin_opener_policy_reporter_unittest.cc
rename to content/browser/security/coop/cross_origin_opener_policy_reporter_unittest.cc
index 40aaebf..3f4012d 100644
--- a/content/browser/network/cross_origin_opener_policy_reporter_unittest.cc
+++ b/content/browser/security/coop/cross_origin_opener_policy_reporter_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/network/cross_origin_opener_policy_reporter.h"
+#include "content/browser/security/coop/cross_origin_opener_policy_reporter.h"
 
 #include <memory>
 #include <optional>
diff --git a/content/browser/network/cross_origin_opener_policy_reporting_browsertest.cc b/content/browser/security/coop/cross_origin_opener_policy_reporting_browsertest.cc
similarity index 100%
rename from content/browser/network/cross_origin_opener_policy_reporting_browsertest.cc
rename to content/browser/security/coop/cross_origin_opener_policy_reporting_browsertest.cc
diff --git a/content/browser/renderer_host/cross_origin_opener_policy_status.cc b/content/browser/security/coop/cross_origin_opener_policy_status.cc
similarity index 99%
rename from content/browser/renderer_host/cross_origin_opener_policy_status.cc
rename to content/browser/security/coop/cross_origin_opener_policy_status.cc
index 628fe9b..c0644d8 100644
--- a/content/browser/renderer_host/cross_origin_opener_policy_status.cc
+++ b/content/browser/security/coop/cross_origin_opener_policy_status.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/renderer_host/cross_origin_opener_policy_status.h"
+#include "content/browser/security/coop/cross_origin_opener_policy_status.h"
 
 #include <utility>
 
 #include "base/feature_list.h"
 #include "base/time/time.h"
-#include "content/browser/renderer_host/cross_origin_opener_policy_access_report_manager.h"
 #include "content/browser/renderer_host/frame_tree_node.h"
 #include "content/browser/renderer_host/navigation_request.h"
 #include "content/browser/renderer_host/render_frame_host_delegate.h"
+#include "content/browser/security/coop/cross_origin_opener_policy_access_report_manager.h"
 #include "services/network/public/cpp/cross_origin_opener_policy.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
diff --git a/content/browser/renderer_host/cross_origin_opener_policy_status.h b/content/browser/security/coop/cross_origin_opener_policy_status.h
similarity index 96%
rename from content/browser/renderer_host/cross_origin_opener_policy_status.h
rename to content/browser/security/coop/cross_origin_opener_policy_status.h
index 4b6c1bb..bee7c10 100644
--- a/content/browser/renderer_host/cross_origin_opener_policy_status.h
+++ b/content/browser/security/coop/cross_origin_opener_policy_status.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_RENDERER_HOST_CROSS_ORIGIN_OPENER_POLICY_STATUS_H_
-#define CONTENT_BROWSER_RENDERER_HOST_CROSS_ORIGIN_OPENER_POLICY_STATUS_H_
+#ifndef CONTENT_BROWSER_SECURITY_COOP_CROSS_ORIGIN_OPENER_POLICY_STATUS_H_
+#define CONTENT_BROWSER_SECURITY_COOP_CROSS_ORIGIN_OPENER_POLICY_STATUS_H_
 
 #include <memory>
 #include <optional>
 
 #include "base/memory/raw_ptr.h"
 #include "base/scoped_observation.h"
-#include "content/browser/renderer_host/coop_swap_result.h"
+#include "content/browser/security/coop/coop_swap_result.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_process_host_observer.h"
 #include "services/network/public/cpp/cross_origin_opener_policy.h"
@@ -196,4 +196,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_RENDERER_HOST_CROSS_ORIGIN_OPENER_POLICY_STATUS_H_
+#endif  // CONTENT_BROWSER_SECURITY_COOP_CROSS_ORIGIN_OPENER_POLICY_STATUS_H_
diff --git a/content/browser/renderer_host/cross_origin_opener_policy_status_unittest.cc b/content/browser/security/coop/cross_origin_opener_policy_status_unittest.cc
similarity index 98%
rename from content/browser/renderer_host/cross_origin_opener_policy_status_unittest.cc
rename to content/browser/security/coop/cross_origin_opener_policy_status_unittest.cc
index 84e63f74..a9cbba9 100644
--- a/content/browser/renderer_host/cross_origin_opener_policy_status_unittest.cc
+++ b/content/browser/security/coop/cross_origin_opener_policy_status_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/renderer_host/cross_origin_opener_policy_status.h"
+#include "content/browser/security/coop/cross_origin_opener_policy_status.h"
 
 #include "base/test/scoped_feature_list.h"
 #include "services/network/public/cpp/features.h"
diff --git a/content/browser/site_instance_group.h b/content/browser/site_instance_group.h
index 1df9ee4..9e0423c 100644
--- a/content/browser/site_instance_group.h
+++ b/content/browser/site_instance_group.h
@@ -13,8 +13,8 @@
 #include "base/types/id_type.h"
 #include "base/unguessable_token.h"
 #include "content/browser/browsing_instance.h"
-#include "content/browser/coop_related_group.h"
 #include "content/browser/renderer_host/agent_scheduling_group_host.h"
+#include "content/browser/security/coop/coop_related_group.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/browsing_instance_id.h"
 #include "content/public/browser/render_process_host_observer.h"
diff --git a/content/browser/site_instance_impl.h b/content/browser/site_instance_impl.h
index bbdc0644..3652182 100644
--- a/content/browser/site_instance_impl.h
+++ b/content/browser/site_instance_impl.h
@@ -11,8 +11,8 @@
 #include "base/check.h"
 #include "base/memory/scoped_refptr.h"
 #include "content/browser/browsing_instance.h"
-#include "content/browser/coop_related_group.h"
 #include "content/browser/isolation_context.h"
+#include "content/browser/security/coop/coop_related_group.h"
 #include "content/browser/site_info.h"
 #include "content/browser/web_exposed_isolation_info.h"
 #include "content/common/content_export.h"
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 7d3933c4..f46f1ca 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -5118,7 +5118,7 @@
 }
 
 void WebContentsImpl::AccessibilityEventReceived(
-    const ui::AXEventNotificationDetails& details) {
+    const ui::AXUpdatesAndEvents& details) {
   OPTIONAL_TRACE_EVENT0("content",
                         "WebContentsImpl::AccessibilityEventReceived");
   observers_.NotifyObservers(&WebContentsObserver::AccessibilityEventReceived,
@@ -5126,7 +5126,7 @@
 }
 
 void WebContentsImpl::AccessibilityLocationChangesReceived(
-    const std::vector<ui::AXLocationChangeNotificationDetails>& details) {
+    const std::vector<ui::AXLocationChanges>& details) {
   OPTIONAL_TRACE_EVENT0(
       "content", "WebContentsImpl::AccessibilityLocationChangesReceived");
   observers_.NotifyObservers(
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index c0ced4f..b2cb33e5 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -116,7 +116,7 @@
 }  // namespace service_manager
 
 namespace ui {
-struct AXEventNotificationDetails;
+struct AXUpdatesAndEvents;
 }
 
 namespace content {
@@ -680,10 +680,9 @@
   void ResetAccessibility() override;
   void AXTreeIDForMainFrameHasChanged() override;
   void AccessibilityEventReceived(
-      const ui::AXEventNotificationDetails& details) override;
+      const ui::AXUpdatesAndEvents& details) override;
   void AccessibilityLocationChangesReceived(
-      const std::vector<ui::AXLocationChangeNotificationDetails>& details)
-      override;
+      const std::vector<ui::AXLocationChanges>& details) override;
   ui::AXNode* GetAccessibilityRootNode() override;
   std::string DumpAccessibilityTree(
       bool internal,
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc
index a4e8452..9fd8827 100644
--- a/content/browser/webid/federated_auth_request_impl.cc
+++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -671,7 +671,7 @@
   // idp_get_params_ptrs should never be empty since it is the renderer-side
   // code which populates it.
   if (idp_get_params_ptrs.empty()) {
-    mojo::ReportBadMessage("idp_get_params_ptrs is empty.");
+    ReportBadMessageAndDeleteThis("idp_get_params_ptrs is empty.");
     return;
   }
   // This could only happen with a compromised renderer process. We ensure that
@@ -679,13 +679,13 @@
   // parsing |IdentityCredentialRequestOptions|.
   for (auto& idp_get_params_ptr : idp_get_params_ptrs) {
     if (idp_get_params_ptr->providers.size() == 0) {
-      mojo::ReportBadMessage("The provider list should not be empty.");
+      ReportBadMessageAndDeleteThis("The provider list should not be empty.");
       return;
     }
   }
 
   if (render_frame_host().IsNestedWithinFencedFrame()) {
-    mojo::ReportBadMessage(
+    ReportBadMessageAndDeleteThis(
         "FedCM should not be allowed in fenced frame trees.");
     return;
   }
@@ -940,7 +940,7 @@
           // ButtonMode enabled (which controls the JS WebIDL), so we crash
           // here if we ever get to this situation.
           if (!IsFedCmButtonModeEnabled()) {
-            mojo::ReportBadMessage("FedCM button mode is not enabled.");
+            ReportBadMessageAndDeleteThis("FedCM button mode is not enabled.");
             return;
           }
           // We fail sooner before, but just to double check, we assert that
@@ -1010,7 +1010,7 @@
     blink::mojom::IdentityProviderConfigPtr provider,
     RequestUserInfoCallback callback) {
   if (!render_frame_host().GetPage().IsPrimary()) {
-    mojo::ReportBadMessage(
+    ReportBadMessageAndDeleteThis(
         "FedCM should not be allowed in nested frame trees.");
     return;
   }
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 3161cd58b..0de10e2 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -156,7 +156,7 @@
   using FeatureList = base::FeatureList;
   const bool feature_enabled = FeatureList::IsEnabled(chromium_feature);
   const bool is_overridden =
-      FeatureList::GetInstance()->IsFeatureOverridden(chromium_feature.name);
+      FeatureList::GetStateIfOverridden(chromium_feature).has_value();
   switch (option) {
     case kSetOnlyIfOverridden:
       if (is_overridden) {
diff --git a/content/public/browser/child_process_host.h b/content/public/browser/child_process_host.h
index cbd1bfc..468e4e62 100644
--- a/content/public/browser/child_process_host.h
+++ b/content/public/browser/child_process_host.h
@@ -80,6 +80,18 @@
       ChildProcessHostDelegate* delegate,
       IpcMode ipc_mode);
 
+  // Returns a unique ID to identify a child process. Used by both child
+  // processes that are derived from ChildProcessHost, but also used to generate
+  // IDs for RenderProcessHost as well as embedded specific child processes.
+  // This ensures that IDs are unique for all different types of child
+  // processes.
+  //
+  // This function is threadsafe since RenderProcessHost is on the UI thread,
+  // but normally this will be used on the IO thread.
+  //
+  // This will never return kInvalidUniqueID.
+  static int GenerateChildProcessUniqueId();
+
   // These flags may be passed to GetChildPath in order to alter its behavior,
   // causing it to return a child path more suited to a specific task.
   enum {
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h
index 47ddc31..f21a4be 100644
--- a/content/public/browser/web_contents_observer.h
+++ b/content/public/browser/web_contents_observer.h
@@ -49,8 +49,8 @@
 }  // namespace gfx
 
 namespace ui {
-struct AXEventNotificationDetails;
-struct AXLocationChangeNotificationDetails;
+struct AXUpdatesAndEvents;
+struct AXLocationChanges;
 namespace mojom {
 enum class VirtualKeyboardMode;
 }  // namespace mojom
@@ -770,9 +770,9 @@
   // from a render frame, but only when the accessibility mode has the
   // ui::AXMode::kWebContents flag set.
   virtual void AccessibilityEventReceived(
-      const ui::AXEventNotificationDetails& details) {}
+      const ui::AXUpdatesAndEvents& details) {}
   virtual void AccessibilityLocationChangesReceived(
-      const std::vector<ui::AXLocationChangeNotificationDetails>& details) {}
+      const std::vector<ui::AXLocationChanges>& details) {}
 
   // Invoked when theme color is changed.
   virtual void DidChangeThemeColor() {}
diff --git a/content/public/test/mock_web_contents_observer.h b/content/public/test/mock_web_contents_observer.h
index 272932c71..cd7577c 100644
--- a/content/public/test/mock_web_contents_observer.h
+++ b/content/public/test/mock_web_contents_observer.h
@@ -7,7 +7,7 @@
 
 #include "content/public/browser/web_contents_observer.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "ui/accessibility/ax_event_notification_details.h"
+#include "ui/accessibility/ax_updates_and_events.h"
 
 namespace content {
 
@@ -257,13 +257,12 @@
   MOCK_METHOD(void, AXTreeIDForMainFrameHasChanged, (), (override));
   MOCK_METHOD(void,
               AccessibilityEventReceived,
-              (const ui::AXEventNotificationDetails& details),
+              (const ui::AXUpdatesAndEvents& details),
               (override));
-  MOCK_METHOD(
-      void,
-      AccessibilityLocationChangesReceived,
-      (const std::vector<ui::AXLocationChangeNotificationDetails>& details),
-      (override));
+  MOCK_METHOD(void,
+              AccessibilityLocationChangesReceived,
+              (const std::vector<ui::AXLocationChanges>& details),
+              (override));
   MOCK_METHOD(void, DidChangeThemeColor, (), (override));
   MOCK_METHOD(void, OnBackgroundColorChanged, (), (override));
   MOCK_METHOD(void,
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 7143a913..7b00405f 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1393,7 +1393,6 @@
     "../browser/content_index/content_index_browsertest.cc",
     "../browser/content_security_policy_browsertest.cc",
     "../browser/cookie_deprecation_label/cookie_deprecation_label_browsertest.cc",
-    "../browser/cross_origin_opener_policy_browsertest.cc",
     "../browser/cross_site_transfer_browsertest.cc",
     "../browser/data_decoder_browsertest.cc",
     "../browser/database_browsertest.cc",
@@ -1577,6 +1576,7 @@
     "../browser/resource_loading_browsertest.cc",
     "../browser/screen_details/screen_details_browsertest.cc",
     "../browser/screen_orientation/screen_orientation_browsertest.cc",
+    "../browser/security/coop/cross_origin_opener_policy_browsertest.cc",
     "../browser/security_exploit_browsertest.cc",
     "../browser/service_process_host_browsertest.cc",
     "../browser/service_worker/service_worker_auth_browsertest.cc",
@@ -1703,9 +1703,7 @@
   }
 
   if (enable_reporting) {
-    sources += [
-      "../browser/network/cross_origin_opener_policy_reporting_browsertest.cc",
-    ]
+    sources += [ "../browser/security/coop/cross_origin_opener_policy_reporting_browsertest.cc" ]
   }
 
   if (use_viz_debugger) {
@@ -2540,7 +2538,6 @@
     "../browser/mojo_binder_policy_applier_unittest.cc",
     "../browser/mojo_binder_policy_map_impl_unittest.cc",
     "../browser/network/cross_origin_embedder_policy_reporter_unittest.cc",
-    "../browser/network/cross_origin_opener_policy_reporter_unittest.cc",
     "../browser/network/network_quality_observer_impl_unittest.cc",
     "../browser/network/socket_broker_impl_unittest.cc",
     "../browser/network_context_client_base_impl_unittest.cc",
@@ -2608,7 +2605,6 @@
     "../browser/renderer_host/browsing_context_group_swap_unittest.cc",
     "../browser/renderer_host/clipboard_host_impl_unittest.cc",
     "../browser/renderer_host/commit_deferring_condition_runner_unittest.cc",
-    "../browser/renderer_host/cross_origin_opener_policy_status_unittest.cc",
     "../browser/renderer_host/cursor_manager_unittest.cc",
     "../browser/renderer_host/display_feature_unittest.cc",
     "../browser/renderer_host/document_service_unittest.cc",
@@ -2684,6 +2680,8 @@
     "../browser/scheduler/responsiveness/watcher_unittest.cc",
     "../browser/screen_orientation/screen_orientation_provider_unittest.cc",
     "../browser/screenlock_monitor/screenlock_monitor_unittest.cc",
+    "../browser/security/coop/cross_origin_opener_policy_reporter_unittest.cc",
+    "../browser/security/coop/cross_origin_opener_policy_status_unittest.cc",
     "../browser/service_worker/embedded_worker_instance_unittest.cc",
     "../browser/service_worker/service_worker_cache_writer_unittest.cc",
     "../browser/service_worker/service_worker_container_host_unittest.cc",
diff --git a/content/test/fuzzer/browser_accessibility_fuzzer.cc b/content/test/fuzzer/browser_accessibility_fuzzer.cc
index a39f35f..c0f721b7 100644
--- a/content/test/fuzzer/browser_accessibility_fuzzer.cc
+++ b/content/test/fuzzer/browser_accessibility_fuzzer.cc
@@ -200,7 +200,7 @@
   update.nodes[1].role = GetInterestingRole(fdp);
   AddStates(fdp, &update.nodes[1]);
 
-  ui::AXEventNotificationDetails notification;
+  ui::AXUpdatesAndEvents notification;
   notification.updates.resize(1);
   notification.updates[0] = update;
 
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index 2c03f52..2da3a40 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -1005,30 +1005,30 @@
 crbug.com/332743717 conformance/uniforms/uniform-location.html [ Failure ]
 crbug.com/332743717 [ android android-pixel-4 ] conformance2/canvas/drawingbuffer-storage-test.html [ Failure ]
 crbug.com/332743717 [ linux ] conformance2/canvas/drawingbuffer-storage-test.html [ Failure ]
-crbug.com/332743717 [ android android-pixel-4 ] conformance2/wasm/bufferdata-16gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ android android-pixel-4 ] conformance2/wasm/bufferdata-4gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ android android-pixel-4 ] conformance2/wasm/buffersubdata-16gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ android android-pixel-4 ] conformance2/wasm/buffersubdata-4gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ android android-pixel-4 ] conformance2/wasm/getbuffersubdata-16gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ android android-pixel-4 ] conformance2/wasm/getbuffersubdata-4gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ android android-pixel-4 ] conformance2/wasm/readpixels-16gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ android android-pixel-4 ] conformance2/wasm/readpixels-4gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ android android-pixel-4 ] conformance2/wasm/teximage2d-16gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ android android-pixel-4 ] conformance2/wasm/teximage2d-4gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ android android-pixel-4 ] conformance2/wasm/texsubimage2d-16gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ android android-pixel-4 ] conformance2/wasm/texsubimage2d-4gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ linux ] conformance2/wasm/bufferdata-16gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ linux ] conformance2/wasm/buffersubdata-16gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ linux ] conformance2/wasm/getbuffersubdata-16gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ linux ] conformance2/wasm/readpixels-16gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ linux ] conformance2/wasm/teximage2d-16gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ linux ] conformance2/wasm/texsubimage2d-16gb-wasm-memory.html [ Failure ]
-crbug.com/332743717 [ win ] conformance2/wasm/bufferdata-16gb-wasm-memory.html [ RetryOnFailure ]
-crbug.com/332743717 [ win ] conformance2/wasm/buffersubdata-16gb-wasm-memory.html [ RetryOnFailure ]
-crbug.com/332743717 [ win ] conformance2/wasm/getbuffersubdata-16gb-wasm-memory.html [ RetryOnFailure ]
-crbug.com/332743717 [ win ] conformance2/wasm/readpixels-16gb-wasm-memory.html [ RetryOnFailure ]
-crbug.com/332743717 [ win ] conformance2/wasm/teximage2d-16gb-wasm-memory.html [ RetryOnFailure ]
-crbug.com/332743717 [ win ] conformance2/wasm/texsubimage2d-16gb-wasm-memory.html [ RetryOnFailure ]
+crbug.com/335203259 [ android android-pixel-4 ] conformance2/wasm/bufferdata-16gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ android android-pixel-4 ] conformance2/wasm/bufferdata-4gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ android android-pixel-4 ] conformance2/wasm/buffersubdata-16gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ android android-pixel-4 ] conformance2/wasm/buffersubdata-4gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ android android-pixel-4 ] conformance2/wasm/getbuffersubdata-16gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ android android-pixel-4 ] conformance2/wasm/getbuffersubdata-4gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ android android-pixel-4 ] conformance2/wasm/readpixels-16gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ android android-pixel-4 ] conformance2/wasm/readpixels-4gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ android android-pixel-4 ] conformance2/wasm/teximage2d-16gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ android android-pixel-4 ] conformance2/wasm/teximage2d-4gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ android android-pixel-4 ] conformance2/wasm/texsubimage2d-16gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ android android-pixel-4 ] conformance2/wasm/texsubimage2d-4gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ linux ] conformance2/wasm/bufferdata-16gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ linux ] conformance2/wasm/buffersubdata-16gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ linux ] conformance2/wasm/getbuffersubdata-16gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ linux ] conformance2/wasm/readpixels-16gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ linux ] conformance2/wasm/teximage2d-16gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ linux ] conformance2/wasm/texsubimage2d-16gb-wasm-memory.html [ Failure ]
+crbug.com/335203259 [ win ] conformance2/wasm/bufferdata-16gb-wasm-memory.html [ RetryOnFailure ]
+crbug.com/335203259 [ win ] conformance2/wasm/buffersubdata-16gb-wasm-memory.html [ RetryOnFailure ]
+crbug.com/335203259 [ win ] conformance2/wasm/getbuffersubdata-16gb-wasm-memory.html [ RetryOnFailure ]
+crbug.com/335203259 [ win ] conformance2/wasm/readpixels-16gb-wasm-memory.html [ RetryOnFailure ]
+crbug.com/335203259 [ win ] conformance2/wasm/teximage2d-16gb-wasm-memory.html [ RetryOnFailure ]
+crbug.com/335203259 [ win ] conformance2/wasm/texsubimage2d-16gb-wasm-memory.html [ RetryOnFailure ]
 crbug.com/332743717 [ mac intel angle-metal ] conformance2/query/occlusion-query-scissor.html [ Failure ]
 
 #################################################################
diff --git a/docs/updater/functional_spec.md b/docs/updater/functional_spec.md
index 74fd731..5a19e6bd 100644
--- a/docs/updater/functional_spec.md
+++ b/docs/updater/functional_spec.md
@@ -820,7 +820,8 @@
 `EnrollmentMandatory` to `1` (Windows only).
 
 After the updater sets itself up, the `FetchPolicies` RPC is invoked on the
-updater server to register with device management and fetch policies.
+updater server to register with device management and fetch policies. Concurrent
+calls of `FetchPolicies` will result in only a single policy fetch.
 
 The updater also checks for policy updates when the `RunPeriodicTasks` RPC is
 invoked at periodic intervals.
@@ -829,12 +830,12 @@
 
 #### Windows
 The enrollment token is searched in the order:
-* The `EnrollmentToken` REG_BINARY value from
+* The `EnrollmentToken` `REG_BINARY` value from
   `HKLM\Software\Policies\{COMPANY_SHORTNAME}\CloudManagement`
-* The `CloudManagementEnrollmentToken` REG_BINARY value from
+* The `CloudManagementEnrollmentToken` `REG_BINARY` value from
   `HKLM\Software\Policies\{COMPANY_SHORTNAME}\{BROWSER_NAME}`
 
-The `EnrollmentMandatory` REG_DWORD value is also read from
+The `EnrollmentMandatory` `REG_DWORD` value is also read from
 `HKLM\Software\Policies\{COMPANY_SHORTNAME}\CloudManagement`.
 
 #### macOS
@@ -1685,6 +1686,12 @@
 *   it leaves a small log file in its data directory.
 *   it leaves the Clients registry key in Windows registry.
 
+Inactive instances of the updater uninstall themselves (but not the updater
+overall) once the active version of the updater is higher than the inactive
+instance's version. Additionally, as part of its periodic tasks, the active
+updater will trigger the uninstallation of old instances of the updater and
+clean up any files they leak.
+
 ## Associated Tools
 
 ### External Constants Overrides
diff --git a/docs/website b/docs/website
index 192b4c1..15de42c 160000
--- a/docs/website
+++ b/docs/website
@@ -1 +1 @@
-Subproject commit 192b4c1fca9c092343459067d75ba65fbc6ea856
+Subproject commit 15de42c1a6ab2c80ad289fb8e61aea8ced48a4b9
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index aac6dfa..a09cc77 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -548,6 +548,8 @@
     "service_worker/worker_id_set.h",
     "service_worker_manager.cc",
     "service_worker_manager.h",
+    "site_access_requests_helper.cc",
+    "site_access_requests_helper.h",
     "state_store.cc",
     "state_store.h",
     "state_store_test_observer.cc",
diff --git a/extensions/browser/api/automation_internal/automation_event_router.cc b/extensions/browser/api/automation_internal/automation_event_router.cc
index ccac38c2..9dbb11ef 100644
--- a/extensions/browser/api/automation_internal/automation_event_router.cc
+++ b/extensions/browser/api/automation_internal/automation_event_router.cc
@@ -96,7 +96,7 @@
 }
 
 void AutomationEventRouter::DispatchAccessibilityLocationChange(
-    const ui::AXLocationChangeNotificationDetails& details) {
+    const ui::AXLocationChanges& details) {
   if (remote_router_) {
     remote_router_->DispatchAccessibilityLocationChange(details);
     return;
diff --git a/extensions/browser/api/automation_internal/automation_event_router.h b/extensions/browser/api/automation_internal/automation_event_router.h
index 04951ad..3df72ae 100644
--- a/extensions/browser/api/automation_internal/automation_event_router.h
+++ b/extensions/browser/api/automation_internal/automation_event_router.h
@@ -27,8 +27,8 @@
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/bindings/remote_set.h"
 #include "services/accessibility/public/mojom/automation.mojom.h"
-#include "ui/accessibility/ax_event_notification_details.h"
 #include "ui/accessibility/ax_tree_id.h"
+#include "ui/accessibility/ax_updates_and_events.h"
 
 namespace content {
 class BrowserContext;
@@ -99,7 +99,7 @@
                                    const gfx::Point& mouse_location,
                                    std::vector<ui::AXEvent> events) override;
   void DispatchAccessibilityLocationChange(
-      const ui::AXLocationChangeNotificationDetails& details) override;
+      const ui::AXLocationChanges& details) override;
   void DispatchTreeDestroyedEvent(ui::AXTreeID tree_id) override;
   void DispatchActionResult(
       const ui::AXActionData& data,
diff --git a/extensions/browser/api/automation_internal/automation_event_router_interface.h b/extensions/browser/api/automation_internal/automation_event_router_interface.h
index bf0286b..46c28c8 100644
--- a/extensions/browser/api/automation_internal/automation_event_router_interface.h
+++ b/extensions/browser/api/automation_internal/automation_event_router_interface.h
@@ -11,7 +11,7 @@
 
 #include "extensions/common/api/automation_internal.h"
 #include "extensions/common/extension_id.h"
-#include "ui/accessibility/ax_event_notification_details.h"
+#include "ui/accessibility/ax_updates_and_events.h"
 
 namespace content {
 class BrowserContext;
@@ -31,7 +31,7 @@
       const gfx::Point& mouse_location,
       std::vector<ui::AXEvent> events) = 0;
   virtual void DispatchAccessibilityLocationChange(
-      const ui::AXLocationChangeNotificationDetails& details) = 0;
+      const ui::AXLocationChanges& details) = 0;
 
   // Notify all automation extensions that an accessibility tree was
   // destroyed. If |browser_context| is null, use the currently active context.
diff --git a/extensions/browser/api/automation_internal/automation_internal_api.cc b/extensions/browser/api/automation_internal/automation_internal_api.cc
index c028cfa..f2a781b 100644
--- a/extensions/browser/api/automation_internal/automation_internal_api.cc
+++ b/extensions/browser/api/automation_internal/automation_internal_api.cc
@@ -43,7 +43,7 @@
 #include "ui/accessibility/ax_action_handler_base.h"
 #include "ui/accessibility/ax_action_handler_registry.h"
 #include "ui/accessibility/ax_enum_util.h"
-#include "ui/accessibility/ax_event_notification_details.h"
+#include "ui/accessibility/ax_updates_and_events.h"
 
 #if defined(USE_AURA)
 #include "ui/aura/env.h"
@@ -340,7 +340,7 @@
 
   // content::WebContentsObserver overrides.
   void AccessibilityEventReceived(
-      const ui::AXEventNotificationDetails& content_event_bundle) override {
+      const ui::AXUpdatesAndEvents& content_event_bundle) override {
     gfx::Point mouse_location;
 #if defined(USE_AURA)
     mouse_location = aura::Env::GetInstance()->last_mouse_location();
@@ -353,8 +353,7 @@
   }
 
   void AccessibilityLocationChangesReceived(
-      const std::vector<ui::AXLocationChangeNotificationDetails>& details)
-      override {
+      const std::vector<ui::AXLocationChanges>& details) override {
     AutomationEventRouter* router = AutomationEventRouter::GetInstance();
     for (const auto& src : details) {
       router->DispatchAccessibilityLocationChange(src);
@@ -368,7 +367,7 @@
     if (!render_frame_host)
       return;
 
-    ui::AXEventNotificationDetails content_event_bundle;
+    ui::AXUpdatesAndEvents content_event_bundle;
     content_event_bundle.ax_tree_id = render_frame_host->GetAXTreeID();
     content_event_bundle.events.resize(1);
     content_event_bundle.events[0].event_type =
@@ -385,7 +384,7 @@
     if (!render_frame_host)
       return;
 
-    ui::AXEventNotificationDetails content_event_bundle;
+    ui::AXUpdatesAndEvents content_event_bundle;
     content_event_bundle.ax_tree_id = render_frame_host->GetAXTreeID();
     content_event_bundle.events.resize(1);
     content_event_bundle.events[0].event_type =
@@ -453,7 +452,7 @@
         return;
       }
 
-      ui::AXEventNotificationDetails content_event_bundle;
+      ui::AXUpdatesAndEvents content_event_bundle;
       content_event_bundle.ax_tree_id = render_frame_host->GetAXTreeID();
       content_event_bundle.events.resize(1);
       content_event_bundle.events[0].event_type =
diff --git a/extensions/browser/permissions_manager.cc b/extensions/browser/permissions_manager.cc
index e184adc..707c6079 100644
--- a/extensions/browser/permissions_manager.cc
+++ b/extensions/browser/permissions_manager.cc
@@ -21,6 +21,7 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_factory.h"
@@ -30,6 +31,7 @@
 #include "extensions/browser/pref_names.h"
 #include "extensions/browser/pref_types.h"
 #include "extensions/browser/renderer_startup_helper.h"
+#include "extensions/browser/site_access_requests_helper.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_features.h"
 #include "extensions/common/manifest_handlers/permissions_parser.h"
@@ -213,6 +215,7 @@
 PermissionsManager::~PermissionsManager() {
   user_permissions_.restricted_sites.clear();
   user_permissions_.permitted_sites.clear();
+  requests_helpers_.clear();
 }
 
 // static
@@ -780,6 +783,36 @@
              : extension_prefs_->GetGrantedPermissions(extension.id());
 }
 
+void PermissionsManager::AddSiteAccessRequest(
+    content::WebContents* web_contents,
+    int tab_id,
+    const Extension& extension) {
+  SiteAccessRequestsHelper* helper =
+      GetOrCreateSiteAccessRequestsHelperFor(web_contents, tab_id);
+  helper->AddRequest(extension);
+}
+
+void PermissionsManager::RemoveSiteAccessRequest(
+    int tab_id,
+    const ExtensionId& extension_id) {
+  SiteAccessRequestsHelper* helper = GetSiteAccessRequestsHelperFor(tab_id);
+  if (!helper) {
+    return;
+  }
+
+  helper->RemoveRequest(extension_id);
+
+  if (!helper->HasRequests()) {
+    DeleteSiteAccessRequestHelperFor(tab_id);
+  }
+}
+
+bool PermissionsManager::HasSiteAccessRequest(int tab_id,
+                                              const ExtensionId& extension_id) {
+  SiteAccessRequestsHelper* helper = GetSiteAccessRequestsHelperFor(tab_id);
+  return helper && helper->HasRequest(extension_id);
+}
+
 void PermissionsManager::AddExtensionToPreviousBroadSiteAccessSet(
     const ExtensionId& extension_id) {
   extensions_with_previous_broad_access_.insert(extension_id);
@@ -802,13 +835,29 @@
   for (Observer& observer : observers_) {
     observer.OnExtensionPermissionsUpdated(extension, permissions, reason);
   }
+
+  std::vector<int> tabs_to_remove;
+  for (auto& [tab_id, helper] : requests_helpers_) {
+    helper->RemoveRequestIfGrantedAccess(extension);
+    if (!helper->HasRequests()) {
+      tabs_to_remove.push_back(tab_id);
+    }
+  }
+
+  for (auto tab_id : tabs_to_remove) {
+    DeleteSiteAccessRequestHelperFor(tab_id);
+  }
 }
 
 void PermissionsManager::NotifyActiveTabPermisssionGranted(
+    content::WebContents* web_contents,
+    int tab_id,
     const Extension& extension) {
   for (Observer& observer : observers_) {
     observer.OnActiveTabPermissionGranted(extension);
   }
+
+  RemoveSiteAccessRequest(tab_id, extension.id());
 }
 
 void PermissionsManager::NotifyExtensionDismissedRequests(
@@ -919,6 +968,32 @@
   return removed_site;
 }
 
+SiteAccessRequestsHelper* PermissionsManager::GetSiteAccessRequestsHelperFor(
+    int tab_id) {
+  auto it = requests_helpers_.find(tab_id);
+  return it == requests_helpers_.end() ? nullptr : it->second.get();
+}
+
+SiteAccessRequestsHelper*
+PermissionsManager::GetOrCreateSiteAccessRequestsHelperFor(
+    content::WebContents* web_contents,
+    int tab_id) {
+  auto* helper = GetSiteAccessRequestsHelperFor(tab_id);
+
+  if (!helper) {
+    auto helper_unique = std::make_unique<SiteAccessRequestsHelper>(
+        PassKey(), this, web_contents, tab_id);
+    helper = helper_unique.get();
+    requests_helpers_.emplace(tab_id, std::move(helper_unique));
+  }
+
+  return helper;
+}
+
+void PermissionsManager::DeleteSiteAccessRequestHelperFor(int tab_id) {
+  requests_helpers_.erase(tab_id);
+}
+
 void PermissionsManager::NotifyUserPermissionSettingsChanged() {
   for (auto& observer : observers_) {
     observer.OnUserPermissionsSettingsChanged(GetUserPermissionsSettings());
diff --git a/extensions/browser/permissions_manager.h b/extensions/browser/permissions_manager.h
index 0ed0050..247b7b1 100644
--- a/extensions/browser/permissions_manager.h
+++ b/extensions/browser/permissions_manager.h
@@ -5,6 +5,7 @@
 #ifndef EXTENSIONS_BROWSER_PERMISSIONS_MANAGER_H_
 #define EXTENSIONS_BROWSER_PERMISSIONS_MANAGER_H_
 
+#include <map>
 #include <set>
 
 #include "base/memory/raw_ptr.h"
@@ -12,6 +13,8 @@
 #include "base/observer_list.h"
 #include "base/types/pass_key.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/browser/site_access_requests_helper.h"
 #include "extensions/common/extension_id.h"
 #include "url/origin.h"
 
@@ -268,6 +271,18 @@
   std::unique_ptr<const PermissionSet> GetExtensionGrantedPermissions(
       const Extension& extension) const;
 
+  // Adds site access request for `extension` in `web_contents` with
+  // `tab_id`. Extension must have site access withheld for request to be added.
+  void AddSiteAccessRequest(content::WebContents* web_contents,
+                            int tab_id,
+                            const Extension& extension);
+
+  // Removes site access request for `extension` in `tab_id`, if existent.
+  void RemoveSiteAccessRequest(int tab_id, const ExtensionId& extension);
+
+  // Returns whether `tab_id` has a site access request for `extension_id`.
+  bool HasSiteAccessRequest(int tab_id, const ExtensionId& extension_id);
+
   // Adds `extension_id` to the `extensions_with_previous_broad_access` set.
   void AddExtensionToPreviousBroadSiteAccessSet(
       const ExtensionId& extension_id);
@@ -288,8 +303,10 @@
                                          UpdateReason reason);
 
   // Notifies `observers_` that `extension` has been granted active tab
-  // permission.
-  void NotifyActiveTabPermisssionGranted(const Extension& extension);
+  // permission for `web_contents` on `tab_id`.
+  void NotifyActiveTabPermisssionGranted(content::WebContents* web_contents,
+                                         int tab_id,
+                                         const Extension& extension);
 
   // Notifies `observers_`that show access requests in toolbar pref changed.
   void NotifyShowAccessRequestsInToolbarChanged(
@@ -307,6 +324,9 @@
   void RemoveObserver(Observer* observer);
 
  private:
+  using PassKey = base::PassKey<PermissionsManager>;
+  friend class SiteAccessRequestsHelper;
+
   // Called whenever `user_permissions_` have changed.
   void OnUserPermissionsSettingsChanged();
 
@@ -328,6 +348,20 @@
       const Extension& extension,
       const PermissionSet& user_permitted_set);
 
+  // Returns the site access requests helper for `tab_id` or nullptr if it
+  // doesn't exist.
+  SiteAccessRequestsHelper* GetSiteAccessRequestsHelperFor(int tab_id);
+
+  // Returns the site access requests helper for `tab_id`. If the helper doesn't
+  // exist for such tab, it creates a new one.
+  SiteAccessRequestsHelper* GetOrCreateSiteAccessRequestsHelperFor(
+      content::WebContents* web_contents,
+      int tab_id);
+
+  // Deletes helper corresponding to `tab_id` by removing its entry from
+  // `requests_helper_`.
+  void DeleteSiteAccessRequestHelperFor(int tab_id);
+
   // Notifies `observers_` that user permissions have changed.
   void NotifyUserPermissionSettingsChanged();
 
@@ -339,6 +373,9 @@
   const raw_ptr<ExtensionPrefs> extension_prefs_;
   UserPermissionsSettings user_permissions_;
 
+  // Helpers that store and manage the site access requests per tab.
+  std::map<int, std::unique_ptr<SiteAccessRequestsHelper>> requests_helpers_;
+
   // Stores extensions whose site access was updated using the extensions
   // menu and previously had broad site access. This is done to preserve the
   // previous site access state when toggling on the extension's site access
diff --git a/extensions/browser/renderer_startup_helper.cc b/extensions/browser/renderer_startup_helper.cc
index 9beced49..164bdd3 100644
--- a/extensions/browser/renderer_startup_helper.cc
+++ b/extensions/browser/renderer_startup_helper.cc
@@ -387,6 +387,25 @@
   }
 }
 
+void RendererStartupHelper::ClearUserScriptWorldProperties(
+    const Extension& extension,
+    const std::optional<std::string>& world_id) {
+  for (auto& process_entry : process_mojo_map_) {
+    content::RenderProcessHost* process = process_entry.first;
+    mojom::Renderer* renderer = GetRenderer(process);
+    if (!renderer) {
+      continue;
+    }
+
+    if (!util::IsExtensionVisibleToContext(extension,
+                                           process->GetBrowserContext())) {
+      continue;
+    }
+
+    renderer->ClearUserScriptWorldConfig(extension.id(), world_id);
+  }
+}
+
 mojo::PendingAssociatedRemote<mojom::Renderer>
 RendererStartupHelper::BindNewRendererRemote(
     content::RenderProcessHost* process) {
diff --git a/extensions/browser/renderer_startup_helper.h b/extensions/browser/renderer_startup_helper.h
index b7ad9e7a2..c44f012 100644
--- a/extensions/browser/renderer_startup_helper.h
+++ b/extensions/browser/renderer_startup_helper.h
@@ -106,6 +106,12 @@
                                     std::optional<std::string> csp,
                                     bool enable_messaging);
 
+  // Notifies renderers to clear any properties for the user script world
+  // associated with the given `extension` and `world_id`.
+  void ClearUserScriptWorldProperties(
+      const Extension& extension,
+      const std::optional<std::string>& world_id);
+
   // Returns mojom::Renderer* corresponding to |process|. This would return
   // nullptr when it's called before |process| is inserted to
   // |process_mojo_map_| or after it's deleted. Note that the callers should
diff --git a/extensions/browser/renderer_startup_helper_unittest.cc b/extensions/browser/renderer_startup_helper_unittest.cc
index f8aadd4..dfa759e 100644
--- a/extensions/browser/renderer_startup_helper_unittest.cc
+++ b/extensions/browser/renderer_startup_helper_unittest.cc
@@ -134,6 +134,10 @@
   void UpdateUserScriptWorlds(
       std::vector<mojom::UserScriptWorldInfoPtr> info) override {}
 
+  void ClearUserScriptWorldConfig(
+      const std::string& extension_id,
+      const std::optional<std::string>& world_id) override {}
+
   void ShouldSuspend(ShouldSuspendCallback callback) override {
     std::move(callback).Run();
   }
diff --git a/extensions/browser/site_access_requests_helper.cc b/extensions/browser/site_access_requests_helper.cc
new file mode 100644
index 0000000..450f118
--- /dev/null
+++ b/extensions/browser/site_access_requests_helper.cc
@@ -0,0 +1,108 @@
+// 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 "extensions/browser/site_access_requests_helper.h"
+
+#include <sys/types.h>
+
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/browser/permissions_manager.h"
+#include "extensions/common/extension.h"
+
+namespace extensions {
+
+SiteAccessRequestsHelper::SiteAccessRequestsHelper(
+    PassKey pass_key,
+    PermissionsManager* permissions_manager,
+    content::WebContents* web_contents,
+    int tab_id)
+    : content::WebContentsObserver(web_contents),
+      permissions_manager_(permissions_manager),
+      web_contents_(web_contents),
+      tab_id_(tab_id) {}
+
+SiteAccessRequestsHelper::~SiteAccessRequestsHelper() = default;
+
+void SiteAccessRequestsHelper::AddRequest(const Extension& extension) {
+  // Extension must not have granted access to the current site.
+  auto site_access = permissions_manager_->GetSiteAccess(
+      extension, web_contents_->GetLastCommittedURL());
+  CHECK(!site_access.has_site_access && !site_access.has_all_sites_access);
+
+  requesting_extensions_.insert(extension.id());
+
+  // TODO(crbug.com/330588494): Notify PermissionsManager's observers request
+  // was added.
+}
+
+void SiteAccessRequestsHelper::RemoveRequest(const ExtensionId& extension_id) {
+  requesting_extensions_.erase(extension_id);
+  // TODO(crbug.com/330588494): Remove request from dismissed set, if existent,
+  // once dismissed requests are moved to SiteAccessRequestsHelper.
+
+  // TODO(crbug.com/330588494): Notify PermissionsManager's observer request was
+  // removed.
+}
+
+void SiteAccessRequestsHelper::RemoveRequestIfGrantedAccess(
+    const Extension& extension) {
+  // Request is removed iff extension has access to the current site.
+  const GURL& url = web_contents_->GetLastCommittedURL();
+  PermissionsManager::ExtensionSiteAccess site_access =
+      permissions_manager_->GetSiteAccess(extension, url);
+  if (!site_access.has_site_access && !site_access.has_all_sites_access &&
+      !permissions_manager_->HasActiveTabAndCanAccess(extension, url)) {
+    return;
+  }
+
+  RemoveRequest(extension.id());
+}
+
+bool SiteAccessRequestsHelper::HasRequest(const ExtensionId& extension_id) {
+  return requesting_extensions_.contains(extension_id);
+}
+
+bool SiteAccessRequestsHelper::HasRequests() {
+  return !requesting_extensions_.empty();
+}
+
+void SiteAccessRequestsHelper::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
+  // Sub-frames don't get specific requests.
+  if (!navigation_handle->IsInPrimaryMainFrame() ||
+      !navigation_handle->HasCommitted() ||
+      navigation_handle->IsSameDocument()) {
+    return;
+  }
+
+  // Only clear requests for cross-origin navigations.
+  if (navigation_handle->IsSameOrigin()) {
+    return;
+  }
+
+  requesting_extensions_.clear();
+  // TODO(crbug.com/330588494): Clear dismissed requests once they are moved to
+  // SiteAccessRequestsHelper.
+
+  // TODO(crbug.com/330588494): Notify PermissionsManager's observers requests
+  // were cleared.
+
+  permissions_manager_->DeleteSiteAccessRequestHelperFor(tab_id_);
+  // IMPORTANT: This object is now deleted and is unsafe to use.
+}
+
+void SiteAccessRequestsHelper::WebContentsDestroyed() {
+  // Delete web contents pointer so it's not dangling at helper's destruction.
+  web_contents_ = nullptr;
+
+  requesting_extensions_.clear();
+  // TODO(crbug.com/330588494): Clear dismissed requests once they are moved to
+  // SiteAccessRequestsHelper.
+
+  permissions_manager_->DeleteSiteAccessRequestHelperFor(tab_id_);
+  // IMPORTANT: This object is now deleted and is unsafe to use.
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/site_access_requests_helper.h b/extensions/browser/site_access_requests_helper.h
new file mode 100644
index 0000000..e4f6d1fd
--- /dev/null
+++ b/extensions/browser/site_access_requests_helper.h
@@ -0,0 +1,78 @@
+// 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 EXTENSIONS_BROWSER_SITE_ACCESS_REQUESTS_HELPER_H_
+#define EXTENSIONS_BROWSER_SITE_ACCESS_REQUESTS_HELPER_H_
+
+#include "content/public/browser/web_contents_observer.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+namespace extensions {
+
+class PermissionsManager;
+
+// Per-tab helper that stores extension's site access requests and restores
+// them on cross-origin navigations.
+// This class should only be used by PermissionsManager since it's an
+// implementation detail that was pulled out for legibility.
+class SiteAccessRequestsHelper : public content::WebContentsObserver {
+ public:
+  using PassKey = base::PassKey<PermissionsManager>;
+
+  SiteAccessRequestsHelper(PassKey pass_key,
+                           PermissionsManager* permissions_manager,
+                           content::WebContents* web_contents,
+                           int tab_id);
+  SiteAccessRequestsHelper(const SiteAccessRequestsHelper&) = delete;
+  const SiteAccessRequestsHelper& operator=(const SiteAccessRequestsHelper&) =
+      delete;
+  ~SiteAccessRequestsHelper() override;
+
+  // Adds `extension` to the set of extensions with site access requests.
+  // Extension must not have granted access to the current site.
+  void AddRequest(const Extension& extension);
+
+  // Removes `extension_id` from the set of extensions with site access
+  // requests.
+  void RemoveRequest(const ExtensionId& extension_id);
+
+  // Removes `extension` from the set of extensions with site access requests
+  // iff extension has granted access to the current site.
+  void RemoveRequestIfGrantedAccess(const Extension& extension);
+
+  // Returns whether `extension_id` has a site access request.
+  bool HasRequest(const ExtensionId& extension_id);
+
+  // Returns whether helper has any site access requests.
+  bool HasRequests();
+
+ private:
+  // content::WebContentsObserver:
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override;
+  void WebContentsDestroyed() override;
+
+  // TODO(crbug.com/330588494): Remove site access request, if existent, for
+  // unloaded extension.
+
+  // PermissionsManager owns this object, thus `permissions_manager_` will
+  // always be valid.
+  raw_ptr<PermissionsManager> permissions_manager_;
+  raw_ptr<content::WebContents> web_contents_;
+  int tab_id_;
+
+  // Extensions that have a site access request for this tab's origin.
+  std::set<ExtensionId> requesting_extensions_;
+
+  // TODO(crbug.com/330588494): Moves dismissed extensions from TabHelper.
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_SITE_ACCESS_REQUESTS_HELPER_H_
diff --git a/extensions/browser/user_script_world_configuration_manager.cc b/extensions/browser/user_script_world_configuration_manager.cc
index 05b959d..3a8c3e8 100644
--- a/extensions/browser/user_script_world_configuration_manager.cc
+++ b/extensions/browser/user_script_world_configuration_manager.cc
@@ -127,6 +127,26 @@
                                                  enable_messaging);
 }
 
+void UserScriptWorldConfigurationManager::ClearUserScriptWorldInfo(
+    const Extension& extension,
+    const std::optional<std::string>& world_id) {
+  ExtensionPrefs::ScopedDictionaryUpdate update(
+      extension_prefs_, extension.id(), kUserScriptsWorldsConfiguration.name);
+  std::unique_ptr<prefs::DictionaryValueUpdate> update_dict = update.Get();
+
+  if (!update_dict) {
+    return;  // No configs.
+  }
+
+  std::string_view world_key = GetUserScriptWorldKeyForWorldId(world_id);
+  if (!update_dict->HasKey(world_key)) {
+    return;  // No config for this world ID.
+  }
+
+  update_dict->Remove(world_key);
+  renderer_helper_->ClearUserScriptWorldProperties(extension, world_id);
+}
+
 mojom::UserScriptWorldInfoPtr
 UserScriptWorldConfigurationManager::GetUserScriptWorldInfo(
     const ExtensionId& extension_id,
diff --git a/extensions/browser/user_script_world_configuration_manager.h b/extensions/browser/user_script_world_configuration_manager.h
index 96af801..3a80c22 100644
--- a/extensions/browser/user_script_world_configuration_manager.h
+++ b/extensions/browser/user_script_world_configuration_manager.h
@@ -52,6 +52,12 @@
                               std::optional<std::string> csp,
                               bool enable_messaging);
 
+  // Clears any stored configuration for a user script world indicated by
+  // `world_id`. If `world_id` is omitted, removes the configuration for the
+  // default user script world.
+  void ClearUserScriptWorldInfo(const Extension& extension,
+                                const std::optional<std::string>& world_id);
+
   // Retrieve a configuration for a user script world indicated by `world_id`.
   // If `world_id` is omitted, retrieves the configuration for the default user
   // script world. If there is no registration for the given user script world,
diff --git a/extensions/common/mojom/renderer.mojom b/extensions/common/mojom/renderer.mojom
index 7622cf9..fc9977d 100644
--- a/extensions/common/mojom/renderer.mojom
+++ b/extensions/common/mojom/renderer.mojom
@@ -122,6 +122,11 @@
   // Updates the user script worlds accordiging to `infos`.
   UpdateUserScriptWorlds(array<UserScriptWorldInfo> infos);
 
+  // Clears configurations associated with the given `extension_id` and
+  // `world_id`.
+  ClearUserScriptWorldConfig(string extension_id,
+                             string? world_id);
+
   // Asks the lazy background page if it is ready to be suspended and replies
   // back to the browser. This is sent when the page is considered idle.
   ShouldSuspend() => ();
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index 4e5dbef6..624e23b 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -1058,6 +1058,13 @@
   }
 }
 
+void Dispatcher::ClearUserScriptWorldConfig(
+    const std::string& extension_id,
+    const std::optional<std::string>& world_id) {
+  IsolatedWorldManager::GetInstance().ClearUserScriptWorldProperties(
+      extension_id, world_id);
+}
+
 void Dispatcher::UpdateUserHostRestrictions(URLPatternSet user_blocked_hosts,
                                             URLPatternSet user_allowed_hosts) {
   PermissionsData::SetUserHostRestrictions(kRendererProfileId,
diff --git a/extensions/renderer/dispatcher.h b/extensions/renderer/dispatcher.h
index 60e746e..1800419b 100644
--- a/extensions/renderer/dispatcher.h
+++ b/extensions/renderer/dispatcher.h
@@ -235,6 +235,9 @@
       const std::vector<ExtensionId>& extension_ids) override;
   void UpdateUserScriptWorlds(
       std::vector<mojom::UserScriptWorldInfoPtr> infos) override;
+  void ClearUserScriptWorldConfig(
+      const std::string& extension_id,
+      const std::optional<std::string>& world_id) override;
   void ShouldSuspend(ShouldSuspendCallback callback) override;
   void TransferBlobs(TransferBlobsCallback callback) override;
   void UpdatePermissions(const ExtensionId& extension_id,
diff --git a/extensions/renderer/isolated_world_manager.cc b/extensions/renderer/isolated_world_manager.cc
index d9a0865..9c271254 100644
--- a/extensions/renderer/isolated_world_manager.cc
+++ b/extensions/renderer/isolated_world_manager.cc
@@ -102,6 +102,23 @@
   }
 }
 
+void IsolatedWorldManager::ClearUserScriptWorldProperties(
+    const std::string& host_id,
+    const std::optional<std::string>& world_id) {
+  // Clear the pending world registration.
+  pending_worlds_info_.erase(std::make_pair(host_id, world_id));
+
+  // Determine if there's already an IsolatedWorldInfo for this world. If there
+  // is, reset it to the default values from the user script configuration. This
+  // ensures future worlds created from this config will have the proper state.
+  IsolatedWorldInfo* world_info = FindIsolatedWorldInfo(
+      host_id, mojom::ExecutionWorld::kUserScript, world_id);
+  if (world_info) {
+    world_info->csp = std::nullopt;
+    world_info->enable_messaging = false;
+  }
+}
+
 bool IsolatedWorldManager::IsMessagingEnabledInUserScriptWorld(
     int blink_world_id) {
   auto iter = isolated_worlds_.find(blink_world_id);
diff --git a/extensions/renderer/isolated_world_manager.h b/extensions/renderer/isolated_world_manager.h
index 8e6f656..a11faad7 100644
--- a/extensions/renderer/isolated_world_manager.h
+++ b/extensions/renderer/isolated_world_manager.h
@@ -64,6 +64,12 @@
                                     std::optional<std::string> csp,
                                     bool enable_messaging);
 
+  // Clears any properties associated with the given `host_id` and `world_id`.
+  // Note this does *not* update any existing worlds.
+  void ClearUserScriptWorldProperties(
+      const std::string& host_id,
+      const std::optional<std::string>& world_id);
+
   // Returns whether messaging APIs should be enabled in worlds for the given
   // `host_id`.
   bool IsMessagingEnabledInUserScriptWorld(int blink_world_id);
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc
index 242364e..3d3821d 100644
--- a/gpu/command_buffer/service/raster_decoder.cc
+++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -13,6 +13,7 @@
 #include <vector>
 
 #include "base/atomic_sequence_num.h"
+#include "base/command_line.h"
 #include "base/containers/flat_map.h"
 #include "base/debug/crash_logging.h"
 #include "base/functional/bind.h"
@@ -83,6 +84,7 @@
 #include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h"
 #include "third_party/skia/include/gpu/graphite/Context.h"
 #include "third_party/skia/include/private/chromium/GrPromiseImageTexture.h"
+#include "third_party/skia/include/utils/SkNoDrawCanvas.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/gfx/buffer_format_util.h"
 #include "ui/gfx/geometry/skia_conversions.h"
@@ -889,6 +891,7 @@
   std::vector<GrBackendSemaphore> end_semaphores_;
   std::unique_ptr<cc::ServicePaintCache> paint_cache_;
 
+  std::unique_ptr<SkNoDrawCanvas> no_draw_canvas_;
   raw_ptr<SkCanvas> raster_canvas_ = nullptr;
   std::vector<SkDiscardableHandleId> locked_handles_;
 
@@ -1015,6 +1018,10 @@
       is_raw_draw_enabled_(features::IsUsingRawDraw()) {
   DCHECK(shared_context_state_);
   shared_context_state_->AddContextLostObserver(this);
+  const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
+  if (cmdline->HasSwitch(switches::kDisableGLDrawingForTests)) {
+    no_draw_canvas_ = std::make_unique<SkNoDrawCanvas>(0, 0);
+  }
 }
 
 RasterDecoderImpl::~RasterDecoderImpl() {
@@ -2977,7 +2984,12 @@
     DCHECK(result);
   }
 
-  raster_canvas_ = sk_surface_->getCanvas();
+  if (no_draw_canvas_) {
+    no_draw_canvas_->resetCanvas(sk_surface_->width(), sk_surface_->height());
+    raster_canvas_ = no_draw_canvas_.get();
+  } else {
+    raster_canvas_ = sk_surface_->getCanvas();
+  }
 
   paint_op_shared_image_provider_ = std::make_unique<SharedImageProviderImpl>(
       &shared_image_representation_factory_, shared_context_state_, sk_surface_,
diff --git a/infra/config/generated/builders/ci/Leak Detection Linux/properties.json b/infra/config/generated/builders/ci/Leak Detection Linux/properties.json
index 26567069..0d494841 100644
--- a/infra/config/generated/builders/ci/Leak Detection Linux/properties.json
+++ b/infra/config/generated/builders/ci/Leak Detection Linux/properties.json
@@ -54,7 +54,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/Leak Detection Linux/shadow-properties.json b/infra/config/generated/builders/ci/Leak Detection Linux/shadow-properties.json
index b9b1d05..6bc0cf4 100644
--- a/infra/config/generated/builders/ci/Leak Detection Linux/shadow-properties.json
+++ b/infra/config/generated/builders/ci/Leak Detection Linux/shadow-properties.json
@@ -6,7 +6,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git "a/infra/config/generated/builders/ci/Linux Builder \050Wayland\051/properties.json" "b/infra/config/generated/builders/ci/Linux Builder \050Wayland\051/properties.json"
index 978cb29e..40a9ef1 100644
--- "a/infra/config/generated/builders/ci/Linux Builder \050Wayland\051/properties.json"
+++ "b/infra/config/generated/builders/ci/Linux Builder \050Wayland\051/properties.json"
@@ -96,7 +96,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git "a/infra/config/generated/builders/ci/Linux Builder \050Wayland\051/shadow-properties.json" "b/infra/config/generated/builders/ci/Linux Builder \050Wayland\051/shadow-properties.json"
index b9b1d05..6bc0cf4 100644
--- "a/infra/config/generated/builders/ci/Linux Builder \050Wayland\051/shadow-properties.json"
+++ "b/infra/config/generated/builders/ci/Linux Builder \050Wayland\051/shadow-properties.json"
@@ -6,7 +6,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git "a/infra/config/generated/builders/ci/Linux Builder \050dbg\051/properties.json" "b/infra/config/generated/builders/ci/Linux Builder \050dbg\051/properties.json"
index 5ef94104..8597c87 100644
--- "a/infra/config/generated/builders/ci/Linux Builder \050dbg\051/properties.json"
+++ "b/infra/config/generated/builders/ci/Linux Builder \050dbg\051/properties.json"
@@ -95,7 +95,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git "a/infra/config/generated/builders/ci/Linux Builder \050dbg\051/shadow-properties.json" "b/infra/config/generated/builders/ci/Linux Builder \050dbg\051/shadow-properties.json"
index 779e85dc..a3e8654 100644
--- "a/infra/config/generated/builders/ci/Linux Builder \050dbg\051/shadow-properties.json"
+++ "b/infra/config/generated/builders/ci/Linux Builder \050dbg\051/shadow-properties.json"
@@ -6,7 +6,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/Linux Builder/properties.json b/infra/config/generated/builders/ci/Linux Builder/properties.json
index 15efcd7..338139bf 100644
--- a/infra/config/generated/builders/ci/Linux Builder/properties.json
+++ b/infra/config/generated/builders/ci/Linux Builder/properties.json
@@ -112,7 +112,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/Linux Builder/shadow-properties.json b/infra/config/generated/builders/ci/Linux Builder/shadow-properties.json
index 779e85dc..a3e8654 100644
--- a/infra/config/generated/builders/ci/Linux Builder/shadow-properties.json
+++ b/infra/config/generated/builders/ci/Linux Builder/shadow-properties.json
@@ -6,7 +6,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git "a/infra/config/generated/builders/ci/Linux Tests \050Wayland\051/properties.json" "b/infra/config/generated/builders/ci/Linux Tests \050Wayland\051/properties.json"
index 5bafc1d..a0ec0e4f 100644
--- "a/infra/config/generated/builders/ci/Linux Tests \050Wayland\051/properties.json"
+++ "b/infra/config/generated/builders/ci/Linux Tests \050Wayland\051/properties.json"
@@ -80,7 +80,9 @@
     }
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git "a/infra/config/generated/builders/ci/Linux Tests \050Wayland\051/shadow-properties.json" "b/infra/config/generated/builders/ci/Linux Tests \050Wayland\051/shadow-properties.json"
index d7f978c4..5271cc6a 100644
--- "a/infra/config/generated/builders/ci/Linux Tests \050Wayland\051/shadow-properties.json"
+++ "b/infra/config/generated/builders/ci/Linux Tests \050Wayland\051/shadow-properties.json"
@@ -1,6 +1,8 @@
 {
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git "a/infra/config/generated/builders/ci/Linux Tests \050dbg\051\0501\051/properties.json" "b/infra/config/generated/builders/ci/Linux Tests \050dbg\051\0501\051/properties.json"
index 86a07156..17227fe3 100644
--- "a/infra/config/generated/builders/ci/Linux Tests \050dbg\051\0501\051/properties.json"
+++ "b/infra/config/generated/builders/ci/Linux Tests \050dbg\051\0501\051/properties.json"
@@ -79,7 +79,9 @@
     }
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git "a/infra/config/generated/builders/ci/Linux Tests \050dbg\051\0501\051/shadow-properties.json" "b/infra/config/generated/builders/ci/Linux Tests \050dbg\051\0501\051/shadow-properties.json"
index d7f978c4..5271cc6a 100644
--- "a/infra/config/generated/builders/ci/Linux Tests \050dbg\051\0501\051/shadow-properties.json"
+++ "b/infra/config/generated/builders/ci/Linux Tests \050dbg\051\0501\051/shadow-properties.json"
@@ -1,6 +1,8 @@
 {
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/Linux Tests/properties.json b/infra/config/generated/builders/ci/Linux Tests/properties.json
index ff4c393..38ec3ef 100644
--- a/infra/config/generated/builders/ci/Linux Tests/properties.json
+++ b/infra/config/generated/builders/ci/Linux Tests/properties.json
@@ -96,7 +96,9 @@
     }
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/Linux Tests/shadow-properties.json b/infra/config/generated/builders/ci/Linux Tests/shadow-properties.json
index d7f978c4..5271cc6a 100644
--- a/infra/config/generated/builders/ci/Linux Tests/shadow-properties.json
+++ b/infra/config/generated/builders/ci/Linux Tests/shadow-properties.json
@@ -1,6 +1,8 @@
 {
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/Network Service Linux/properties.json b/infra/config/generated/builders/ci/Network Service Linux/properties.json
index 1592b8b..6ef1264d8 100644
--- a/infra/config/generated/builders/ci/Network Service Linux/properties.json
+++ b/infra/config/generated/builders/ci/Network Service Linux/properties.json
@@ -54,7 +54,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/Network Service Linux/shadow-properties.json b/infra/config/generated/builders/ci/Network Service Linux/shadow-properties.json
index b9b1d05..6bc0cf4 100644
--- a/infra/config/generated/builders/ci/Network Service Linux/shadow-properties.json
+++ b/infra/config/generated/builders/ci/Network Service Linux/shadow-properties.json
@@ -6,7 +6,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/fuchsia-arm64-cast-receiver-rel/properties.json b/infra/config/generated/builders/ci/fuchsia-arm64-cast-receiver-rel/properties.json
index 6148db7d..ec557bbd 100644
--- a/infra/config/generated/builders/ci/fuchsia-arm64-cast-receiver-rel/properties.json
+++ b/infra/config/generated/builders/ci/fuchsia-arm64-cast-receiver-rel/properties.json
@@ -59,7 +59,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/fuchsia-arm64-cast-receiver-rel/shadow-properties.json b/infra/config/generated/builders/ci/fuchsia-arm64-cast-receiver-rel/shadow-properties.json
index 779e85dc..a3e8654 100644
--- a/infra/config/generated/builders/ci/fuchsia-arm64-cast-receiver-rel/shadow-properties.json
+++ b/infra/config/generated/builders/ci/fuchsia-arm64-cast-receiver-rel/shadow-properties.json
@@ -6,7 +6,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/fuchsia-x64-cast-receiver-dbg/properties.json b/infra/config/generated/builders/ci/fuchsia-x64-cast-receiver-dbg/properties.json
index 11d7214..6e52f8e 100644
--- a/infra/config/generated/builders/ci/fuchsia-x64-cast-receiver-dbg/properties.json
+++ b/infra/config/generated/builders/ci/fuchsia-x64-cast-receiver-dbg/properties.json
@@ -61,7 +61,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/fuchsia-x64-cast-receiver-dbg/shadow-properties.json b/infra/config/generated/builders/ci/fuchsia-x64-cast-receiver-dbg/shadow-properties.json
index 779e85dc..a3e8654 100644
--- a/infra/config/generated/builders/ci/fuchsia-x64-cast-receiver-dbg/shadow-properties.json
+++ b/infra/config/generated/builders/ci/fuchsia-x64-cast-receiver-dbg/shadow-properties.json
@@ -6,7 +6,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/fuchsia-x64-cast-receiver-rel/properties.json b/infra/config/generated/builders/ci/fuchsia-x64-cast-receiver-rel/properties.json
index 6e61e90d..57ab6c2 100644
--- a/infra/config/generated/builders/ci/fuchsia-x64-cast-receiver-rel/properties.json
+++ b/infra/config/generated/builders/ci/fuchsia-x64-cast-receiver-rel/properties.json
@@ -57,7 +57,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/fuchsia-x64-cast-receiver-rel/shadow-properties.json b/infra/config/generated/builders/ci/fuchsia-x64-cast-receiver-rel/shadow-properties.json
index 779e85dc..a3e8654 100644
--- a/infra/config/generated/builders/ci/fuchsia-x64-cast-receiver-rel/shadow-properties.json
+++ b/infra/config/generated/builders/ci/fuchsia-x64-cast-receiver-rel/shadow-properties.json
@@ -6,7 +6,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/linux-arm64-cast-rel/properties.json b/infra/config/generated/builders/ci/linux-arm64-cast-rel/properties.json
index 63dbfb06..81c5de9 100644
--- a/infra/config/generated/builders/ci/linux-arm64-cast-rel/properties.json
+++ b/infra/config/generated/builders/ci/linux-arm64-cast-rel/properties.json
@@ -58,7 +58,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/linux-arm64-cast-rel/shadow-properties.json b/infra/config/generated/builders/ci/linux-arm64-cast-rel/shadow-properties.json
index 779e85dc..a3e8654 100644
--- a/infra/config/generated/builders/ci/linux-arm64-cast-rel/shadow-properties.json
+++ b/infra/config/generated/builders/ci/linux-arm64-cast-rel/shadow-properties.json
@@ -6,7 +6,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/linux-bfcache-rel/properties.json b/infra/config/generated/builders/ci/linux-bfcache-rel/properties.json
index 21923a11..e5fbcc9c 100644
--- a/infra/config/generated/builders/ci/linux-bfcache-rel/properties.json
+++ b/infra/config/generated/builders/ci/linux-bfcache-rel/properties.json
@@ -54,7 +54,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/linux-bfcache-rel/shadow-properties.json b/infra/config/generated/builders/ci/linux-bfcache-rel/shadow-properties.json
index b9b1d05..6bc0cf4 100644
--- a/infra/config/generated/builders/ci/linux-bfcache-rel/shadow-properties.json
+++ b/infra/config/generated/builders/ci/linux-bfcache-rel/shadow-properties.json
@@ -6,7 +6,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/linux-extended-tracing-rel/properties.json b/infra/config/generated/builders/ci/linux-extended-tracing-rel/properties.json
index 9f06b89b..5e68ac6f 100644
--- a/infra/config/generated/builders/ci/linux-extended-tracing-rel/properties.json
+++ b/infra/config/generated/builders/ci/linux-extended-tracing-rel/properties.json
@@ -54,7 +54,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/linux-extended-tracing-rel/shadow-properties.json b/infra/config/generated/builders/ci/linux-extended-tracing-rel/shadow-properties.json
index b9b1d05..6bc0cf4 100644
--- a/infra/config/generated/builders/ci/linux-extended-tracing-rel/shadow-properties.json
+++ b/infra/config/generated/builders/ci/linux-extended-tracing-rel/shadow-properties.json
@@ -6,7 +6,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/linux-gcc-rel/properties.json b/infra/config/generated/builders/ci/linux-gcc-rel/properties.json
index 885f27cb..563c75bd 100644
--- a/infra/config/generated/builders/ci/linux-gcc-rel/properties.json
+++ b/infra/config/generated/builders/ci/linux-gcc-rel/properties.json
@@ -48,7 +48,9 @@
     }
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/linux-gcc-rel/shadow-properties.json b/infra/config/generated/builders/ci/linux-gcc-rel/shadow-properties.json
index d7f978c4..5271cc6a 100644
--- a/infra/config/generated/builders/ci/linux-gcc-rel/shadow-properties.json
+++ b/infra/config/generated/builders/ci/linux-gcc-rel/shadow-properties.json
@@ -1,6 +1,8 @@
 {
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/linux-v4l2-codec-rel/properties.json b/infra/config/generated/builders/ci/linux-v4l2-codec-rel/properties.json
index 2599cf8..5763735 100644
--- a/infra/config/generated/builders/ci/linux-v4l2-codec-rel/properties.json
+++ b/infra/config/generated/builders/ci/linux-v4l2-codec-rel/properties.json
@@ -54,7 +54,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/linux-v4l2-codec-rel/shadow-properties.json b/infra/config/generated/builders/ci/linux-v4l2-codec-rel/shadow-properties.json
index 779e85dc..a3e8654 100644
--- a/infra/config/generated/builders/ci/linux-v4l2-codec-rel/shadow-properties.json
+++ b/infra/config/generated/builders/ci/linux-v4l2-codec-rel/shadow-properties.json
@@ -6,7 +6,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/linux-x64-cast-dbg/properties.json b/infra/config/generated/builders/ci/linux-x64-cast-dbg/properties.json
index b31bc60..ceecf91 100644
--- a/infra/config/generated/builders/ci/linux-x64-cast-dbg/properties.json
+++ b/infra/config/generated/builders/ci/linux-x64-cast-dbg/properties.json
@@ -54,7 +54,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/builders/ci/linux-x64-cast-dbg/shadow-properties.json b/infra/config/generated/builders/ci/linux-x64-cast-dbg/shadow-properties.json
index 779e85dc..a3e8654 100644
--- a/infra/config/generated/builders/ci/linux-x64-cast-dbg/shadow-properties.json
+++ b/infra/config/generated/builders/ci/linux-x64-cast-dbg/shadow-properties.json
@@ -6,7 +6,9 @@
     "scandeps_server": true
   },
   "$build/siso": {
-    "configs": null,
+    "configs": [
+      "builder"
+    ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 633d618..5c98c85 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -12192,7 +12192,9 @@
         '    "scandeps_server": true'
         '  },'
         '  "$build/siso": {'
-        '    "configs": null,'
+        '    "configs": ['
+        '      "builder"'
+        '    ],'
         '    "enable_cloud_profiler": true,'
         '    "enable_cloud_trace": true,'
         '    "experiments": [],'
@@ -12267,7 +12269,9 @@
           '    "scandeps_server": true'
           '  },'
           '  "$build/siso": {'
-          '    "configs": null,'
+          '    "configs": ['
+          '      "builder"'
+          '    ],'
           '    "enable_cloud_profiler": true,'
           '    "enable_cloud_trace": true,'
           '    "experiments": [],'
@@ -12304,7 +12308,9 @@
         '    "scandeps_server": true'
         '  },'
         '  "$build/siso": {'
-        '    "configs": null,'
+        '    "configs": ['
+        '      "builder"'
+        '    ],'
         '    "enable_cloud_profiler": true,'
         '    "enable_cloud_trace": true,'
         '    "experiments": [],'
@@ -12379,7 +12385,9 @@
           '    "scandeps_server": true'
           '  },'
           '  "$build/siso": {'
-          '    "configs": null,'
+          '    "configs": ['
+          '      "builder"'
+          '    ],'
           '    "enable_cloud_profiler": true,'
           '    "enable_cloud_trace": true,'
           '    "experiments": [],'
@@ -12416,7 +12424,9 @@
         '    "scandeps_server": true'
         '  },'
         '  "$build/siso": {'
-        '    "configs": null,'
+        '    "configs": ['
+        '      "builder"'
+        '    ],'
         '    "enable_cloud_profiler": true,'
         '    "enable_cloud_trace": true,'
         '    "experiments": [],'
@@ -12491,7 +12501,9 @@
           '    "scandeps_server": true'
           '  },'
           '  "$build/siso": {'
-          '    "configs": null,'
+          '    "configs": ['
+          '      "builder"'
+          '    ],'
           '    "enable_cloud_profiler": true,'
           '    "enable_cloud_trace": true,'
           '    "experiments": [],'
diff --git a/infra/config/generated/luci/project.cfg b/infra/config/generated/luci/project.cfg
index 2dc5849..a193d43 100644
--- a/infra/config/generated/luci/project.cfg
+++ b/infra/config/generated/luci/project.cfg
@@ -7,7 +7,7 @@
 name: "chromium"
 access: "group:all"
 lucicfg {
-  version: "1.43.5"
+  version: "1.43.6"
   package_dir: "../.."
   config_dir: "generated/luci"
   entry_point: "main.star"
diff --git a/infra/config/generated/testing/test_suites.pyl b/infra/config/generated/testing/test_suites.pyl
index b339ed6..c7ef739b 100644
--- a/infra/config/generated/testing/test_suites.pyl
+++ b/infra/config/generated/testing/test_suites.pyl
@@ -4152,6 +4152,12 @@
           '--use-gpu-in-tests',
         ],
       },
+      'components_browsertests': {
+        'args': [
+          '--test-launcher-bot-mode',
+          '--test-launcher-filter-file=testing/buildbot/filters/ios.use_blink.components_browsertests.filter',
+        ],
+      },
       'components_unittests': {
         'args': [
           '--test-launcher-bot-mode',
diff --git a/infra/config/generated/testing/variants.pyl b/infra/config/generated/testing/variants.pyl
index 108ec1a..d5b4c7d0 100644
--- a/infra/config/generated/testing/variants.pyl
+++ b/infra/config/generated/testing/variants.pyl
@@ -251,16 +251,16 @@
   },
   'LACROS_VERSION_SKEW_BETA': {
     'identifier': 'Lacros version skew testing ash beta',
-    'description': 'Run with ash-chrome version 124.0.6367.34',
+    'description': 'Run with ash-chrome version 124.0.6367.66',
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.34/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.66/test_ash_chrome',
     ],
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v124.0.6367.34',
-          'revision': 'version:124.0.6367.34',
+          'location': 'lacros_version_skew_tests_v124.0.6367.66',
+          'revision': 'version:124.0.6367.66',
         },
       ],
     },
diff --git a/infra/config/lib/builders.star b/infra/config/lib/builders.star
index 16c852a..724fcaf 100644
--- a/infra/config/lib/builders.star
+++ b/infra/config/lib/builders.star
@@ -364,10 +364,10 @@
     reclient_ensure_verified = None,
     reclient_disable_bq_upload = None,
     siso_enabled = None,
-    siso_configs = None,
+    siso_configs = ["builder"],
     siso_project = None,
-    siso_enable_cloud_profiler = None,
-    siso_enable_cloud_trace = None,
+    siso_enable_cloud_profiler = True,
+    siso_enable_cloud_trace = True,
     siso_experiments = [],
     siso_remote_jobs = None,
     health_spec = None,
diff --git a/infra/config/subprojects/build/build.fyi.star b/infra/config/subprojects/build/build.fyi.star
index 6b6cc86..71b47b5 100644
--- a/infra/config/subprojects/build/build.fyi.star
+++ b/infra/config/subprojects/build/build.fyi.star
@@ -24,9 +24,6 @@
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
     shadow_siso_project = siso.project.DEFAULT_UNTRUSTED,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
 )
diff --git a/infra/config/subprojects/build/build.star b/infra/config/subprojects/build/build.star
index e4d7dc7c..a18e8d16 100644
--- a/infra/config/subprojects/build/build.star
+++ b/infra/config/subprojects/build/build.star
@@ -84,8 +84,6 @@
     priority = ci.DEFAULT_FYI_PRIORITY,
     service_account = "chromium-build-perf-ci-builder@chops-service-accounts.iam.gserviceaccount.com",
     siso_configs = [],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_experiments = ["no-fallback"],
 )
diff --git a/infra/config/subprojects/chromium/ci/chromium.accessibility.star b/infra/config/subprojects/chromium/ci/chromium.accessibility.star
index b6efe6d..88025f7 100644
--- a/infra/config/subprojects/chromium/ci/chromium.accessibility.star
+++ b/infra/config/subprojects/chromium/ci/chromium.accessibility.star
@@ -25,9 +25,6 @@
     reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CI,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.android.fyi.star b/infra/config/subprojects/chromium/ci/chromium.android.fyi.star
index eb0c476..657f21b 100644
--- a/infra/config/subprojects/chromium/ci/chromium.android.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.android.fyi.star
@@ -23,9 +23,6 @@
     reclient_jobs = reclient.jobs.DEFAULT,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.android.star b/infra/config/subprojects/chromium/ci/chromium.android.star
index 40735092..07f4e63 100644
--- a/infra/config/subprojects/chromium/ci/chromium.android.star
+++ b/infra/config/subprojects/chromium/ci/chromium.android.star
@@ -25,9 +25,6 @@
     reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CI,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.HIGH_JOBS_FOR_CI,
diff --git a/infra/config/subprojects/chromium/ci/chromium.angle.star b/infra/config/subprojects/chromium/ci/chromium.angle.star
index ccba020..e10bdd7 100644
--- a/infra/config/subprojects/chromium/ci/chromium.angle.star
+++ b/infra/config/subprojects/chromium/ci/chromium.angle.star
@@ -25,9 +25,6 @@
     reclient_jobs = reclient.jobs.DEFAULT,
     service_account = ci.gpu.SERVICE_ACCOUNT,
     shadow_service_account = ci.gpu.SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.cft.star b/infra/config/subprojects/chromium/ci/chromium.cft.star
index f245408..a3125271 100644
--- a/infra/config/subprojects/chromium/ci/chromium.cft.star
+++ b/infra/config/subprojects/chromium/ci/chromium.cft.star
@@ -24,9 +24,6 @@
     reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CI,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.HIGH_JOBS_FOR_CI,
diff --git a/infra/config/subprojects/chromium/ci/chromium.chromiumos.star b/infra/config/subprojects/chromium/ci/chromium.chromiumos.star
index 54e298f..2310af6 100644
--- a/infra/config/subprojects/chromium/ci/chromium.chromiumos.star
+++ b/infra/config/subprojects/chromium/ci/chromium.chromiumos.star
@@ -32,9 +32,6 @@
     reclient_jobs = reclient.jobs.DEFAULT,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.clang.star b/infra/config/subprojects/chromium/ci/chromium.clang.star
index 52123b6..c998073 100644
--- a/infra/config/subprojects/chromium/ci/chromium.clang.star
+++ b/infra/config/subprojects/chromium/ci/chromium.clang.star
@@ -149,9 +149,6 @@
     notifies = ["CFI Linux"],
     reclient_instance = reclient.instance.DEFAULT_TRUSTED,
     reclient_jobs = reclient.jobs.DEFAULT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.coverage.star b/infra/config/subprojects/chromium/ci/chromium.coverage.star
index 0e92a27..5e5f446 100644
--- a/infra/config/subprojects/chromium/ci/chromium.coverage.star
+++ b/infra/config/subprojects/chromium/ci/chromium.coverage.star
@@ -38,9 +38,6 @@
     reclient_jobs = reclient.jobs.DEFAULT,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.dawn.star b/infra/config/subprojects/chromium/ci/chromium.dawn.star
index bcf903d..13aab86b 100644
--- a/infra/config/subprojects/chromium/ci/chromium.dawn.star
+++ b/infra/config/subprojects/chromium/ci/chromium.dawn.star
@@ -23,9 +23,6 @@
     reclient_jobs = reclient.jobs.DEFAULT,
     service_account = ci.gpu.SERVICE_ACCOUNT,
     shadow_service_account = ci.gpu.SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star
index a3e906b..781e0e8bc 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star
@@ -25,9 +25,6 @@
     reclient_jobs = reclient.jobs.DEFAULT,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.fuchsia.star b/infra/config/subprojects/chromium/ci/chromium.fuchsia.star
index 547e9cb..345029c 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fuchsia.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fuchsia.star
@@ -28,8 +28,6 @@
     reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CI,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.HIGH_JOBS_FOR_CI,
diff --git a/infra/config/subprojects/chromium/ci/chromium.fuzz.star b/infra/config/subprojects/chromium/ci/chromium.fuzz.star
index a730414e..ffedb57 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fuzz.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fuzz.star
@@ -26,9 +26,6 @@
     reclient_jobs = reclient.jobs.DEFAULT,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star
index 5362982..ee9e044 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -25,9 +25,6 @@
     reclient_jobs = reclient.jobs.DEFAULT,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
 )
 
 consoles.console_view(
diff --git a/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star b/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star
index 5389f8c7..08cee95 100644
--- a/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star
@@ -26,9 +26,6 @@
     reclient_jobs = reclient.jobs.DEFAULT,
     service_account = ci.gpu.SERVICE_ACCOUNT,
     shadow_service_account = ci.gpu.SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.gpu.star b/infra/config/subprojects/chromium/ci/chromium.gpu.star
index 607a110..a7fe66a8 100644
--- a/infra/config/subprojects/chromium/ci/chromium.gpu.star
+++ b/infra/config/subprojects/chromium/ci/chromium.gpu.star
@@ -25,9 +25,6 @@
     reclient_jobs = reclient.jobs.DEFAULT,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.linux.star b/infra/config/subprojects/chromium/ci/chromium.linux.star
index 8fe41d1..ecad4529 100644
--- a/infra/config/subprojects/chromium/ci/chromium.linux.star
+++ b/infra/config/subprojects/chromium/ci/chromium.linux.star
@@ -29,8 +29,6 @@
     reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CI,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.HIGH_JOBS_FOR_CI,
diff --git a/infra/config/subprojects/chromium/ci/chromium.mac.star b/infra/config/subprojects/chromium/ci/chromium.mac.star
index f134f70..eb7a8ef 100644
--- a/infra/config/subprojects/chromium/ci/chromium.mac.star
+++ b/infra/config/subprojects/chromium/ci/chromium.mac.star
@@ -27,9 +27,6 @@
     reclient_jobs = reclient.jobs.DEFAULT,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.memory.fyi.star b/infra/config/subprojects/chromium/ci/chromium.memory.fyi.star
index ff92e80..52bfcb4 100644
--- a/infra/config/subprojects/chromium/ci/chromium.memory.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.memory.fyi.star
@@ -23,9 +23,6 @@
     reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CI,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.LOW_JOBS_FOR_CI,
diff --git a/infra/config/subprojects/chromium/ci/chromium.memory.star b/infra/config/subprojects/chromium/ci/chromium.memory.star
index fa8ee98..45fc608e5 100644
--- a/infra/config/subprojects/chromium/ci/chromium.memory.star
+++ b/infra/config/subprojects/chromium/ci/chromium.memory.star
@@ -29,9 +29,6 @@
     reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CI,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.HIGH_JOBS_FOR_CI,
diff --git a/infra/config/subprojects/chromium/ci/chromium.star b/infra/config/subprojects/chromium/ci/chromium.star
index 5481ce91..f3e8753 100644
--- a/infra/config/subprojects/chromium/ci/chromium.star
+++ b/infra/config/subprojects/chromium/ci/chromium.star
@@ -31,9 +31,6 @@
     reclient_jobs = reclient.jobs.DEFAULT,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.swangle.star b/infra/config/subprojects/chromium/ci/chromium.swangle.star
index 5dc47cdb..34eff4b 100644
--- a/infra/config/subprojects/chromium/ci/chromium.swangle.star
+++ b/infra/config/subprojects/chromium/ci/chromium.swangle.star
@@ -22,9 +22,6 @@
     reclient_jobs = reclient.jobs.DEFAULT,
     service_account = ci.gpu.SERVICE_ACCOUNT,
     shadow_service_account = ci.gpu.SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.updater.star b/infra/config/subprojects/chromium/ci/chromium.updater.star
index 61d14cba..34b6671 100644
--- a/infra/config/subprojects/chromium/ci/chromium.updater.star
+++ b/infra/config/subprojects/chromium/ci/chromium.updater.star
@@ -23,9 +23,6 @@
     reclient_jobs = reclient.jobs.DEFAULT,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/ci/chromium.win.star b/infra/config/subprojects/chromium/ci/chromium.win.star
index b1e14e2..2c677b07 100644
--- a/infra/config/subprojects/chromium/ci/chromium.win.star
+++ b/infra/config/subprojects/chromium/ci/chromium.win.star
@@ -29,9 +29,6 @@
     reclient_jobs = reclient.jobs.DEFAULT,
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     shadow_service_account = ci.DEFAULT_SHADOW_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_TRUSTED,
     siso_remote_jobs = reclient.jobs.DEFAULT,
diff --git a/infra/config/subprojects/chromium/gpu.try.star b/infra/config/subprojects/chromium/gpu.try.star
index b231d07..4069495 100644
--- a/infra/config/subprojects/chromium/gpu.try.star
+++ b/infra/config/subprojects/chromium/gpu.try.star
@@ -22,9 +22,6 @@
     expiration_timeout = 2 * time.hour,
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     service_account = "chromium-try-gpu-builder@chops-service-accounts.iam.gserviceaccount.com",
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
     subproject_list_view = "luci.chromium.try",
diff --git a/infra/config/subprojects/chromium/swangle.try.star b/infra/config/subprojects/chromium/swangle.try.star
index 02356c3..ddeaf37 100644
--- a/infra/config/subprojects/chromium/swangle.try.star
+++ b/infra/config/subprojects/chromium/swangle.try.star
@@ -25,9 +25,6 @@
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CQ,
     service_account = "chromium-try-gpu-builder@chops-service-accounts.iam.gserviceaccount.com",
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
     subproject_list_view = "luci.chromium.try",
diff --git a/infra/config/subprojects/chromium/try/tryserver.blink.star b/infra/config/subprojects/chromium/try/tryserver.blink.star
index e349417..005472a5 100644
--- a/infra/config/subprojects/chromium/try/tryserver.blink.star
+++ b/infra/config/subprojects/chromium/try/tryserver.blink.star
@@ -19,9 +19,6 @@
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CQ,
     service_account = try_.DEFAULT_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
 )
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.accessibility.star b/infra/config/subprojects/chromium/try/tryserver.chromium.accessibility.star
index 08d4a13..d8df36bd 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.accessibility.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.accessibility.star
@@ -19,9 +19,6 @@
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     reclient_jobs = 150,
     service_account = try_.DEFAULT_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
 )
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.android.star b/infra/config/subprojects/chromium/try/tryserver.chromium.android.star
index be94afa..85a67d2 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.android.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.android.star
@@ -23,9 +23,6 @@
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ,
     service_account = try_.DEFAULT_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
 )
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.angle.star b/infra/config/subprojects/chromium/try/tryserver.chromium.angle.star
index ed69a2e..93b33d96 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.angle.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.angle.star
@@ -20,9 +20,6 @@
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ,
     service_account = try_.gpu.SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
 )
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.cft.star b/infra/config/subprojects/chromium/try/tryserver.chromium.cft.star
index 39985e5..0acb6c1 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.cft.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.cft.star
@@ -18,9 +18,6 @@
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CQ,
     service_account = try_.DEFAULT_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
 )
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star b/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star
index 890c2bc..d860194d 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star
@@ -25,9 +25,6 @@
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CQ,
     service_account = try_.DEFAULT_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
 )
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.dawn.star b/infra/config/subprojects/chromium/try/tryserver.chromium.dawn.star
index 975f900..d70e167 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.dawn.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.dawn.star
@@ -21,9 +21,6 @@
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CQ,
     service_account = try_.gpu.SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
 )
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star b/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
index 9c8e6b0f..98695444 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
@@ -25,9 +25,6 @@
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ,
     service_account = try_.DEFAULT_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
 )
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.fuzz.star b/infra/config/subprojects/chromium/try/tryserver.chromium.fuzz.star
index 97343fa..1e838f9 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.fuzz.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.fuzz.star
@@ -18,9 +18,6 @@
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ,
     service_account = try_.DEFAULT_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
 )
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
index 9e0c544..a73d554 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
@@ -24,9 +24,6 @@
     orchestrator_reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ,
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     service_account = try_.DEFAULT_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
 )
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star b/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star
index 1ef543b..7b73ae0d 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star
@@ -23,9 +23,6 @@
     orchestrator_reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ,
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     service_account = try_.DEFAULT_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
 )
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.rust.star b/infra/config/subprojects/chromium/try/tryserver.chromium.rust.star
index b1e9b7b..81ada6a0 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.rust.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.rust.star
@@ -18,9 +18,6 @@
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CQ,
     service_account = try_.DEFAULT_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
 )
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.star b/infra/config/subprojects/chromium/try/tryserver.chromium.star
index 3773d29..91c4d48 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.star
@@ -20,9 +20,6 @@
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ,
     service_account = try_.DEFAULT_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
 )
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.updater.star b/infra/config/subprojects/chromium/try/tryserver.chromium.updater.star
index 1d38e0bf9..d8a387b5 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.updater.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.updater.star
@@ -17,9 +17,6 @@
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CQ,
     service_account = try_.DEFAULT_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
 )
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.win.star b/infra/config/subprojects/chromium/try/tryserver.chromium.win.star
index 85bb4fd..29f586dd 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.win.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.win.star
@@ -26,9 +26,6 @@
     reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
     reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CQ,
     service_account = try_.DEFAULT_SERVICE_ACCOUNT,
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
     siso_enabled = True,
     siso_project = siso.project.DEFAULT_UNTRUSTED,
 )
diff --git a/infra/config/subprojects/reclient/reclient.star b/infra/config/subprojects/reclient/reclient.star
index a265d5c3..67d0050 100644
--- a/infra/config/subprojects/reclient/reclient.star
+++ b/infra/config/subprojects/reclient/reclient.star
@@ -46,9 +46,6 @@
     service_account = (
         "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
     ),
-    siso_configs = ["builder"],
-    siso_enable_cloud_profiler = True,
-    siso_enable_cloud_trace = True,
 )
 
 consoles.console_view(
diff --git a/infra/config/targets/basic_suites.star b/infra/config/targets/basic_suites.star
index 9fdf7c4..055fd8d 100644
--- a/infra/config/targets/basic_suites.star
+++ b/infra/config/targets/basic_suites.star
@@ -3810,6 +3810,12 @@
                 "--use-gpu-in-tests",
             ],
         ),
+        "components_browsertests": targets.legacy_test_config(
+            args = [
+                "--test-launcher-bot-mode",
+                "--test-launcher-filter-file=testing/buildbot/filters/ios.use_blink.components_browsertests.filter",
+            ],
+        ),
         "components_unittests": targets.legacy_test_config(
             args = [
                 "--test-launcher-bot-mode",
diff --git a/infra/config/targets/lacros-version-skew-variants.json b/infra/config/targets/lacros-version-skew-variants.json
index 39c76a9..021daeb 100644
--- a/infra/config/targets/lacros-version-skew-variants.json
+++ b/infra/config/targets/lacros-version-skew-variants.json
@@ -33,16 +33,16 @@
   },
   "LACROS_VERSION_SKEW_BETA": {
     "args": [
-      "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.34/test_ash_chrome"
+      "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.66/test_ash_chrome"
     ],
-    "description": "Run with ash-chrome version 124.0.6367.34",
+    "description": "Run with ash-chrome version 124.0.6367.66",
     "identifier": "Lacros version skew testing ash beta",
     "swarming": {
       "cipd_packages": [
         {
           "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-          "location": "lacros_version_skew_tests_v124.0.6367.34",
-          "revision": "version:124.0.6367.34"
+          "location": "lacros_version_skew_tests_v124.0.6367.66",
+          "revision": "version:124.0.6367.66"
         }
       ]
     }
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index 22c7abe..5c1b18d 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -609,13 +609,6 @@
      "PasswordManagerEnableReceiverService,SharedPasswordNotificationUI"},
 };
 
-const FeatureEntry::FeatureParam kIOSHideFeedWithSearchChoiceTargetedParams[] =
-    {{kIOSHideFeedWithSearchChoiceTargeted, "true"}};
-const FeatureEntry::FeatureVariation kIOSHideFeedWithSearchChoiceVariations[]{
-    {"with targeting", kIOSHideFeedWithSearchChoiceTargetedParams,
-     std::size(kIOSHideFeedWithSearchChoiceTargetedParams), nullptr},
-};
-
 const flags_ui::FeatureEntry::FeatureParam kParcelTrackingTestDataDelivered[] =
     {{commerce::kParcelTrackingTestDataParam,
       commerce::kParcelTrackingTestDataParamDelivered}};
@@ -964,14 +957,6 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(kMagicStack,
                                     kMagicStackVariations,
                                     flag_descriptions::kMagicStackName)},
-    {"ios-hide-feed-with-search-choice",
-     flag_descriptions::kIOSHideFeedWithSearchChoiceName,
-     flag_descriptions::kIOSHideFeedWithSearchChoiceDescription,
-     flags_ui::kOsIos,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(
-         kIOSHideFeedWithSearchChoice,
-         kIOSHideFeedWithSearchChoiceVariations,
-         flag_descriptions::kIOSHideFeedWithSearchChoiceName)},
     {"ios-keyboard-accessory-upgrade",
      flag_descriptions::kIOSKeyboardAccessoryUpgradeName,
      flag_descriptions::kIOSKeyboardAccessoryUpgradeDescription,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index db93752..ef09b3c 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -1024,11 +1024,6 @@
     "When enabled with bottom omnibox, the top toolbar background color is the "
     "page's theme color. Disabled when a dynamic color flag is enabled.";
 
-const char kIOSHideFeedWithSearchChoiceName[] = "Hide Feed with Search Choice";
-const char kIOSHideFeedWithSearchChoiceDescription[] =
-    "When enabled, the feed and feed header are hidden depending on the "
-    "Search Engine setting.";
-
 const char kIOSLargeFakeboxName[] = "Enable Large Fakebox on Home";
 const char kIOSLargeFakeboxDescription[] =
     "When enabled, the Fakebox on Home appears larger and has an updated "
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index 2dbdae5..3394549 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -907,11 +907,6 @@
 extern const char kThemeColorInTopToolbarName[];
 extern const char kThemeColorInTopToolbarDescription[];
 
-// Title and description for the flag to enable the iOS Hide Feed with Search
-// Choice feature.
-extern const char kIOSHideFeedWithSearchChoiceName[];
-extern const char kIOSHideFeedWithSearchChoiceDescription[];
-
 // Title and description for the flag to enable the iOS Large Fakebox feature
 extern const char kIOSLargeFakeboxName[];
 extern const char kIOSLargeFakeboxDescription[];
diff --git a/ios/chrome/browser/ntp/model/BUILD.gn b/ios/chrome/browser/ntp/model/BUILD.gn
index 5d67b23..a6b9f67 100644
--- a/ios/chrome/browser/ntp/model/BUILD.gn
+++ b/ios/chrome/browser/ntp/model/BUILD.gn
@@ -41,7 +41,6 @@
     "//components/search",
     "//components/search_engines",
     "//ios/chrome/browser/shared/model/url:constants",
-    "//ios/chrome/browser/shared/public/features",
     "//ios/web/public",
   ]
 }
diff --git a/ios/chrome/browser/ntp/model/new_tab_page_util.mm b/ios/chrome/browser/ntp/model/new_tab_page_util.mm
index 87aa470a..cdedf357 100644
--- a/ios/chrome/browser/ntp/model/new_tab_page_util.mm
+++ b/ios/chrome/browser/ntp/model/new_tab_page_util.mm
@@ -8,7 +8,6 @@
 #import "components/search_engines/template_url_service.h"
 #import "ios/chrome/browser/ntp/model/new_tab_page_tab_helper.h"
 #import "ios/chrome/browser/shared/model/url/chrome_url_constants.h"
-#import "ios/chrome/browser/shared/public/features/features.h"
 #import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state.h"
@@ -35,8 +34,6 @@
 }
 
 bool ShouldHideFeedWithSearchChoice(TemplateURLService* template_url_service) {
-  return IsIOSHideFeedWithSearchChoiceEnabled() &&
-         !search::DefaultSearchProviderIsGoogle(template_url_service) &&
-         (!IsIOSHideFeedWithSearchChoiceTargeted() ||
-          template_url_service->IsEeaChoiceCountry());
+  return !search::DefaultSearchProviderIsGoogle(template_url_service) &&
+         template_url_service->IsEeaChoiceCountry();
 }
diff --git a/ios/chrome/browser/shared/public/features/features.h b/ios/chrome/browser/shared/public/features/features.h
index a24b832..8306a0ae 100644
--- a/ios/chrome/browser/shared/public/features/features.h
+++ b/ios/chrome/browser/shared/public/features/features.h
@@ -348,10 +348,6 @@
 // Feature flag to enable the Large Fakebox design changes.
 BASE_DECLARE_FEATURE(kIOSLargeFakebox);
 
-// Feature flag to enable hiding the feed and feed header depending on Search
-// Engine choice.
-BASE_DECLARE_FEATURE(kIOSHideFeedWithSearchChoice);
-
 // Feature flag to enable a more stable fullscreen.
 BASE_DECLARE_FEATURE(kFullscreenImprovement);
 
@@ -399,11 +395,6 @@
 // performing a background refresh. A zero value means the age check is ignored.
 extern const char kBackgroundRefreshMaxAgeInSeconds[];
 
-// Feature param under `kIOSHideFeedWithSearchChoice` to only target the
-// feature at certain countries (i.e. only hide the feed when the device is
-// from those countries when the search engine is changed).
-extern const char kIOSHideFeedWithSearchChoiceTargeted[];
-
 // Whether the Following Feed is enabled on NTP.
 bool IsWebChannelsEnabled();
 
@@ -465,10 +456,6 @@
 // Returns the background refresh max age in seconds.
 double GetBackgroundRefreshMaxAgeInSeconds();
 
-// Returns whether the feed hide with search choice feature should be targeted
-// only at devices from certain countries.
-bool IsIOSHideFeedWithSearchChoiceTargeted();
-
 // Whether the feed is disabled.
 bool IsFeedAblationEnabled();
 
@@ -498,9 +485,6 @@
 // Returns true when the IOSLargeFakebox feature is enabled.
 bool IsIOSLargeFakeboxEnabled();
 
-// Returns true when the IOSHideFeedWithSearchChoice feature is enabled.
-bool IsIOSHideFeedWithSearchChoiceEnabled();
-
 // Whether or not the kIOSKeyboardAccessoryUpgrade feature is enabled.
 bool IsKeyboardAccessoryUpgradeEnabled();
 
diff --git a/ios/chrome/browser/shared/public/features/features.mm b/ios/chrome/browser/shared/public/features/features.mm
index 8663db8f..9bf3ac6 100644
--- a/ios/chrome/browser/shared/public/features/features.mm
+++ b/ios/chrome/browser/shared/public/features/features.mm
@@ -378,10 +378,6 @@
              "IOSLargeFakebox",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kIOSHideFeedWithSearchChoice,
-             "IOSHideFeedWithSearchChoice",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kFullscreenImprovement,
              "FullscreenImprovement",
              base::FEATURE_DISABLED_BY_DEFAULT);
@@ -434,8 +430,6 @@
     "BackgroundRefreshIntervalInSeconds";
 const char kBackgroundRefreshMaxAgeInSeconds[] =
     "BackgroundRefreshMaxAgeInSeconds";
-const char kIOSHideFeedWithSearchChoiceTargeted[] =
-    "IOSHideFeedWithSearchChoiceTargeted";
 
 bool IsDockingPromoEnabled() {
   return base::FeatureList::IsEnabled(kIOSDockingPromo);
@@ -579,12 +573,6 @@
       /*default=*/0);
 }
 
-bool IsIOSHideFeedWithSearchChoiceTargeted() {
-  return base::GetFieldTrialParamByFeatureAsBool(
-      kIOSHideFeedWithSearchChoice, kIOSHideFeedWithSearchChoiceTargeted,
-      /*default=*/true);
-}
-
 bool IsFeedAblationEnabled() {
   return base::FeatureList::IsEnabled(kEnableFeedAblation);
 }
@@ -640,10 +628,6 @@
   return base::FeatureList::IsEnabled(kIOSLargeFakebox);
 }
 
-bool IsIOSHideFeedWithSearchChoiceEnabled() {
-  return base::FeatureList::IsEnabled(kIOSHideFeedWithSearchChoice);
-}
-
 bool IsKeyboardAccessoryUpgradeEnabled() {
   return base::FeatureList::IsEnabled(kIOSKeyboardAccessoryUpgrade) &&
          ui::GetDeviceFormFactor() != ui::DEVICE_FORM_FACTOR_TABLET;
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/chip_button.mm b/ios/chrome/browser/ui/autofill/manual_fill/chip_button.mm
index e14d163..9ccaa76 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/chip_button.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/chip_button.mm
@@ -30,6 +30,9 @@
 // the kIOSKeyboardAccessoryUpgrade feature is disabled.
 constexpr CGFloat kChipVerticalMargin = 4;
 
+// Minimal height and width for the button.
+constexpr CGFloat kChipMinSize = 40;
+
 // Font size for the button's title.
 constexpr CGFloat kFontSize = 14;
 
@@ -136,7 +139,8 @@
       [[NSMutableParagraphStyle alloc] init];
   paragraphStyle.lineSpacing = kLineSpacing;
   _titleAttributes = @{
-    NSFontAttributeName : font,
+    NSFontAttributeName :
+        [[UIFontMetrics defaultMetrics] scaledFontForFont:font],
     NSParagraphStyleAttributeName : paragraphStyle,
   };
 
@@ -176,6 +180,16 @@
 
   [self addSubview:_backgroundView];
   [self sendSubviewToBack:_backgroundView];
+
+  if (IsKeyboardAccessoryUpgradeEnabled()) {
+    [NSLayoutConstraint activateConstraints:@[
+      [_backgroundView.heightAnchor
+          constraintGreaterThanOrEqualToConstant:kChipMinSize],
+      [_backgroundView.widthAnchor
+          constraintGreaterThanOrEqualToConstant:kChipMinSize],
+    ]];
+  }
+
   [NSLayoutConstraint activateConstraints:@[
     [_backgroundView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
     [_backgroundView.trailingAnchor
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/chip_button_unittest.mm b/ios/chrome/browser/ui/autofill/manual_fill/chip_button_unittest.mm
index ac4b748..84ae1dcbf 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/chip_button_unittest.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/chip_button_unittest.mm
@@ -25,7 +25,8 @@
 // Tests that the chip button has the expected configuration after its title is
 // set.
 TEST_F(ChipButtonTest, SetTitle) {
-  UIFont* font = [UIFont systemFontOfSize:14 weight:UIFontWeightMedium];
+  UIFont* font = [[UIFontMetrics defaultMetrics]
+      scaledFontForFont:[UIFont systemFontOfSize:14 weight:UIFontWeightMedium]];
   NSString* title = @"Title";
 
   {
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_mediator_unittest.mm b/ios/chrome/browser/ui/ntp/new_tab_page_mediator_unittest.mm
index 1963136..9d49b1a 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_mediator_unittest.mm
@@ -234,41 +234,9 @@
                                         1);
 }
 
-// Tests that the feed will be hidden when IOSHideFeedWithSearchChoice is
-// enabled and a non-Google search engine is chosen.
-TEST_F(NewTabPageMediatorTest, TestHideFeedWithSearchChoice) {
-  scoped_feature_list_.InitWithFeaturesAndParameters(
-      {
-          {kIOSHideFeedWithSearchChoice,
-           {{kIOSHideFeedWithSearchChoiceTargeted, "false"}}},
-      },
-      {});
-
-  // Test it with the default search engine.
-  [mediator_ setUp];
-  EXPECT_TRUE(mediator_.feedHeaderVisible);
-
-  // Set up expectation for custom search engine.
-  id feed_control_delegate = OCMProtocolMock(@protocol(FeedControlDelegate));
-  OCMExpect([feed_control_delegate setFeedAndHeaderVisibility:NO]);
-  mediator_.feedControlDelegate = feed_control_delegate;
-
-  // Test setting a custom search engine.
-  SetCustomSearchEngine();
-  EXPECT_FALSE(mediator_.feedHeaderVisible);
-  EXPECT_OCMOCK_VERIFY(feed_control_delegate);
-}
-
-// Tests that the feed will be hidden when IOSHideFeedWithSearchChoice is
-// enabled and a non-Google search engine is chosen, but only in EEA countries.
+// Tests that the feed will be hidden when a non-Google search engine is chosen,
+// but only in EEA countries.
 TEST_F(NewTabPageMediatorTest, TestHideFeedWithSearchChoiceTargeted) {
-  scoped_feature_list_.InitWithFeaturesAndParameters(
-      {
-          {kIOSHideFeedWithSearchChoice,
-           {{kIOSHideFeedWithSearchChoiceTargeted, "true"}}},
-      },
-      {});
-
   // Test it with the default search engine, with country set to France.
   OverrideSearchEngineChoiceCountry("FR");
   [mediator_ setUp];
diff --git a/ios/chrome/test/wpt/tools/run_cwt_chromedriver.py b/ios/chrome/test/wpt/tools/run_cwt_chromedriver.py
index b9ec8754..34309bf 100755
--- a/ios/chrome/test/wpt/tools/run_cwt_chromedriver.py
+++ b/ios/chrome/test/wpt/tools/run_cwt_chromedriver.py
@@ -42,13 +42,7 @@
 parser.set_defaults(asan_build=False)
 parser.add_argument('--version', help='Get the version of current browser app.',
     action='store_true')
-parser.add_argument('--enable-chrome-logs', action='store_true',
-    help='No-op, recognized as an argument for compatiblity with ChromeDriver')
-parser.add_argument('--verbose', action='store_true',
-    help='No-op, recognized as an argument for compatiblity with ChromeDriver')
-parser.add_argument('--log-path',
-    help='No-op, recognized as an argument for compatiblity with ChromeDriver')
-args=parser.parse_args()
+args, _ = parser.parse_known_args()
 
 test_app = os.path.join(
     args.build_dir, 'ios_cwt_chromedriver_tests_module-Runner.app')
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index 0654ff61..7946a92 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -360,6 +360,7 @@
     "video_frame_pool.h",
     "video_renderer.cc",
     "video_renderer.h",
+    "video_renderer_sink.h",
     "video_thumbnail_decoder.cc",
     "video_thumbnail_decoder.h",
     "video_transformation.cc",
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index fd2df22..d4416bb 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -1863,7 +1863,8 @@
 }
 
 bool IsMultiPlaneFormatForHardwareVideoEnabled() {
-#if BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_APPLE)
+#if BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+    BUILDFLAG(IS_CHROMEOS)
   return true;
 #else
   return
diff --git a/media/base/stream_parser_buffer.cc b/media/base/stream_parser_buffer.cc
index ac53d42..dda8a20 100644
--- a/media/base/stream_parser_buffer.cc
+++ b/media/base/stream_parser_buffer.cc
@@ -8,6 +8,7 @@
 
 #include "base/check_op.h"
 #include "base/memory/ptr_util.h"
+#include "media/base/media_client.h"
 #include "media/base/timestamp_constants.h"
 
 namespace media {
@@ -23,6 +24,14 @@
     bool is_key_frame,
     Type type,
     TrackId track_id) {
+  if (auto* media_client = GetMediaClient()) {
+    if (auto* alloc = media_client->GetMediaAllocator()) {
+      auto data_span = UNSAFE_BUFFERS(
+          base::span(data, base::checked_cast<size_t>(data_size)));
+      return StreamParserBuffer::FromExternalMemory(
+          alloc->CopyFrom(data_span), is_key_frame, type, track_id);
+    }
+  }
   return base::WrapRefCounted(
       new StreamParserBuffer(data, data_size, is_key_frame, type, track_id));
 }
diff --git a/media/formats/webm/webm_cluster_parser.cc b/media/formats/webm/webm_cluster_parser.cc
index b04806d..ce4d9399 100644
--- a/media/formats/webm/webm_cluster_parser.cc
+++ b/media/formats/webm/webm_cluster_parser.cc
@@ -14,7 +14,6 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/types/optional_util.h"
 #include "media/base/decrypt_config.h"
-#include "media/base/media_client.h"
 #include "media/base/stream_parser_buffer.h"
 #include "media/base/timestamp_constants.h"
 #include "media/base/webvtt_util.h"
@@ -494,23 +493,12 @@
     return false;
   }
 
-  scoped_refptr<StreamParserBuffer> buffer;
-  if (auto* media_client = GetMediaClient()) {
-    if (auto* alloc = media_client->GetMediaAllocator()) {
-      auto data_span = UNSAFE_BUFFERS(base::span(
-          data + data_offset, base::checked_cast<size_t>(size - data_offset)));
-      buffer = StreamParserBuffer::FromExternalMemory(
-          alloc->CopyFrom(data_span), is_keyframe, buffer_type, track_num);
-    }
-  }
-  if (!buffer) {
-    // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
-    // type with remapped bytestream track numbers and allow multiple tracks as
-    // applicable. See https://crbug.com/341581.
-    buffer =
-        StreamParserBuffer::CopyFrom(data + data_offset, size - data_offset,
-                                     is_keyframe, buffer_type, track_num);
-  }
+  // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
+  // type with remapped bytestream track numbers and allow multiple tracks as
+  // applicable. See https://crbug.com/341581.
+  auto buffer =
+      StreamParserBuffer::CopyFrom(data + data_offset, size - data_offset,
+                                   is_keyframe, buffer_type, track_num);
   if (additional_size) {
     buffer->WritableSideData().alpha_data.assign(additional,
                                                  additional + additional_size);
diff --git a/media/gpu/chromeos/mailbox_video_frame_converter.cc b/media/gpu/chromeos/mailbox_video_frame_converter.cc
index b1f2c37..e10a9b0c 100644
--- a/media/gpu/chromeos/mailbox_video_frame_converter.cc
+++ b/media/gpu/chromeos/mailbox_video_frame_converter.cc
@@ -462,14 +462,13 @@
   mailbox_frame->set_color_space(frame->ColorSpace());
   mailbox_frame->set_hdr_metadata(frame->hdr_metadata());
   mailbox_frame->set_metadata(frame->metadata());
-  if (IsMultiPlaneFormatForHardwareVideoEnabled()) {
-    auto si_format = GetSharedImageFormat(*buffer_format);
+
+  auto si_format = GetSharedImageFormat(*buffer_format);
+  mailbox_frame->set_shared_image_format_type(
+      media::SharedImageFormatType::kSharedImageFormat);
+  if (si_format.PrefersExternalSampler()) {
     mailbox_frame->set_shared_image_format_type(
-        media::SharedImageFormatType::kSharedImageFormat);
-    if (si_format.PrefersExternalSampler()) {
-      mailbox_frame->set_shared_image_format_type(
-          media::SharedImageFormatType::kSharedImageFormatExternalSampler);
-    }
+        media::SharedImageFormatType::kSharedImageFormatExternalSampler);
   }
   mailbox_frame->metadata().read_lock_fences_enabled = true;
   mailbox_frame->metadata().is_webgpu_compatible =
@@ -599,19 +598,12 @@
     shared_image_usage |= gpu::SHARED_IMAGE_USAGE_WEBGPU_READ;
   }
 
-  gpu::SharedImageStub::SharedImageDestructionCallback destroy_shared_image_cb;
-  if (IsMultiPlaneFormatForHardwareVideoEnabled()) {
-    destroy_shared_image_cb = gpu_delegate_->CreateSharedImage(
-        mailbox, std::move(gpu_memory_buffer_handle),
-        GetSharedImageFormat(*buffer_format), shared_image_size,
-        src_color_space, kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
-        shared_image_usage);
-  } else {
-    destroy_shared_image_cb = gpu_delegate_->CreateSharedImage(
-        mailbox, std::move(gpu_memory_buffer_handle), *buffer_format,
-        gfx::BufferPlane::DEFAULT, shared_image_size, src_color_space,
-        kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, shared_image_usage);
-  }
+  gpu::SharedImageStub::SharedImageDestructionCallback destroy_shared_image_cb =
+      gpu_delegate_->CreateSharedImage(
+          mailbox, std::move(gpu_memory_buffer_handle),
+          GetSharedImageFormat(*buffer_format), shared_image_size,
+          src_color_space, kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+          shared_image_usage);
   if (destroy_shared_image_cb.is_null()) {
     OnError(FROM_HERE, "Failed to create shared image.");
     return false;
diff --git a/media/gpu/chromeos/mailbox_video_frame_converter_unittest.cc b/media/gpu/chromeos/mailbox_video_frame_converter_unittest.cc
index 45724602..b6d228b 100644
--- a/media/gpu/chromeos/mailbox_video_frame_converter_unittest.cc
+++ b/media/gpu/chromeos/mailbox_video_frame_converter_unittest.cc
@@ -225,31 +225,17 @@
     {
       InSequence sequence;
       EXPECT_CALL(*mock_gpu_delegate_, Initialize()).WillOnce(Return(true));
-      if (IsMultiPlaneFormatForHardwareVideoEnabled()) {
-        viz::SharedImageFormat shared_image_format =
-            viz::MultiPlaneFormat::kNV12;
-        shared_image_format.SetPrefersExternalSampler();
-        EXPECT_CALL(
-            *mock_gpu_delegate_,
-            CreateSharedImage(
-                /*mailbox=*/_, /*handle=*/_, shared_image_format,
-                /*size=*/kVisibleRect.size(), /*color_space=*/_,
-                kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, /*usage=*/_))
-            .WillOnce(DoAll(
-                SaveArg<0>(&mailboxes_seen_by_gpu_delegate[i]),
-                Return(ByMove(mock_destroy_shared_image_cbs_[i]->Get()))));
-      } else {
-        EXPECT_CALL(
-            *mock_gpu_delegate_,
-            CreateSharedImage(
-                /*mailbox=*/_, /*handle=*/_, kBufferFormat,
-                gfx::BufferPlane::DEFAULT,
-                /*size=*/kVisibleRect.size(), /*color_space=*/_,
-                kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, /*usage=*/_))
-            .WillOnce(DoAll(
-                SaveArg<0>(&mailboxes_seen_by_gpu_delegate[i]),
-                Return(ByMove(mock_destroy_shared_image_cbs_[i]->Get()))));
-      }
+      viz::SharedImageFormat shared_image_format = viz::MultiPlaneFormat::kNV12;
+      shared_image_format.SetPrefersExternalSampler();
+      EXPECT_CALL(
+          *mock_gpu_delegate_,
+          CreateSharedImage(
+              /*mailbox=*/_, /*handle=*/_, shared_image_format,
+              /*size=*/kVisibleRect.size(), /*color_space=*/_,
+              kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, /*usage=*/_))
+          .WillOnce(
+              DoAll(SaveArg<0>(&mailboxes_seen_by_gpu_delegate[i]),
+                    Return(ByMove(mock_destroy_shared_image_cbs_[i]->Get()))));
       EXPECT_CALL(mock_output_cb_, Run(_))
           .WillOnce(SaveArg<0>(&converted_frames[i]));
     }
diff --git a/media/video/renderable_gpu_memory_buffer_video_frame_pool_unittest.cc b/media/video/renderable_gpu_memory_buffer_video_frame_pool_unittest.cc
index 5c15e0ff..ba66e44 100644
--- a/media/video/renderable_gpu_memory_buffer_video_frame_pool_unittest.cc
+++ b/media/video/renderable_gpu_memory_buffer_video_frame_pool_unittest.cc
@@ -462,7 +462,8 @@
     All,
     RenderableGpuMemoryBufferVideoFramePoolTest,
     testing::Combine(
-#if BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_APPLE)
+#if BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+    BUILDFLAG(IS_CHROMEOS)
         // kUseMultiPlaneFormatForHardwareVideo experiment has been enabled on
         // Fuchsia and Mac fully and codepath is deleted.
         testing::Values(true),
diff --git a/remoting/host/x11_desktop_resizer.cc b/remoting/host/x11_desktop_resizer.cc
index 91e8a9b..513b707 100644
--- a/remoting/host/x11_desktop_resizer.cc
+++ b/remoting/host/x11_desktop_resizer.cc
@@ -7,6 +7,7 @@
 #include <gio/gio.h>
 
 #include <algorithm>
+#include <iterator>
 #include <memory>
 #include <string>
 #include <utility>
@@ -137,6 +138,24 @@
   return 60 * 1e6;
 }
 
+// Gets current layout with context information from a list of monitors.
+std::vector<remoting::DesktopLayoutWithContext> GetLayoutWithContext(
+    std::vector<x11::RandR::MonitorInfo>& monitors) {
+  std::vector<remoting::DesktopLayoutWithContext> current_displays;
+  for (auto& monitor : monitors) {
+    // This implementation only supports resizing synthesized Monitors which
+    // automatically track their Outputs.
+    // TODO(crbug.com/1326339): Maybe support resizing manually-created
+    // monitors?
+    if (monitor.automatic) {
+      current_displays.push_back(
+          {.layout = remoting::ToVideoTrackLayout(monitor),
+           .context = &monitor});
+    }
+  }
+  return current_displays;
+}
+
 }  // namespace
 
 namespace remoting {
@@ -253,18 +272,14 @@
   // that the display configuration doesn't change under our feet.
   ScopedXGrabServer grabber(connection_);
 
-  if (!resources_.Refresh(randr_, root_)) {
-    return;
-  }
-
   // RANDR does not allow fetching information on a particular monitor. So
   // fetch all of them and try to find the requested monitor.
-  auto reply = randr_->GetMonitors({root_}).Sync();
-  if (!reply) {
+  std::vector<x11::RandR::MonitorInfo> monitors;
+  if (!TryGetCurrentMonitors(monitors)) {
     return;
   }
 
-  for (const auto& monitor : reply->monitors) {
+  for (const auto& monitor : monitors) {
     if (static_cast<DesktopScreenId>(monitor.name) != screen_id) {
       continue;
     }
@@ -301,38 +316,32 @@
   SetResolution(original, screen_id);
 }
 
-std::vector<DesktopLayoutWithContext>
-X11DesktopResizer::GetLayoutWithContext() {
+bool X11DesktopResizer::TryGetCurrentMonitors(
+    std::vector<x11::RandR::MonitorInfo>& list) {
   if (!has_randr_ || !is_virtual_session_) {
-    return std::vector<DesktopLayoutWithContext>();
+    return false;
   }
 
   if (!resources_.Refresh(randr_, root_)) {
-    return std::vector<DesktopLayoutWithContext>();
+    return false;
   }
 
   auto reply = randr_->GetMonitors({root_}).Sync();
   if (!reply) {
-    return std::vector<DesktopLayoutWithContext>();
+    return false;
   }
-
-  std::vector<DesktopLayoutWithContext> current_displays;
-  for (auto& monitor : reply->monitors) {
-    // This implementation only supports resizing synthesized Monitors which
-    // automatically track their Outputs.
-    // TODO(crbug.com/1326339): Maybe support resizing manually-created
-    // monitors?
-    if (monitor.automatic) {
-      current_displays.push_back(
-          {.layout = ToVideoTrackLayout(monitor), .context = &monitor});
-    }
-  }
-  return current_displays;
+  std::copy(reply->monitors.begin(), reply->monitors.end(),
+            std::back_inserter(list));
+  return true;
 }
 
 DesktopLayoutSet X11DesktopResizer::GetLayout() {
   DesktopLayoutSet result;
-  for (const auto& layout : GetLayoutWithContext()) {
+  std::vector<x11::RandR::MonitorInfo> monitors;
+  if (!TryGetCurrentMonitors(monitors)) {
+    return DesktopLayoutSet();
+  }
+  for (const auto& layout : GetLayoutWithContext(monitors)) {
     result.layouts.emplace_back(layout.layout);
   }
   return result;
@@ -346,9 +355,12 @@
   // that the display configuration doesn't change under our feet.
   ScopedXGrabServer grabber(connection_);
 
-  std::vector<x11::RandR::MonitorInfo> monitor_infos;
+  std::vector<x11::RandR::MonitorInfo> monitors;
+  if (!TryGetCurrentMonitors(monitors)) {
+    return;
+  }
   std::vector<DesktopLayoutWithContext> current_displays =
-      GetLayoutWithContext();
+      GetLayoutWithContext(monitors);
 
   // TODO(yuweih): Verify that the layout is valid, e.g. no overlaps or gaps
   // between displays.
diff --git a/remoting/host/x11_desktop_resizer.h b/remoting/host/x11_desktop_resizer.h
index 05b5eff2..9f0469e7 100644
--- a/remoting/host/x11_desktop_resizer.h
+++ b/remoting/host/x11_desktop_resizer.h
@@ -15,7 +15,6 @@
 #include "base/timer/timer.h"
 #include "remoting/host/desktop_display_layout_util.h"
 #include "remoting/host/desktop_geometry.h"
-#include "remoting/host/desktop_resizer.h"
 #include "remoting/host/linux/gnome_display_config_dbus_client.h"
 #include "remoting/host/linux/scoped_glib.h"
 #include "ui/gfx/geometry/point.h"
@@ -87,8 +86,10 @@
   // Gets a list of outputs that are not connected to any CRTCs.
   OutputInfoList GetDisabledOutputs();
 
-  // Gets current layout with context information.
-  std::vector<DesktopLayoutWithContext> GetLayoutWithContext();
+  // Attempts to get the current list of XRandR monitors from the current
+  // connection. Returns true on success in which case `list` is populated with
+  // the monitors. Returns false otherwise.
+  bool TryGetCurrentMonitors(std::vector<x11::RandR::MonitorInfo>& list);
 
   void RequestGnomeDisplayConfig();
   void OnGnomeDisplayConfigReceived(GnomeDisplayConfig config);
diff --git a/services/accessibility/android/ax_tree_source_android_unittest.cc b/services/accessibility/android/ax_tree_source_android_unittest.cc
index 409e42e..a09789f 100644
--- a/services/accessibility/android/ax_tree_source_android_unittest.cc
+++ b/services/accessibility/android/ax_tree_source_android_unittest.cc
@@ -76,7 +76,7 @@
   }
 
   void DispatchAccessibilityLocationChange(
-      const ui::AXLocationChangeNotificationDetails& details) override {}
+      const ui::AXLocationChanges& details) override {}
 
   void DispatchTreeDestroyedEvent(ui::AXTreeID tree_id) override {}
 
diff --git a/services/device/BUILD.gn b/services/device/BUILD.gn
index c3e21dd..bde279c9 100644
--- a/services/device/BUILD.gn
+++ b/services/device/BUILD.gn
@@ -5,6 +5,7 @@
 import("//build/config/chromeos/ui_mode.gni")
 import("//build/config/chromeos/ui_mode.gni")
 import("//build/config/features.gni")
+import("//services/device/public/cpp/geolocation/buildflags.gni")
 import("//testing/test.gni")
 
 if (is_android) {
@@ -204,7 +205,7 @@
     ]
   }
 
-  if (is_chromeos || is_mac) {
+  if (os_level_geolocation_permission_supported) {
     sources += [ "public/cpp/geolocation/geolocation_system_permission_manager_unittest.cc" ]
   }
 
diff --git a/services/device/public/cpp/BUILD.gn b/services/device/public/cpp/BUILD.gn
index 63202c0..d3f07be 100644
--- a/services/device/public/cpp/BUILD.gn
+++ b/services/device/public/cpp/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/config/features.gni")
+import("//services/device/public/cpp/geolocation/buildflags.gni")
 
 component("device_features") {
   public = [ "device_features.h" ]
@@ -75,7 +76,7 @@
     "//url",
   ]
 
-  if (is_apple || is_chromeos) {
+  if (os_level_geolocation_permission_supported || is_ios) {
     sources += [
       "test/fake_geolocation_system_permission_manager.cc",
       "test/fake_geolocation_system_permission_manager.h",
diff --git a/services/device/public/cpp/geolocation/BUILD.gn b/services/device/public/cpp/geolocation/BUILD.gn
index 3998ae2..d0e4911 100644
--- a/services/device/public/cpp/geolocation/BUILD.gn
+++ b/services/device/public/cpp/geolocation/BUILD.gn
@@ -37,11 +37,10 @@
   }
 
   public_deps = [
+    ":buildflags",
     "//base",
     "//services/device/public/mojom",
     "//services/device/public/mojom:geolocation_internals",
     "//third_party/abseil-cpp:absl",
   ]
-
-  deps = [ ":buildflags" ]
 }
diff --git a/services/webnn/coreml/graph_builder.cc b/services/webnn/coreml/graph_builder.cc
index cfe291e..d2bc5f1 100644
--- a/services/webnn/coreml/graph_builder.cc
+++ b/services/webnn/coreml/graph_builder.cc
@@ -124,11 +124,21 @@
 constexpr char kOpAvgPoolTypeName[] = "avg_pool";
 constexpr char kOpL2PoolTypeName[] = "l2_pool";
 constexpr char kOpMaxPoolTypeName[] = "max_pool";
+// Reduction operators.
+constexpr char kOpReduceL1[] = "reduce_l1_norm";
+constexpr char kOpReduceL2[] = "reduce_l2_norm";
+constexpr char kOpReduceLogSum[] = "reduce_log_sum";
+constexpr char kOpReduceLogSumExp[] = "reduce_log_sum_exp";
+constexpr char kOpReduceMax[] = "reduce_max";
+constexpr char kOpReduceMean[] = "reduce_mean";
+constexpr char kOpReduceMin[] = "reduce_min";
+constexpr char kOpReduceProduct[] = "reduce_prod";
+constexpr char kOpReduceSum[] = "reduce_sum";
+constexpr char kOpReduceSumSquare[] = "reduce_sum_square";
 // Resample2d operators.
 constexpr char kOpUpsampleBilinearTypeName[] = "upsample_bilinear";
 constexpr char kOpUpsampleNearestNeighborTypeName[] =
     "upsample_nearest_neighbor";
-
 // General op params that are shared across multiple ops.
 constexpr char kOpParamX[] = "x";
 constexpr char kOpParamY[] = "y";
@@ -581,6 +591,10 @@
         RETURN_IF_ERROR(AddOperationForPool2d(*operation->get_pool2d(), block));
         break;
       }
+      case mojom::Operation::Tag::kReduce: {
+        RETURN_IF_ERROR(AddOperationForReduce(*operation->get_reduce(), block));
+        break;
+      }
       case mojom::Operation::Tag::kRelu: {
         RETURN_IF_ERROR(AddOperationForRelu(*operation->get_relu(), block));
         break;
@@ -628,7 +642,6 @@
       case mojom::Operation::Tag::kMatmul:
       case mojom::Operation::Tag::kPad:
       case mojom::Operation::Tag::kPrelu:
-      case mojom::Operation::Tag::kReduce:
       case mojom::Operation::Tag::kReshape:
       case mojom::Operation::Tag::kSlice:
       case mojom::Operation::Tag::kSoftmax:
@@ -1178,6 +1191,69 @@
   return base::ok();
 }
 
+base::expected<void, mojom::ErrorPtr> GraphBuilder::AddOperationForReduce(
+    const mojom::Reduce& operation,
+    CoreML::Specification::MILSpec::Block& block) {
+  CoreML::Specification::MILSpec::Operation* op = block.add_operations();
+  const OperandInfo& input_operand_info =
+      GetOperandInfo(operation.input_operand_id);
+
+  if (!kFloatsAndInt32DataTypes.contains(input_operand_info.mil_data_type)) {
+    return NewNotSupportedError("Unsupported input datatype.");
+  }
+
+  SetInputWithName(*op->mutable_inputs(), kOpParamX,
+                   input_operand_info.coreml_name);
+
+  switch (operation.kind) {
+    case mojom::Reduce::Kind::kL1:
+      op->set_type(kOpReduceL1);
+      break;
+    case mojom::Reduce::Kind::kL2:
+      op->set_type(kOpReduceL2);
+      break;
+    case mojom::Reduce::Kind::kLogSum:
+      op->set_type(kOpReduceLogSum);
+      break;
+    case mojom::Reduce::Kind::kLogSumExp:
+      op->set_type(kOpReduceLogSumExp);
+      break;
+    case mojom::Reduce::Kind::kMax:
+      op->set_type(kOpReduceMax);
+      break;
+    case mojom::Reduce::Kind::kMean:
+      op->set_type(kOpReduceMean);
+      break;
+    case mojom::Reduce::Kind::kMin:
+      op->set_type(kOpReduceMin);
+      break;
+    case mojom::Reduce::Kind::kProduct:
+      op->set_type(kOpReduceProduct);
+      break;
+    case mojom::Reduce::Kind::kSum:
+      op->set_type(kOpReduceSum);
+      break;
+    case mojom::Reduce::Kind::kSumSquare:
+      op->set_type(kOpReduceSumSquare);
+      break;
+  }
+
+  constexpr char kParamAxes[] = "axes";
+  constexpr char kParamKeepDims[] = "keep_dims";
+  PopulateNamedValueType(operation.output_operand_id, *op->add_outputs());
+
+  std::vector<int32_t> axes;
+  base::ranges::transform(
+      operation.axes, std::back_inserter(axes),
+      [](uint32_t val) { return base::checked_cast<int32_t>(val); });
+  SetInputsWithValues(
+      *op->mutable_inputs(),
+      {{kParamAxes, Create1DTensorImmediateValue<int32_t>(axes)},
+       {kParamKeepDims,
+        CreateScalarImmediateValue(operation.keep_dimensions)}});
+  return base::ok();
+}
+
 base::expected<void, mojom::ErrorPtr> GraphBuilder::AddOperationForRelu(
     const mojom::Relu& operation,
     CoreML::Specification::MILSpec::Block& block) {
diff --git a/services/webnn/coreml/graph_builder.h b/services/webnn/coreml/graph_builder.h
index bf9bc4dd..79a860c 100644
--- a/services/webnn/coreml/graph_builder.h
+++ b/services/webnn/coreml/graph_builder.h
@@ -159,6 +159,9 @@
   [[nodiscard]] base::expected<void, mojom::ErrorPtr> AddOperationForPool2d(
       const mojom::Pool2d& operation,
       CoreML::Specification::MILSpec::Block& block);
+  [[nodiscard]] base::expected<void, mojom::ErrorPtr> AddOperationForReduce(
+      const mojom::Reduce& operation,
+      CoreML::Specification::MILSpec::Block& block);
   [[nodiscard]] base::expected<void, mojom::ErrorPtr> AddOperationForRelu(
       const mojom::Relu& operation,
       CoreML::Specification::MILSpec::Block& block);
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 231ae59..92bda4c6 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5454,9 +5454,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.34/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.66/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 124.0.6367.34",
+        "description": "Run with ash-chrome version 124.0.6367.66",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5466,8 +5466,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v124.0.6367.34",
-              "revision": "version:124.0.6367.34"
+              "location": "lacros_version_skew_tests_v124.0.6367.66",
+              "revision": "version:124.0.6367.66"
             }
           ],
           "dimensions": {
@@ -5610,9 +5610,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.34/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.66/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 124.0.6367.34",
+        "description": "Run with ash-chrome version 124.0.6367.66",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5622,8 +5622,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v124.0.6367.34",
-              "revision": "version:124.0.6367.34"
+              "location": "lacros_version_skew_tests_v124.0.6367.66",
+              "revision": "version:124.0.6367.66"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json
index 53cd93b..a42b0f73 100644
--- a/testing/buildbot/chromium.coverage.json
+++ b/testing/buildbot/chromium.coverage.json
@@ -15491,6 +15491,7 @@
         "name": "absl_hardening_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15506,6 +15507,7 @@
         "name": "accessibility_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15521,6 +15523,7 @@
         "name": "angle_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15537,6 +15540,7 @@
         "name": "app_shell_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15552,6 +15556,7 @@
         "name": "ash_components_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15568,6 +15573,7 @@
         "name": "ash_crosapi_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15584,6 +15590,7 @@
         "name": "ash_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -15600,6 +15607,7 @@
         "name": "ash_webui_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15615,6 +15623,7 @@
         "name": "aura_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15630,6 +15639,7 @@
         "name": "base_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15645,6 +15655,7 @@
         "name": "blink_common_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15660,6 +15671,7 @@
         "name": "blink_fuzzer_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15675,6 +15687,7 @@
         "name": "blink_heap_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15698,6 +15711,7 @@
         ],
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15713,6 +15727,7 @@
         "name": "boringssl_crypto_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15728,6 +15743,7 @@
         "name": "boringssl_ssl_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15743,6 +15759,7 @@
         "name": "browser_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -15762,6 +15779,7 @@
         "name": "capture_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15777,6 +15795,7 @@
         "name": "cast_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15792,6 +15811,7 @@
         "name": "cc_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15807,6 +15827,7 @@
         "name": "chrome_app_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15822,6 +15843,7 @@
         "name": "chromedriver_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15837,6 +15859,7 @@
         "name": "chromeos_components_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15852,6 +15875,7 @@
         "name": "chromeos_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15867,6 +15891,7 @@
         "name": "components_browsertests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15882,6 +15907,7 @@
         "name": "components_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15897,6 +15923,7 @@
         "name": "compositor_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15912,6 +15939,7 @@
         "name": "content_browsertests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -15928,6 +15956,7 @@
         "name": "content_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15943,6 +15972,7 @@
         "name": "crashpad_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15958,6 +15988,7 @@
         "name": "crypto_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15973,6 +16004,7 @@
         "name": "dbus_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -15988,6 +16020,7 @@
         "name": "device_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16003,6 +16036,7 @@
         "name": "display_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16019,6 +16053,7 @@
         "name": "env_chromium_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16034,6 +16069,7 @@
         "name": "events_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16049,6 +16085,7 @@
         "name": "exo_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16064,6 +16101,7 @@
         "name": "extensions_browsertests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16079,6 +16117,7 @@
         "name": "extensions_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16094,6 +16133,7 @@
         "name": "filesystem_service_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16109,6 +16149,7 @@
         "name": "gcm_unit_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16124,6 +16165,7 @@
         "name": "gfx_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16139,6 +16181,7 @@
         "name": "gin_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16154,6 +16197,7 @@
         "name": "gl_unittests_ozone",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16169,6 +16213,7 @@
         "name": "google_apis_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16184,6 +16229,7 @@
         "name": "gpu_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16199,6 +16245,7 @@
         "name": "gwp_asan_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16214,6 +16261,7 @@
         "name": "interactive_ui_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -16230,6 +16278,7 @@
         "name": "ipc_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16245,6 +16294,7 @@
         "name": "keyboard_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16260,6 +16310,7 @@
         "name": "latency_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16276,6 +16327,7 @@
         "name": "leveldb_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16291,6 +16343,7 @@
         "name": "libjingle_xmpp_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16306,6 +16359,7 @@
         "name": "liburlpattern_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16321,6 +16375,7 @@
         "name": "media_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16336,6 +16391,7 @@
         "name": "message_center_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16351,6 +16407,7 @@
         "name": "midi_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16366,6 +16423,7 @@
         "name": "mojo_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16381,6 +16439,7 @@
         "name": "nacl_loader_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16396,6 +16455,7 @@
         "name": "native_theme_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16411,6 +16471,7 @@
         "name": "net_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16429,6 +16490,7 @@
         "name": "ozone_gl_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16444,6 +16506,7 @@
         "name": "ozone_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16459,6 +16522,7 @@
         "name": "ozone_x11_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16474,6 +16538,7 @@
         "name": "pdf_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16489,6 +16554,7 @@
         "name": "perfetto_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16504,6 +16570,7 @@
         "name": "ppapi_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16519,6 +16586,7 @@
         "name": "printing_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16535,6 +16603,7 @@
         "name": "pthreadpool_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16550,6 +16619,7 @@
         "name": "remoting_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16565,6 +16635,7 @@
         "name": "sandbox_linux_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16580,6 +16651,7 @@
         "name": "services_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16595,6 +16667,7 @@
         "name": "shell_dialogs_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16610,6 +16683,7 @@
         "name": "shell_encryption_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16625,6 +16699,7 @@
         "name": "skia_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16640,6 +16715,7 @@
         "name": "snapshot_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16655,6 +16731,7 @@
         "name": "sql_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16670,6 +16747,7 @@
         "name": "storage_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16685,6 +16763,7 @@
         "name": "sync_integration_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -16701,6 +16780,7 @@
         "name": "ui_base_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16716,6 +16796,7 @@
         "name": "ui_chromeos_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16731,6 +16812,7 @@
         "name": "ui_touch_selection_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16746,6 +16828,7 @@
         "name": "ui_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16761,6 +16844,7 @@
         "name": "unit_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16776,6 +16860,7 @@
         "name": "url_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16792,6 +16877,7 @@
         "name": "usage_time_limit_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16807,6 +16893,7 @@
         "name": "views_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16822,6 +16909,7 @@
         "name": "viz_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16837,6 +16925,7 @@
         "name": "wayland_client_perftests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16852,6 +16941,7 @@
         "name": "wayland_client_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16867,6 +16957,7 @@
         "name": "webkit_unit_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16882,6 +16973,7 @@
         "name": "wm_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16897,6 +16989,7 @@
         "name": "wtf_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -16912,6 +17005,7 @@
         "name": "zlib_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -18928,6 +19022,7 @@
         "name": "absl_hardening_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -18943,6 +19038,7 @@
         "name": "accessibility_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -18958,6 +19054,7 @@
         "name": "app_shell_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -18973,6 +19070,7 @@
         "name": "aura_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -18988,6 +19086,7 @@
         "name": "base_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19003,6 +19102,7 @@
         "name": "blink_common_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19018,6 +19118,7 @@
         "name": "blink_fuzzer_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19033,6 +19134,7 @@
         "name": "blink_heap_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19056,6 +19158,7 @@
         ],
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19071,6 +19174,7 @@
         "name": "boringssl_crypto_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19086,6 +19190,7 @@
         "name": "boringssl_ssl_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19101,6 +19206,7 @@
         "name": "browser_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -19120,6 +19226,7 @@
         "name": "capture_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19135,6 +19242,7 @@
         "name": "cast_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19150,6 +19258,7 @@
         "name": "cc_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19165,6 +19274,7 @@
         "name": "chrome_app_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19180,6 +19290,7 @@
         "name": "chromedriver_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19195,6 +19306,7 @@
         "name": "chromeos_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19210,6 +19322,7 @@
         "name": "components_browsertests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19225,6 +19338,7 @@
         "name": "components_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19240,6 +19354,7 @@
         "name": "compositor_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19255,6 +19370,7 @@
         "name": "content_browsertests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -19271,6 +19387,7 @@
         "name": "content_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19286,6 +19403,7 @@
         "name": "crashpad_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19301,6 +19419,7 @@
         "name": "crypto_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19316,6 +19435,7 @@
         "name": "dbus_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19331,6 +19451,7 @@
         "name": "device_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19346,6 +19467,7 @@
         "name": "display_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19362,6 +19484,7 @@
         "name": "env_chromium_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19377,6 +19500,7 @@
         "name": "events_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19395,6 +19519,7 @@
         "name": "extensions_browsertests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19413,6 +19538,7 @@
         "name": "extensions_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19428,6 +19554,7 @@
         "name": "filesystem_service_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19443,6 +19570,7 @@
         "name": "gcm_unit_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19458,6 +19586,7 @@
         "name": "gfx_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19473,6 +19602,7 @@
         "name": "gin_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19488,6 +19618,7 @@
         "name": "google_apis_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19503,6 +19634,7 @@
         "name": "gpu_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19518,6 +19650,7 @@
         "name": "gwp_asan_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19533,6 +19666,7 @@
         "name": "interactive_ui_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -19544,9 +19678,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.34/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.66/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 124.0.6367.34",
+        "description": "Run with ash-chrome version 124.0.6367.66",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -19556,11 +19690,12 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v124.0.6367.34",
-              "revision": "version:124.0.6367.34"
+              "location": "lacros_version_skew_tests_v124.0.6367.66",
+              "revision": "version:124.0.6367.66"
             }
           ],
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -19590,6 +19725,7 @@
             }
           ],
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -19619,6 +19755,7 @@
             }
           ],
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -19648,6 +19785,7 @@
             }
           ],
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -19665,6 +19803,7 @@
         "name": "ipc_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19683,6 +19822,7 @@
         "name": "lacros_chrome_browsertests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -19694,9 +19834,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.34/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.66/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 124.0.6367.34",
+        "description": "Run with ash-chrome version 124.0.6367.66",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -19706,11 +19846,12 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v124.0.6367.34",
-              "revision": "version:124.0.6367.34"
+              "location": "lacros_version_skew_tests_v124.0.6367.66",
+              "revision": "version:124.0.6367.66"
             }
           ],
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -19740,6 +19881,7 @@
             }
           ],
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -19769,6 +19911,7 @@
             }
           ],
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -19798,6 +19941,7 @@
             }
           ],
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -19815,6 +19959,7 @@
         "name": "latency_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19831,6 +19976,7 @@
         "name": "leveldb_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19846,6 +19992,7 @@
         "name": "libjingle_xmpp_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19861,6 +20008,7 @@
         "name": "liburlpattern_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19876,6 +20024,7 @@
         "name": "media_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19891,6 +20040,7 @@
         "name": "message_center_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19906,6 +20056,7 @@
         "name": "midi_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19921,6 +20072,7 @@
         "name": "mojo_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19936,6 +20088,7 @@
         "name": "nacl_loader_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19951,6 +20104,7 @@
         "name": "native_theme_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19966,6 +20120,7 @@
         "name": "net_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19981,6 +20136,7 @@
         "name": "ozone_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -19996,6 +20152,7 @@
         "name": "pdf_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20011,6 +20168,7 @@
         "name": "perfetto_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20026,6 +20184,7 @@
         "name": "ppapi_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20041,6 +20200,7 @@
         "name": "printing_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20057,6 +20217,7 @@
         "name": "pthreadpool_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20072,6 +20233,7 @@
         "name": "remoting_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20087,6 +20249,7 @@
         "name": "sandbox_linux_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20102,6 +20265,7 @@
         "name": "services_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20117,6 +20281,7 @@
         "name": "shell_dialogs_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20132,6 +20297,7 @@
         "name": "skia_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20147,6 +20313,7 @@
         "name": "snapshot_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20162,6 +20329,7 @@
         "name": "sql_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20177,6 +20345,7 @@
         "name": "storage_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20192,6 +20361,7 @@
         "name": "sync_integration_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -20208,6 +20378,7 @@
         "name": "ui_base_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20223,6 +20394,7 @@
         "name": "ui_touch_selection_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20238,6 +20410,7 @@
         "name": "ui_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20253,6 +20426,7 @@
         "name": "unit_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20268,6 +20442,7 @@
         "name": "url_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20286,6 +20461,7 @@
         "name": "views_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20301,6 +20477,7 @@
         "name": "viz_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20316,6 +20493,7 @@
         "name": "webkit_unit_tests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20331,6 +20509,7 @@
         "name": "wm_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20346,6 +20525,7 @@
         "name": "wtf_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -20361,6 +20541,7 @@
         "name": "zlib_unittests",
         "swarming": {
           "dimensions": {
+            "cpu": "x86-64",
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 9f9da21c..c184bbba 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -3965,6 +3965,56 @@
       {
         "args": [
           "--test-launcher-bot-mode",
+          "--test-launcher-filter-file=testing/buildbot/filters/ios.use_blink.components_browsertests.filter",
+          "--platform",
+          "iPhone 14",
+          "--version",
+          "17.4",
+          "--out-dir",
+          "${ISOLATED_OUTDIR}",
+          "--xcode-build-version",
+          "15e204a",
+          "--xctest"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "components_browsertests iPhone 14 17.4",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/mac_toolchain/${platform}",
+              "location": ".",
+              "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0"
+            }
+          ],
+          "dimensions": {
+            "cpu": "arm64",
+            "os": "Mac-13|Mac-14"
+          },
+          "named_caches": [
+            {
+              "name": "xcode_ios_15e204a",
+              "path": "Xcode.app"
+            },
+            {
+              "name": "runtime_ios_17_4",
+              "path": "Runtime-ios-17.4"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "components_browsertests",
+        "test_id_prefix": "ninja://components:components_browsertests/",
+        "variant_id": "iPhone 14 17.4"
+      },
+      {
+        "args": [
+          "--test-launcher-bot-mode",
           "--test-launcher-filter-file=testing/buildbot/filters/ios.use_blink.components_unittests.filter",
           "--platform",
           "iPhone 14",
@@ -41709,9 +41759,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.34/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.66/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 124.0.6367.34",
+        "description": "Run with ash-chrome version 124.0.6367.66",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -41720,8 +41770,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v124.0.6367.34",
-              "revision": "version:124.0.6367.34"
+              "location": "lacros_version_skew_tests_v124.0.6367.66",
+              "revision": "version:124.0.6367.66"
             }
           ],
           "dimensions": {
@@ -41859,9 +41909,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.34/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.66/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 124.0.6367.34",
+        "description": "Run with ash-chrome version 124.0.6367.66",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -41870,8 +41920,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v124.0.6367.34",
-              "revision": "version:124.0.6367.34"
+              "location": "lacros_version_skew_tests_v124.0.6367.66",
+              "revision": "version:124.0.6367.66"
             }
           ],
           "dimensions": {
@@ -43207,9 +43257,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.34/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.66/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 124.0.6367.34",
+        "description": "Run with ash-chrome version 124.0.6367.66",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -43219,8 +43269,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v124.0.6367.34",
-              "revision": "version:124.0.6367.34"
+              "location": "lacros_version_skew_tests_v124.0.6367.66",
+              "revision": "version:124.0.6367.66"
             }
           ],
           "dimensions": {
@@ -43363,9 +43413,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.34/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.66/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 124.0.6367.34",
+        "description": "Run with ash-chrome version 124.0.6367.66",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -43375,8 +43425,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v124.0.6367.34",
-              "revision": "version:124.0.6367.34"
+              "location": "lacros_version_skew_tests_v124.0.6367.66",
+              "revision": "version:124.0.6367.66"
             }
           ],
           "dimensions": {
@@ -44689,9 +44739,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.34/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.66/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 124.0.6367.34",
+        "description": "Run with ash-chrome version 124.0.6367.66",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -44700,8 +44750,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v124.0.6367.34",
-              "revision": "version:124.0.6367.34"
+              "location": "lacros_version_skew_tests_v124.0.6367.66",
+              "revision": "version:124.0.6367.66"
             }
           ],
           "dimensions": {
@@ -44839,9 +44889,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.34/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.66/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 124.0.6367.34",
+        "description": "Run with ash-chrome version 124.0.6367.66",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -44850,8 +44900,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v124.0.6367.34",
-              "revision": "version:124.0.6367.34"
+              "location": "lacros_version_skew_tests_v124.0.6367.66",
+              "revision": "version:124.0.6367.66"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 580e072..b216ec2e 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -15732,12 +15732,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.34/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.66/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 124.0.6367.34",
+        "description": "Run with ash-chrome version 124.0.6367.66",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -15747,8 +15747,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v124.0.6367.34",
-              "revision": "version:124.0.6367.34"
+              "location": "lacros_version_skew_tests_v124.0.6367.66",
+              "revision": "version:124.0.6367.66"
             }
           ],
           "dimensions": {
@@ -15908,12 +15908,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.34/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.66/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 124.0.6367.34",
+        "description": "Run with ash-chrome version 124.0.6367.66",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -15923,8 +15923,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v124.0.6367.34",
-              "revision": "version:124.0.6367.34"
+              "location": "lacros_version_skew_tests_v124.0.6367.66",
+              "revision": "version:124.0.6367.66"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/filters/ios.use_blink.components_browsertests.filter b/testing/buildbot/filters/ios.use_blink.components_browsertests.filter
new file mode 100644
index 0000000..69e054a1
--- /dev/null
+++ b/testing/buildbot/filters/ios.use_blink.components_browsertests.filter
@@ -0,0 +1,16 @@
+# TODO(crbug.com/335001216): These tests are failing due to the duplicate
+# resource assertion.
+-DistilledPageJsTest.SettingsDialogTest
+-DistillerPageWebContentsTest.BasicDistillationWorks
+-DistillerPageWebContentsTest.HandlesRelativeImages
+-DistillerPageWebContentsTest.HandlesRelativeLinks
+-DistillerPageWebContentsTest.HandlesRelativeVideos
+-DistillerPageWebContentsTest.MarkupInfo
+-DistillerPageWebContentsTest.PageDestroyedBeforeFinishDistillation
+-DistillerPageWebContentsTest.TestNoContentDoesNotCrash
+-DistillerPageWebContentsTest.UsingCurrentWebContentsNotFinishedLoadingYet
+-DistillerPageWebContentsTest.UsingCurrentWebContentsReadyForDistillation
+-DistillerPageWebContentsTest.UsingCurrentWebContentsWrongUrl
+-DistillerPageWebContentsTest.VisibilityDetection
+-DomDistillerDistillablePageUtilsTest.TestIsDistillablePage
+-DomDistillerJsTest.RunJsTests
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index b339ed6..c7ef739b 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -4152,6 +4152,12 @@
           '--use-gpu-in-tests',
         ],
       },
+      'components_browsertests': {
+        'args': [
+          '--test-launcher-bot-mode',
+          '--test-launcher-filter-file=testing/buildbot/filters/ios.use_blink.components_browsertests.filter',
+        ],
+      },
       'components_unittests': {
         'args': [
           '--test-launcher-bot-mode',
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 108ec1a..d5b4c7d0 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -251,16 +251,16 @@
   },
   'LACROS_VERSION_SKEW_BETA': {
     'identifier': 'Lacros version skew testing ash beta',
-    'description': 'Run with ash-chrome version 124.0.6367.34',
+    'description': 'Run with ash-chrome version 124.0.6367.66',
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.34/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v124.0.6367.66/test_ash_chrome',
     ],
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v124.0.6367.34',
-          'revision': 'version:124.0.6367.34',
+          'location': 'lacros_version_skew_tests_v124.0.6367.66',
+          'revision': 'version:124.0.6367.66',
         },
       ],
     },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 8c4a085..59c7de2 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -2325,6 +2325,7 @@
         'mixins': [
           'isolate_profile_data',
           'linux-jammy',
+          'x86-64',
         ],
         'additional_compile_targets': [
           'gn_all',
@@ -2362,7 +2363,8 @@
         ],
         'mixins': [
           'isolate_profile_data',
-          'linux-jammy'
+          'linux-jammy',
+          'x86-64',
         ],
         'test_suites': {
           'gtest_tests': 'linux_lacros_gtests',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 37c033a..a7cf263b 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -13775,94 +13775,6 @@
             ],
             "experiments": [
                 {
-                    "name": "EnabledWithTrustedAdvice",
-                    "params": {
-                        "PasswordGenerationExperimentSurveyTriggedId": "Vm6DB1ki50ugnJ3q1cK0SpkrheAJ",
-                        "password_generation_variation": "trusted_advice",
-                        "probability": "0.25"
-                    },
-                    "enable_features": [
-                        "PasswordGenerationExperiment"
-                    ]
-                },
-                {
-                    "name": "EnabledWithSafetyFirst",
-                    "params": {
-                        "PasswordGenerationExperimentSurveyTriggedId": "sD7hmDAoo0ugnJ3q1cK0VQ2Y8p6e",
-                        "password_generation_variation": "safety_first",
-                        "probability": "0.25"
-                    },
-                    "enable_features": [
-                        "PasswordGenerationExperiment"
-                    ]
-                },
-                {
-                    "name": "EnabledWithTrySomethingNew",
-                    "params": {
-                        "PasswordGenerationExperimentSurveyTriggedId": "6QssdASS10ugnJ3q1cK0RUK4HnYU",
-                        "password_generation_variation": "try_something_new",
-                        "probability": "0.25"
-                    },
-                    "enable_features": [
-                        "PasswordGenerationExperiment"
-                    ]
-                },
-                {
-                    "name": "EnabledWithConvenience",
-                    "params": {
-                        "PasswordGenerationExperimentSurveyTriggedId": "W23VEAHCT0ugnJ3q1cK0SaPHa9J4",
-                        "password_generation_variation": "convenience",
-                        "probability": "0.25"
-                    },
-                    "enable_features": [
-                        "PasswordGenerationExperiment"
-                    ]
-                },
-                {
-                    "name": "EnabledWithCrossDevice",
-                    "params": {
-                        "PasswordGenerationExperimentSurveyTriggedId": "fRjzkFjzZ0ugnJ3q1cK0RWYBnkGK",
-                        "password_generation_variation": "cross_device",
-                        "probability": "0.25"
-                    },
-                    "enable_features": [
-                        "PasswordGenerationExperiment"
-                    ]
-                },
-                {
-                    "name": "EnabledWithChunkPassword",
-                    "params": {
-                        "PasswordGenerationExperimentSurveyTriggedId": "gnz68PSiB0ugnJ3q1cK0Y7PcR8ix",
-                        "password_generation_variation": "chunk_password",
-                        "probability": "0.25"
-                    },
-                    "enable_features": [
-                        "PasswordGenerationExperiment"
-                    ]
-                },
-                {
-                    "name": "EnabledWithNudgePassword",
-                    "params": {
-                        "PasswordGenerationExperimentSurveyTriggedId": "B8yvCYL9f0ugnJ3q1cK0NXtJvPAJ",
-                        "password_generation_variation": "nudge_password",
-                        "probability": "0.25"
-                    },
-                    "enable_features": [
-                        "PasswordGenerationExperiment"
-                    ]
-                },
-                {
-                    "name": "EnabledWithEditPassword",
-                    "params": {
-                        "PasswordGenerationExperimentSurveyTriggedId": "4yPTnSKPN0ugnJ3q1cK0YJ18dkNR",
-                        "password_generation_variation": "edit_password",
-                        "probability": "0.25"
-                    },
-                    "enable_features": [
-                        "PasswordGenerationExperiment"
-                    ]
-                },
-                {
                     "name": "EnabledWithStrongLabel",
                     "params": {
                         "PasswordGenerationExperimentSurveyTriggedId": "p4WLf1M6c0ugnJ3q1cK0YsmLdpng",
@@ -13874,6 +13786,118 @@
                     ]
                 },
                 {
+                    "name": "EnabledWithTrustedAdvice",
+                    "params": {
+                        "PasswordGenerationExperimentSurveyTriggedId": "Vm6DB1ki50ugnJ3q1cK0SpkrheAJ",
+                        "password_generation_variation": "trusted_advice",
+                        "probability": "0.25"
+                    },
+                    "enable_features": [
+                        "PasswordGenerationExperiment"
+                    ],
+                    "disable_features": [
+                        "PasswordStrongLabel"
+                    ]
+                },
+                {
+                    "name": "EnabledWithSafetyFirst",
+                    "params": {
+                        "PasswordGenerationExperimentSurveyTriggedId": "sD7hmDAoo0ugnJ3q1cK0VQ2Y8p6e",
+                        "password_generation_variation": "safety_first",
+                        "probability": "0.25"
+                    },
+                    "enable_features": [
+                        "PasswordGenerationExperiment"
+                    ],
+                    "disable_features": [
+                        "PasswordStrongLabel"
+                    ]
+                },
+                {
+                    "name": "EnabledWithTrySomethingNew",
+                    "params": {
+                        "PasswordGenerationExperimentSurveyTriggedId": "6QssdASS10ugnJ3q1cK0RUK4HnYU",
+                        "password_generation_variation": "try_something_new",
+                        "probability": "0.25"
+                    },
+                    "enable_features": [
+                        "PasswordGenerationExperiment"
+                    ],
+                    "disable_features": [
+                        "PasswordStrongLabel"
+                    ]
+                },
+                {
+                    "name": "EnabledWithConvenience",
+                    "params": {
+                        "PasswordGenerationExperimentSurveyTriggedId": "W23VEAHCT0ugnJ3q1cK0SaPHa9J4",
+                        "password_generation_variation": "convenience",
+                        "probability": "0.25"
+                    },
+                    "enable_features": [
+                        "PasswordGenerationExperiment"
+                    ],
+                    "disable_features": [
+                        "PasswordStrongLabel"
+                    ]
+                },
+                {
+                    "name": "EnabledWithCrossDevice",
+                    "params": {
+                        "PasswordGenerationExperimentSurveyTriggedId": "fRjzkFjzZ0ugnJ3q1cK0RWYBnkGK",
+                        "password_generation_variation": "cross_device",
+                        "probability": "0.25"
+                    },
+                    "enable_features": [
+                        "PasswordGenerationExperiment"
+                    ],
+                    "disable_features": [
+                        "PasswordStrongLabel"
+                    ]
+                },
+                {
+                    "name": "EnabledWithChunkPassword",
+                    "params": {
+                        "PasswordGenerationExperimentSurveyTriggedId": "gnz68PSiB0ugnJ3q1cK0Y7PcR8ix",
+                        "password_generation_variation": "chunk_password",
+                        "probability": "0.25"
+                    },
+                    "enable_features": [
+                        "PasswordGenerationExperiment"
+                    ],
+                    "disable_features": [
+                        "PasswordStrongLabel"
+                    ]
+                },
+                {
+                    "name": "EnabledWithNudgePassword",
+                    "params": {
+                        "PasswordGenerationExperimentSurveyTriggedId": "B8yvCYL9f0ugnJ3q1cK0NXtJvPAJ",
+                        "password_generation_variation": "nudge_password",
+                        "probability": "0.25"
+                    },
+                    "enable_features": [
+                        "PasswordGenerationExperiment"
+                    ],
+                    "disable_features": [
+                        "PasswordStrongLabel"
+                    ]
+                },
+                {
+                    "name": "EnabledWithEditPassword",
+                    "params": {
+                        "PasswordGenerationExperimentSurveyTriggedId": "4yPTnSKPN0ugnJ3q1cK0YJ18dkNR",
+                        "password_generation_variation": "edit_password",
+                        "probability": "0.25"
+                    },
+                    "enable_features": [
+                        "PasswordGenerationExperiment"
+                    ],
+                    "disable_features": [
+                        "PasswordStrongLabel"
+                    ]
+                },
+                {
                     "name": "Baseline",
                     "params": {
                         "PasswordGenerationExperimentSurveyTriggedId": "DX4MWyX4R0ugnJ3q1cK0YjEiaErj",
@@ -13881,6 +13905,9 @@
                     },
                     "enable_features": [
                         "PasswordGenerationExperiment"
+                    ],
+                    "disable_features": [
+                        "PasswordStrongLabel"
                     ]
                 }
             ]
@@ -14557,6 +14584,25 @@
             ]
         }
     ],
+    "PressAndHoldEscToExitBrowserFullscreen": [
+        {
+            "platforms": [
+                "linux",
+                "mac",
+                "windows",
+                "chromeos",
+                "chromeos_lacros"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "PressAndHoldEscToExitBrowserFullscreen"
+                    ]
+                }
+            ]
+        }
+    ],
     "PriceDropNtpIPH": [
         {
             "platforms": [
@@ -19574,6 +19620,22 @@
             ]
         }
     ],
+    "TouchpadFastClickStudy": [
+        {
+            "platforms": [
+                "chromeos",
+                "chromeos_lacros"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "EnableFastTouchpadClick"
+                    ]
+                }
+            ]
+        }
+    ],
     "TrackingProtection3pcd": [
         {
             "platforms": [
diff --git a/third_party/angle b/third_party/angle
index 97cb3eb..e92b8e8 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit 97cb3eb8a79dcf752a99d0895719fde9f6bb3392
+Subproject commit e92b8e8d97d86ed49e27d8aca38a7c4d76d432a3
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index b73f8f3..d2d8817 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -1303,6 +1303,11 @@
 const base::FeatureParam<int> kLCPCriticalPathPredictorMaxElementLocatorLength{
     &kLCPCriticalPathPredictor, "lcpp_max_element_locator_length", 1024};
 
+const base::FeatureParam<bool>
+    kLCPCriticalPathAdjustImageLoadPriorityOverrideFirstNBoost{
+        &kLCPCriticalPathPredictor,
+        "lcpp_adjust_image_load_priority_override_first_n_boost", false};
+
 const base::FeatureParam<LcppRecordedLcpElementTypes>::Option
     lcpp_recorded_element_types[] = {
         {LcppRecordedLcpElementTypes::kAll, "all"},
diff --git a/third_party/blink/public/blink_resources.grd b/third_party/blink/public/blink_resources.grd
index 5541daad..ff3100ff 100644
--- a/third_party/blink/public/blink_resources.grd
+++ b/third_party/blink/public/blink_resources.grd
@@ -34,6 +34,7 @@
       <include name="IDR_UASTYLE_TRANSITION_ANIMATIONS_CSS" file="../renderer/core/css/transition_animations.css" type="BINDATA" compress="brotli"/>
       <include name="IDR_UASTYLE_FORM_CONTROLS_NOT_VERTICAL_CSS" file="../renderer/core/css/form_controls_not_vertical.css" type="BINDATA" compress="brotli"/>
       <include name="IDR_UASTYLE_FORM_CONTROLS_NOT_VERTICAL_CSS_TEXT" file="../renderer/core/css/form_controls_not_vertical_text.css" type="BINDATA" compress="brotli"/>
+      <include name="IDR_UASTYLE_AUTO_SIZES_CSS" file="../renderer/core/css/auto_sizes.css" type="BINDATA" compress="brotli"/>
       <include name="IDR_DOCUMENTXMLTREEVIEWER_CSS" file="../renderer/core/xml/DocumentXMLTreeViewer.css" type="BINDATA" compress="brotli"/>
       <include name="IDR_DOCUMENTXMLTREEVIEWER_JS" file="../renderer/core/xml/DocumentXMLTreeViewer.js" type="BINDATA" compress="brotli"/>
       <include name="IDR_VALIDATION_BUBBLE_ICON" file="../renderer/core/html/forms/resources/input_alert.svg" type="BINDATA" compress="brotli"/>
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index a7fbf35..b08a616 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -729,6 +729,11 @@
 BLINK_COMMON_EXPORT extern const base::FeatureParam<int>
     kLCPCriticalPathPredictorMaxElementLocatorLength;
 
+// If true, LCP critical path predictor mechanism overrides the first N image
+// prioritization when there is LCP hint.
+BLINK_COMMON_EXPORT extern const base::FeatureParam<bool>
+    kLCPCriticalPathAdjustImageLoadPriorityOverrideFirstNBoost;
+
 // The type of LCP elements recorded by LCPP.
 enum class LcppRecordedLcpElementTypes {
   kAll,
diff --git a/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_impl.cc b/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_impl.cc
index c923c0a..0e5881b 100644
--- a/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_impl.cc
+++ b/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_impl.cc
@@ -271,6 +271,22 @@
   }
 }
 
+namespace {
+// We only care for WrapperTypeInfo and do not supply an actual instance of
+// the document. Since we need a script wrappable to get type info now, this
+// class is a minimal implementation of ScriptWrappable that returns correct
+// type info for HTMLDocument.
+class DummyHTMLDocumentForSnapshot : public ScriptWrappable {
+ public:
+  DummyHTMLDocumentForSnapshot() = default;
+
+ private:
+  const WrapperTypeInfo* GetWrapperTypeInfo() const override {
+    return V8HTMLDocument::GetWrapperTypeInfo();
+  }
+};
+}  // namespace
+
 void TakeSnapshotForWorld(v8::SnapshotCreator* snapshot_creator,
                           const DOMWrapperWorld& world) {
   v8::Isolate* isolate = snapshot_creator->GetIsolate();
@@ -300,11 +316,9 @@
     v8::Local<v8::Object> document_wrapper = CreatePlatformObject(
         isolate, context, world, document_wrapper_type_info);
 
-    int indices[] = {kV8DOMWrapperObjectIndex, kV8DOMWrapperTypeIndex};
-    void* values[] = {nullptr,
-                      const_cast<WrapperTypeInfo*>(document_wrapper_type_info)};
-    document_wrapper->SetAlignedPointerInInternalFields(std::size(indices),
-                                                        indices, values);
+    V8DOMWrapper::SetNativeInfo(
+        isolate, document_wrapper, document_wrapper_type_info,
+        MakeGarbageCollected<DummyHTMLDocumentForSnapshot>());
 
     V8PrivateProperty::GetWindowDocumentCachedAccessor(isolate).Set(
         context->Global(), document_wrapper);
diff --git a/third_party/blink/renderer/core/css/auto_sizes.css b/third_party/blink/renderer/core/css/auto_sizes.css
new file mode 100644
index 0000000..05f9b693
--- /dev/null
+++ b/third_party/blink/renderer/core/css/auto_sizes.css
@@ -0,0 +1,12 @@
+/*
+ * Copyright 2024 The Chromium Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+@namespace "http://www.w3.org/1999/xhtml";
+
+img:is([sizes="auto" i], [sizes^="auto," i]) {
+    contain: size !important;
+    contain-intrinsic-size: 300px 150px;
+}
diff --git a/third_party/blink/renderer/core/css/css_default_style_sheets.cc b/third_party/blink/renderer/core/css/css_default_style_sheets.cc
index 4077ab5b..e56ec74b 100644
--- a/third_party/blink/renderer/core/css/css_default_style_sheets.cc
+++ b/third_party/blink/renderer/core/css/css_default_style_sheets.cc
@@ -133,6 +133,7 @@
   marker_style_sheet_.Clear();
   form_controls_not_vertical_style_sheet_.Clear();
   form_controls_not_vertical_style_text_sheet_.Clear();
+  auto_sizes_style_sheet_.Clear();
   permission_element_style_sheet_.Clear();
   // Recreate the default style sheet to clean up possible SVG resources.
   String default_rules = UncompressResourceAsASCIIString(IDR_UASTYLE_HTML_CSS) +
@@ -389,6 +390,14 @@
     changed_default_style = true;
   }
 
+  if (!auto_sizes_style_sheet_ && IsA<HTMLImageElement>(element) &&
+      RuntimeEnabledFeatures::AutoSizeLazyLoadedImagesEnabled()) {
+    auto_sizes_style_sheet_ = ParseUASheet(
+        UncompressResourceAsASCIIString(IDR_UASTYLE_AUTO_SIZES_CSS));
+    AddRulesToDefaultStyleSheets(auto_sizes_style_sheet_, NamespaceType::kHTML);
+    changed_default_style = true;
+  }
+
   DCHECK(!default_html_style_->Features().HasIdsInSelectors());
   return changed_default_style;
 }
@@ -542,6 +551,7 @@
   visitor->Trace(marker_style_sheet_);
   visitor->Trace(form_controls_not_vertical_style_sheet_);
   visitor->Trace(form_controls_not_vertical_style_text_sheet_);
+  visitor->Trace(auto_sizes_style_sheet_);
   visitor->Trace(default_json_document_style_);
 }
 
diff --git a/third_party/blink/renderer/core/css/css_default_style_sheets.h b/third_party/blink/renderer/core/css/css_default_style_sheets.h
index a1a99c4..2fbe1fe 100644
--- a/third_party/blink/renderer/core/css/css_default_style_sheets.h
+++ b/third_party/blink/renderer/core/css/css_default_style_sheets.h
@@ -108,6 +108,9 @@
   StyleSheetContents* FormControlsNotVerticalTextSheet() {
     return form_controls_not_vertical_style_text_sheet_.Get();
   }
+  StyleSheetContents* AutoSizesStyleSheet() {
+    return auto_sizes_style_sheet_.Get();
+  }
 
   CORE_EXPORT void PrepareForLeakDetection();
 
@@ -175,6 +178,7 @@
   Member<StyleSheetContents> forced_colors_style_sheet_;
   Member<StyleSheetContents> form_controls_not_vertical_style_sheet_;
   Member<StyleSheetContents> form_controls_not_vertical_style_text_sheet_;
+  Member<StyleSheetContents> auto_sizes_style_sheet_;
 
   std::unique_ptr<UAStyleSheetLoader> media_controls_style_sheet_loader_;
 };
diff --git a/third_party/blink/renderer/core/css/parser/sizes_attribute_parser_test.cc b/third_party/blink/renderer/core/css/parser/sizes_attribute_parser_test.cc
index b445340..abb3192 100644
--- a/third_party/blink/renderer/core/css/parser/sizes_attribute_parser_test.cc
+++ b/third_party/blink/renderer/core/css/parser/sizes_attribute_parser_test.cc
@@ -220,11 +220,8 @@
   ASSERT_TRUE(parser.IsAuto());
   ASSERT_EQ(500, parser.Size());
 }
-// TODO(tcaptan):
-// Disabled the size check for images with no width for now because of:
-// crbug.com/1522175
-// Will re-enable or modify after the UA style sheet issue is resolved.
-TEST_F(SizesAttributeParserTest, DISABLED_AutoSizesLazyImgNoWidth) {
+
+TEST_F(SizesAttributeParserTest, AutoSizesLazyImgNoWidth) {
   SetBodyInnerHTML(R"HTML(
     <img id="target" sizes="auto" loading="lazy">
   )HTML");
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 3434d32..bd9f48e 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -1807,7 +1807,7 @@
     }
 
     return AdjustForAbsoluteZoom::AdjustScroll(
-        scrollable_area->GetScrollOffset().x(), *GetLayoutBox());
+        scrollable_area->GetWebExposedScrollOffset().x(), *GetLayoutBox());
   }
 
   return 0;
@@ -1854,7 +1854,7 @@
     }
 
     return AdjustForAbsoluteZoom::AdjustScroll(
-        scrollable_area->GetScrollOffset().y(), *GetLayoutBox());
+        scrollable_area->GetWebExposedScrollOffset().y(), *GetLayoutBox());
   }
 
   return 0;
diff --git a/third_party/blink/renderer/core/frame/dom_visual_viewport.cc b/third_party/blink/renderer/core/frame/dom_visual_viewport.cc
index 3d80909..e4a03cb 100644
--- a/third_party/blink/renderer/core/frame/dom_visual_viewport.cc
+++ b/third_party/blink/renderer/core/frame/dom_visual_viewport.cc
@@ -100,10 +100,10 @@
   SyncScrollAttemptHeuristic::DidAccessScrollOffset();
 
   frame->GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kJavaScript);
-  float viewport_x = view->LayoutViewport()->GetScrollOffset().x();
+  float viewport_x = view->LayoutViewport()->GetWebExposedScrollOffset().x();
 
   if (frame->IsMainFrame() && page->GetVisualViewport().IsActiveViewport())
-    viewport_x += page->GetVisualViewport().GetScrollOffset().x();
+    viewport_x += page->GetVisualViewport().GetWebExposedScrollOffset().x();
 
   return AdjustForAbsoluteZoom::AdjustScroll(viewport_x,
                                              frame->PageZoomFactor());
@@ -127,10 +127,10 @@
   SyncScrollAttemptHeuristic::DidAccessScrollOffset();
 
   frame->GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kJavaScript);
-  float viewport_y = view->LayoutViewport()->GetScrollOffset().y();
+  float viewport_y = view->LayoutViewport()->GetWebExposedScrollOffset().y();
 
   if (frame->IsMainFrame() && page->GetVisualViewport().IsActiveViewport())
-    viewport_y += page->GetVisualViewport().GetScrollOffset().y();
+    viewport_y += page->GetVisualViewport().GetWebExposedScrollOffset().y();
 
   return AdjustForAbsoluteZoom::AdjustScroll(viewport_y,
                                              frame->PageZoomFactor());
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index 7466cde..8e3ac9bf 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -1631,7 +1631,7 @@
 
   // TODO(bokan): This is wrong when the document.rootScroller is non-default.
   // crbug.com/505516.
-  double viewport_x = view->LayoutViewport()->GetScrollOffset().x();
+  double viewport_x = view->LayoutViewport()->GetWebExposedScrollOffset().x();
   return AdjustForAbsoluteZoom::AdjustScroll(viewport_x,
                                              GetFrame()->PageZoomFactor());
 }
@@ -1652,7 +1652,7 @@
 
   // TODO(bokan): This is wrong when the document.rootScroller is non-default.
   // crbug.com/505516.
-  double viewport_y = view->LayoutViewport()->GetScrollOffset().y();
+  double viewport_y = view->LayoutViewport()->GetWebExposedScrollOffset().y();
   return AdjustForAbsoluteZoom::AdjustScroll(viewport_y,
                                              GetFrame()->PageZoomFactor());
 }
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.cc b/third_party/blink/renderer/core/frame/visual_viewport.cc
index 241c0edc..b7af52e4e 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport.cc
+++ b/third_party/blink/renderer/core/frame/visual_viewport.cc
@@ -625,9 +625,7 @@
 
   needs_paint_property_update_ = true;
 
-  // TODO(crbug.com/1015625): Avoid scroll_layer_.
   scroll_layer_ = cc::Layer::Create();
-  scroll_layer_->SetScrollable(size_);
   scroll_layer_->SetBounds(ContentsSize());
   scroll_layer_->SetElementId(GetScrollElementId());
 
diff --git a/third_party/blink/renderer/core/layout/inline/ruby_utils.cc b/third_party/blink/renderer/core/layout/inline/ruby_utils.cc
index 4b8b150..464ec967 100644
--- a/third_party/blink/renderer/core/layout/inline/ruby_utils.cc
+++ b/third_party/blink/renderer/core/layout/inline/ruby_utils.cc
@@ -974,9 +974,11 @@
     return result_height;
   }
   if (const auto& layout_result = line_item.layout_result) {
-    // Assume 0 is the baseline.  BlockOffset() is always negative.
-    return FontHeight(-line_item.BlockOffset(),
-                      line_item.Size().block_size + line_item.BlockOffset());
+    if (line_item.Size().inline_size != LayoutUnit()) {
+      // Assume 0 is the baseline.  BlockOffset() is always negative.
+      return FontHeight(-line_item.BlockOffset(),
+                        line_item.Size().block_size + line_item.BlockOffset());
+    }
   }
   return FontHeight();
 }
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index 6b37b2b..96bfeb8 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -550,6 +550,18 @@
   return lcpp->HasAnyHintData();
 }
 
+bool FrameFetchContext::DoesLCPPHaveLcpElementLocatorHintData() {
+  if (GetResourceFetcherProperties().IsDetached()) {
+    return false;
+  }
+
+  LCPCriticalPathPredictor* lcpp = GetFrame()->GetLCPP();
+  if (!lcpp) {
+    return false;
+  }
+  return !lcpp->lcp_element_locators().empty();
+}
+
 void FrameFetchContext::SetFirstPartyCookie(ResourceRequest& request) {
   // Set the first party for cookies url if it has not been set yet (new
   // requests). This value will be updated during redirects, consistent with
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.h b/third_party/blink/renderer/core/loader/frame_fetch_context.h
index 0c185cd3..82839b6 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.h
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.h
@@ -105,6 +105,8 @@
 
   bool DoesLCPPHaveAnyHintData() override;
 
+  bool DoesLCPPHaveLcpElementLocatorHintData() override;
+
   // Exposed for testing.
   void ModifyRequestForCSP(ResourceRequest&);
   void AddClientHintsIfNecessary(const std::optional<float> resource_width,
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index 6fbaeacb..d17823381 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -133,6 +133,7 @@
 #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "url/url_features.h"
 
 namespace blink {
 
@@ -794,6 +795,18 @@
     }
     return;
   }
+  // If kStandardCompliantNonSpecialSchemeURLParsing feature is enabled,
+  // "javascript:" scheme URL can be a invalid URL. e.g. "javascript://a b".
+  //
+  // We shouldn't navigate to such an invalid "javascript:" scheme URL.
+  //
+  // See wpt/url/javascript-urls.window.js test for the standard compliant
+  // behaviors.
+  if (url::IsUsingStandardCompliantNonSpecialSchemeURLParsing() &&
+      ProtocolIsJavaScript(url.GetString())) {
+    DCHECK(!url.IsValid());
+    return;
+  }
 
   if (request.GetNavigationPolicy() == kNavigationPolicyCurrentTab &&
       (!origin_window || origin_window->GetSecurityOrigin()->CanAccess(
diff --git a/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc b/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
index c171c5b9..a17f8de 100644
--- a/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
@@ -92,10 +92,6 @@
         .FindNodeFromElementId(scrollable_area.GetScrollElementId());
   }
 
-  bool IsScrollable(const cc::Layer* layer) const {
-    return GetScrollNode(layer)->scrollable;
-  }
-
   uint32_t GetMainThreadScrollingReasons(const cc::Layer* layer) const {
     return GetScrollNode(layer)->main_thread_scrolling_reasons;
   }
@@ -166,7 +162,6 @@
   const cc::Layer* inner_scroll_layer = CcLayerByCcElementId(
       root_layer, inner_scroll_node->GetCompositorElementId());
   ASSERT_TRUE(inner_scroll_layer);
-  ASSERT_TRUE(IsScrollable(inner_scroll_layer));
   EXPECT_MAIN_THREAD_SCROLLING_REASON(
       cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects,
       GetMainThreadScrollingReasons(inner_scroll_layer));
@@ -184,7 +179,6 @@
   const cc::Layer* outer_scroll_layer = CcLayerByCcElementId(
       root_layer, outer_scroll_node->GetCompositorElementId());
   ASSERT_TRUE(outer_scroll_layer);
-  ASSERT_TRUE(IsScrollable(outer_scroll_layer));
   EXPECT_NO_MAIN_THREAD_SCROLLING_REASON(
       GetMainThreadScrollingReasons(outer_scroll_layer));
 
@@ -203,7 +197,6 @@
   ASSERT_EQ(inner_scroll_layer,
             CcLayerByCcElementId(root_layer,
                                  inner_scroll_node->GetCompositorElementId()));
-  ASSERT_TRUE(IsScrollable(inner_scroll_layer));
   EXPECT_NO_MAIN_THREAD_SCROLLING_REASON(
       GetMainThreadScrollingReasons(inner_scroll_layer));
 
@@ -214,7 +207,6 @@
   ASSERT_EQ(outer_scroll_layer,
             CcLayerByCcElementId(root_layer,
                                  outer_scroll_node->GetCompositorElementId()));
-  ASSERT_TRUE(IsScrollable(outer_scroll_layer));
   EXPECT_NO_MAIN_THREAD_SCROLLING_REASON(
       GetMainThreadScrollingReasons(outer_scroll_layer));
 
@@ -239,7 +231,6 @@
   ASSERT_EQ(inner_scroll_layer,
             CcLayerByCcElementId(root_layer,
                                  inner_scroll_node->GetCompositorElementId()));
-  ASSERT_TRUE(IsScrollable(inner_scroll_layer));
   EXPECT_MAIN_THREAD_SCROLLING_REASON(
       cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects,
       GetMainThreadScrollingReasons(inner_scroll_layer));
@@ -252,7 +243,6 @@
   ASSERT_EQ(outer_scroll_layer,
             CcLayerByCcElementId(root_layer,
                                  outer_scroll_node->GetCompositorElementId()));
-  ASSERT_TRUE(IsScrollable(outer_scroll_layer));
   EXPECT_MAIN_THREAD_SCROLLING_REASON(
       cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects,
       GetMainThreadScrollingReasons(outer_scroll_layer));
@@ -381,7 +371,6 @@
 
   const cc::Layer* visual_viewport_scroll_layer =
       GetFrame()->GetPage()->GetVisualViewport().LayerForScrolling();
-  ASSERT_TRUE(IsScrollable(visual_viewport_scroll_layer));
   EXPECT_FALSE(GetMainThreadScrollingReasons(visual_viewport_scroll_layer));
 }
 
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_test.cc b/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
index 791491f3..d773cb7 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
@@ -170,7 +170,6 @@
                                 ->property_trees()
                                 ->scroll_tree()
                                 .FindNodeFromElementId(scroll_element_id);
-  EXPECT_TRUE(scroll_node->scrollable);
   EXPECT_EQ(scroll_node->container_bounds, gfx::Size(100, 100));
 
   // Ensure a synthetic impl-side scroll offset propagates to the scrollable
@@ -230,7 +229,6 @@
           ->scroll_tree()
           .FindNodeFromElementId(scrollable_area->GetScrollElementId());
   ASSERT_TRUE(scroll_node);
-  EXPECT_TRUE(scroll_node->scrollable);
 
   // Ensure a synthetic impl-side scroll offset propagates to the scrollable
   // area using the DidScroll callback.
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.cc b/third_party/blink/renderer/core/scroll/scrollable_area.cc
index dbab7737..2899769 100644
--- a/third_party/blink/renderer/core/scroll/scrollable_area.cc
+++ b/third_party/blink/renderer/core/scroll/scrollable_area.cc
@@ -1432,4 +1432,15 @@
                                                       inline_target);
 }
 
+ScrollOffset ScrollableArea::GetWebExposedScrollOffset() const {
+  ScrollOffset scroll_offset = GetScrollOffset();
+  if (RuntimeEnabledFeatures::WebExposedScrollOffsetEnabled()) {
+    return gfx::ToFlooredVector2d(scroll_offset);
+  }
+  // Ensure that, if fractional scroll offsets are not enabled, the scroll
+  // offset is an floored value.
+  CHECK_EQ(gfx::ToFlooredVector2d(scroll_offset), scroll_offset);
+  return scroll_offset;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.h b/third_party/blink/renderer/core/scroll/scrollable_area.h
index d4337342..ac90288 100644
--- a/third_party/blink/renderer/core/scroll/scrollable_area.h
+++ b/third_party/blink/renderer/core/scroll/scrollable_area.h
@@ -379,6 +379,9 @@
   virtual ScrollOffset GetScrollOffset() const {
     return ScrollOffset(ScrollOffsetInt());
   }
+  // Returns a floored version of the scroll offset as the web-exposed scroll
+  // offset to ensure web compatibility in DOM APIs.
+  virtual ScrollOffset GetWebExposedScrollOffset() const;
   virtual gfx::Vector2d MinimumScrollOffsetInt() const = 0;
   virtual ScrollOffset MinimumScrollOffset() const {
     return ScrollOffset(MinimumScrollOffsetInt());
diff --git a/third_party/blink/renderer/core/svg/svg_animation_element.cc b/third_party/blink/renderer/core/svg/svg_animation_element.cc
index 166b38a..d31b5dd 100644
--- a/third_party/blink/renderer/core/svg/svg_animation_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_animation_element.cc
@@ -549,37 +549,11 @@
 }
 
 bool SVGAnimationElement::CalculateValuesAnimation() {
-  if (values_.empty())
-    return false;
-  CalcMode calc_mode = GetCalcMode();
-  // For 'values' animations, there should be exactly as many 'keyTimes' as
-  // 'values'.
-  if (calc_mode != kCalcModePaced &&
-      !FastHasAttribute(svg_names::kKeyPointsAttr) &&
-      FastHasAttribute(svg_names::kKeyTimesAttr) &&
-      values_.size() != KeyTimes().size())
-    return false;
-  // If 'keyTimes' is specified its last value should be 1 (and the first 0)
-  // unless 'calcMode' is 'discrete'.
-  if (calc_mode != kCalcModeDiscrete && !KeyTimes().empty() &&
-      KeyTimes().back() != 1)
-    return false;
-  // If 'calcMode' is 'spline', there should be one less spline than there are
-  // 'keyPoints' or 'values'.
-  if (calc_mode == kCalcModeSpline) {
-    if ((key_splines_.empty() || key_splines_.size() != values_.size() - 1) &&
-        key_splines_.size() != key_points_.size() - 1)
-      return false;
-  }
-  // If 'keyPoints' is specified it should have the same amount of points as
-  // 'keyTimes', and at least two points.
-  if (FastHasAttribute(svg_names::kKeyPointsAttr) &&
-      (KeyTimes().size() < 2 || KeyTimes().size() != key_points_.size()))
-    return false;
   if (!CalculateToAtEndOfDurationValue(values_.back()))
     return false;
-  if (calc_mode == kCalcModePaced)
+  if (GetCalcMode() == kCalcModePaced) {
     CalculateKeyTimesForCalcModePaced();
+  }
   return true;
 }
 
@@ -593,14 +567,30 @@
     return false;
 
   // These validations are appropriate for all animation modes.
-  // If 'keyPoints' is specified it should have the same amount of points as
-  // 'keyTimes'.
-  if (FastHasAttribute(svg_names::kKeyPointsAttr) &&
-      KeyTimes().size() != key_points_.size())
-    return false;
-
-  CalcMode calc_mode = GetCalcMode();
-  if (calc_mode == kCalcModeSpline) {
+  if (FastHasAttribute(svg_names::kKeyPointsAttr)) {
+    // If 'keyPoints' is specified it should have the same amount of points as
+    // 'keyTimes'.
+    if (KeyTimes().size() != key_points_.size()) {
+      return false;
+    }
+    if (animation_mode == kFromToAnimation ||
+        animation_mode == kFromByAnimation || animation_mode == kToAnimation ||
+        animation_mode == kByAnimation) {
+      if (FastHasAttribute(svg_names::kKeyTimesAttr)) {
+        // ...and at least two points.
+        if (KeyTimes().size() < 2) {
+          return false;
+        }
+      }
+    } else if (animation_mode == kValuesAnimation ||
+               animation_mode == kPathAnimation) {
+      // ...and at least two points.
+      if (KeyTimes().size() < 2) {
+        return false;
+      }
+    }
+  }
+  if (GetCalcMode() == kCalcModeSpline) {
     // If 'calcMode' is 'spline', there should be one less spline than there
     // are 'keyTimes' or 'keyPoints' - or 'values' if it is used.
     if (key_splines_.empty() ||
@@ -612,18 +602,35 @@
          key_splines_.size() != KeyTimes().size() - 1))
       return false;
   }
-
-  if (animation_mode == kFromToAnimation ||
-      animation_mode == kFromByAnimation || animation_mode == kToAnimation ||
-      animation_mode == kByAnimation) {
-    if (FastHasAttribute(svg_names::kKeyTimesAttr)) {
-      // If 'keyPoints' is specified it should have the same amount of points
-      // as 'keyTimes', and at least two points.
-      if (FastHasAttribute(svg_names::kKeyPointsAttr) &&
-          (KeyTimes().size() < 2 || KeyTimes().size() != key_points_.size()))
+  if (animation_mode == kValuesAnimation) {
+    if (values_.empty()) {
+      return false;
+    }
+    const CalcMode calc_mode = GetCalcMode();
+    // For 'values' animations, there should be exactly as many 'keyTimes' as
+    // 'values'.
+    if (calc_mode != kCalcModePaced &&
+        !FastHasAttribute(svg_names::kKeyPointsAttr) &&
+        FastHasAttribute(svg_names::kKeyTimesAttr) &&
+        values_.size() != KeyTimes().size()) {
+      return false;
+    }
+    // If 'keyTimes' is specified its last value should be 1 (and the first 0)
+    // unless 'calcMode' is 'discrete'.
+    if (calc_mode != kCalcModeDiscrete && !KeyTimes().empty() &&
+        KeyTimes().back() != 1) {
+      return false;
+    }
+    // If 'calcMode' is 'spline', there should be one less spline than there are
+    // 'keyPoints' or 'values'.
+    if (calc_mode == kCalcModeSpline) {
+      if ((key_splines_.empty() || key_splines_.size() != values_.size() - 1) &&
+          key_splines_.size() != key_points_.size() - 1) {
         return false;
+      }
     }
   }
+
   const String& from = FromValue();
   const String& to = ToValue();
   const String& by = ByValue();
@@ -642,11 +649,6 @@
   if (animation_mode == kValuesAnimation)
     return CalculateValuesAnimation();
   if (animation_mode == kPathAnimation) {
-    // If 'keyPoints' is specified it should have the same amount of points as
-    // 'keyTimes', and at least two points.
-    if (FastHasAttribute(svg_names::kKeyPointsAttr) &&
-        (KeyTimes().size() < 2 || KeyTimes().size() != key_points_.size()))
-      return false;
     return true;
   }
   return false;
diff --git a/third_party/blink/renderer/modules/mediarecorder/audio_track_mojo_encoder.cc b/third_party/blink/renderer/modules/mediarecorder/audio_track_mojo_encoder.cc
index 6bd1e63..ada36f6 100644
--- a/third_party/blink/renderer/modules/mediarecorder/audio_track_mojo_encoder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/audio_track_mojo_encoder.cc
@@ -175,8 +175,11 @@
     return;
   }
 
-  std::string encoded_data(encoded_buffer.encoded_data.begin(),
-                           encoded_buffer.encoded_data.end());
+  // Don't use encoded_buffer.encoded_data.end() as the encoded data size could
+  // be smaller than the allocated encoded_data.
+  std::string encoded_data(
+      encoded_buffer.encoded_data.begin(),
+      encoded_buffer.encoded_data.begin() + encoded_buffer.encoded_data_size);
   on_encoded_audio_cb_.Run(encoded_buffer.params, encoded_data,
                            std::move(codec_desc), encoded_buffer.timestamp);
 }
diff --git a/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc b/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc
index e823d59..f618f00 100644
--- a/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc
+++ b/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc
@@ -57,13 +57,14 @@
   return v8_template;
 }
 
-const WrapperTypeInfo* ToWrapperTypeInfo(
-    const v8::TracedReference<v8::Object>& wrapper) {
-  return GetInternalField<WrapperTypeInfo, kV8DOMWrapperTypeIndex>(wrapper);
-}
-
 const WrapperTypeInfo* ToWrapperTypeInfo(v8::Local<v8::Object> wrapper) {
-  return GetInternalField<WrapperTypeInfo, kV8DOMWrapperTypeIndex>(wrapper);
+  const auto* wrappable = ToScriptWrappable(wrapper->GetIsolate(), wrapper);
+  const WrapperTypeInfo* type_info =
+      wrappable ? wrappable->GetWrapperTypeInfo() : nullptr;
+  DCHECK_EQ(
+      type_info,
+      (GetInternalField<WrapperTypeInfo, kV8DOMWrapperTypeIndex>(wrapper)));
+  return type_info;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/bindings/wrapper_type_info.h b/third_party/blink/renderer/platform/bindings/wrapper_type_info.h
index 6cd34f0..a153137 100644
--- a/third_party/blink/renderer/platform/bindings/wrapper_type_info.h
+++ b/third_party/blink/renderer/platform/bindings/wrapper_type_info.h
@@ -207,9 +207,6 @@
 }
 
 PLATFORM_EXPORT const WrapperTypeInfo* ToWrapperTypeInfo(
-    const v8::TracedReference<v8::Object>& wrapper);
-
-PLATFORM_EXPORT const WrapperTypeInfo* ToWrapperTypeInfo(
     v8::Local<v8::Object> wrapper);
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
index c89e382..4603edc2 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -1024,7 +1024,6 @@
 
 static void CheckCcScrollNode(const ScrollPaintPropertyNode& blink_scroll,
                               const cc::ScrollNode& cc_scroll) {
-  EXPECT_TRUE(cc_scroll.scrollable);
   EXPECT_EQ(blink_scroll.ContainerRect().size(), cc_scroll.container_bounds);
   EXPECT_EQ(blink_scroll.ContentsRect().size(), cc_scroll.bounds);
   EXPECT_EQ(blink_scroll.UserScrollableHorizontal(),
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
index 20c77cb..6c473d3 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -614,8 +614,6 @@
   id = scroll_tree_.Insert(cc::ScrollNode(), parent_id);
 
   cc::ScrollNode& compositor_node = *scroll_tree_.Node(id);
-  compositor_node.scrollable = true;
-
   compositor_node.container_bounds = scroll_node.ContainerRect().size();
   compositor_node.bounds = scroll_node.ContentsRect().size();
   compositor_node.user_scrollable_horizontal =
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_context.h b/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
index ceecd88..1100c30 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
@@ -189,6 +189,10 @@
   // Returns true iff we have LCPP hint data for the fetch context.
   virtual bool DoesLCPPHaveAnyHintData() { return false; }
 
+  // Returns true iff we have LCP element locator hint data for the fetch
+  // context.
+  virtual bool DoesLCPPHaveLcpElementLocatorHintData() { return false; }
+
   // Returns the origin of the top frame in the document or the dedicated
   // worker. This returns nullptr for Shared Workers and Service Workers.
   virtual scoped_refptr<const SecurityOrigin> GetTopFrameOrigin() const {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index 58fb3aa..0cb5c2bd 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -666,6 +666,19 @@
     }
   }
 
+  // The following code disables AdjustImagePriority when there is LCPP
+  // LcpElementLocator hint data. The reason why not to early return from this
+  // function is that we want to record UMA with following
+  // MaybeRecordBoostImagePriorityReason() function even when we disables
+  // AdjustImagePriority.
+  if (base::FeatureList::IsEnabled(features::kLCPCriticalPathPredictor) &&
+      features::kLCPCriticalPathAdjustImageLoadPriority.Get() &&
+      features::kLCPCriticalPathAdjustImageLoadPriorityOverrideFirstNBoost
+          .Get() &&
+      context_->DoesLCPPHaveLcpElementLocatorHintData()) {
+    new_priority = priority_so_far;
+  }
+
   // Only records HTTP family URLs (e.g. Exclude data URLs).
   if (resource_request.Url().ProtocolIsInHTTPFamily()) {
     MaybeRecordBoostImagePriorityReason(priority_so_far != new_priority,
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index efa5cbb..4c9bb9d 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -406,7 +406,7 @@
       // attribute is missing or set to auto.
       name: "AutoSizeLazyLoadedImages",
       depends_on: ["NoIntrinsicSizeOverride"],
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "AvoidCaretVisibleSelectionAdjuster",
@@ -1565,6 +1565,7 @@
       browser_process_read_access: true,
       status: "test",
       base_feature: "none",
+      origin_trial_feature_name: "FedCmContinueOnBundle",
       origin_trial_allows_third_party: true,
     },
     {
@@ -4266,6 +4267,10 @@
       status: "experimental",
     },
     {
+      name: "WebExposedScrollOffset",
+      status: "stable",
+    },
+    {
       name: "WebFontResizeLCP",
       status: "experimental",
     },
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index a39a4446..5dca83a 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -5462,6 +5462,7 @@
 
 # Failures with FractionalScrollOffsets disabled for web tests by default.
 crbug.com/1358383 virtual/threaded-prefer-compositing/fast/scrolling/scrollbars/mouse-scrolling-on-root-scrollbar-thumb.html [ Failure ]
+crbug.com/326122314 external/wpt/css/css-viewport/zoom/scroll-top-test-with-zoom.html [ Failure ]
 
 # Sheriff 2022-08-30
 
@@ -7247,10 +7248,8 @@
 
 # RubyLineBreakable
 crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/br-clear-all-002.html [ Failure ]
-crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/empty-ruby-text-container-abs.html [ Failure ]
 crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/line-break-around-ruby-001.html [ Failure ]
 crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/line-spacing.html [ Failure ]
-crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-intra-level-whitespace-001.html [ Failure ]
 crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-line-breaking-002.html [ Failure ]
 crbug.com/324111880 virtual/ruby-lb/fast/ruby/float-overhang-from-ruby-text.html [ Failure ]
 crbug.com/324111880 virtual/ruby-lb/fast/ruby/line-break-ruby.html [ Failure ]
@@ -7258,7 +7257,6 @@
 crbug.com/324111880 virtual/ruby-lb/fast/ruby/overhang-horizontal.html [ Failure ]
 crbug.com/324111880 virtual/ruby-lb/fast/ruby/overhang-vertical.html [ Failure ]
 crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-position-modern-japanese-fonts.html [ Failure ]
-crbug.com/324111880 virtual/ruby-lb/fast/ruby/rubyDOM-insert-text2.html [ Failure ]
 crbug.com/324111880 virtual/ruby-lb/fast/ruby/select-ruby.html [ Failure ]
 # RubyLineBreakable; NeedsRebaseline
 crbug.com/324111880 virtual/ruby-lb/fast/ruby/after-doesnt-crash.html [ Failure ]
@@ -7278,6 +7276,9 @@
 crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-text-before-after-content.html [ Failure ]
 crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-trailing.html [ Failure ]
 crbug.com/324111880 virtual/ruby-lb/fast/ruby/split-ruby-column-percentage-height-descendant.html [ Failure ]
+# RubyLineBreakable; Passing in the virtual suite though failing in non-virtual
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/empty-ruby-text-container-float.html [ Pass ]
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-base-different-size.html [ Pass ]
 
 # line-clamp
 crbug.com/40336192 external/wpt/css/css-overflow/line-clamp-001.tentative.html [ Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index f25ae6e..685c4758 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -448,6 +448,7 @@
     "prefix": "fractional-scroll-offsets",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/css/css-position/sticky/",
+              "external/wpt/css/css-viewport/zoom/scroll-top-test-with-zoom.html",
               "fast/scrolling/"],
     "args": ["--enable-blink-features=FractionalScrollOffsets",
              "--disable-threaded-compositing", "--disable-threaded-animation"],
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 6b8d3a0..e18a8e5 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -70793,6 +70793,19 @@
        {}
       ]
      ],
+     "anchor-scroll-overflow-hidden.html": [
+      "b57e39956bbbb3f268b25d3dabedb6c97ef22dd0",
+      [
+       null,
+       [
+        [
+         "/css/css-anchor-position/anchor-scroll-overflow-hidden-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "anchor-scroll-position-try-012.html": [
       "7c0b381999d303dcefd8dccbdcad60d9c4b1d29d",
       [
@@ -70806,6 +70819,19 @@
        {}
       ]
      ],
+     "anchor-scroll-scrollable-anchor.html": [
+      "c2a256877d4c64b9652d2056d1ba19c0f1e51be9",
+      [
+       null,
+       [
+        [
+         "/css/css-anchor-position/anchor-scroll-scrollable-anchor-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "anchor-scroll-to-sticky-001.html": [
       "a6c3b0572533a2cb689ce23655f0b16ff47ea3b9",
       [
@@ -302274,10 +302300,18 @@
       "dc7f77f2b3441ebee25f3e40a9480b668ee79ea4",
       []
      ],
+     "anchor-scroll-overflow-hidden-ref.html": [
+      "b674998a5db1f347af82bde1f5efb4261a3732af",
+      []
+     ],
      "anchor-scroll-position-try-012-ref.html": [
       "fbc0b5fc6da55cfadb1ea610092882b8ff7502a7",
       []
      ],
+     "anchor-scroll-scrollable-anchor-ref.html": [
+      "3528b565fccb1d32dff6fe732c9497446e5f525e",
+      []
+     ],
      "inset-area-inline-container-ref.html": [
       "ecf54f1a9ac2d756cb78f4d2c0690c1ac8b65916",
       []
@@ -320048,7 +320082,7 @@
          []
         ],
         "masonry-align-content-003-ref.html": [
-         "9780d5f5dcf069295ce97d301e37bc4253b561d0",
+         "9da15c0f40319f07c5560f9aaf96a2e3e0ffa592",
          []
         ],
         "masonry-align-content-004-ref.html": [
@@ -454163,7 +454197,7 @@
      "masonry": {
       "tentative": {
        "masonry-grid-template-columns-computed-withcontent.html": [
-        "b36efb664dadc62a2f7f2ffaf1e834c195f13acc",
+        "a799955553e4c39177f5712f7a2e6b244b1a499e",
         [
          null,
          {}
@@ -699909,7 +699943,7 @@
      ]
     ],
     "invalid.html": [
-     "26b2905e4d44c2534af70930e2ea24876ed0f556",
+     "6c0ed90f735c59fe7c832a634779eab56914437c",
      [
       null,
       {}
diff --git a/third_party/blink/web_tests/external/wpt/credential-management/support/set_cookie.headers b/third_party/blink/web_tests/external/wpt/credential-management/support/set_cookie.headers
index 4226ff4..ddeb0bb 100644
--- a/third_party/blink/web_tests/external/wpt/credential-management/support/set_cookie.headers
+++ b/third_party/blink/web_tests/external/wpt/credential-management/support/set_cookie.headers
@@ -1,3 +1,3 @@
 Content-Type: text/html
-Set-Cookie: cookie=1; SameSite=None; Secure
-Set-Cookie: same_site_strict=1; SameSite=Strict; Secure
+Set-Cookie: cookie=1; SameSite=None; Secure; Path=/
+Set-Cookie: same_site_strict=1; SameSite=Strict; Secure; Path=/
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/align-content/masonry-align-content-003-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/align-content/masonry-align-content-003-ref.html
index 9780d5f5..9da15c0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/align-content/masonry-align-content-003-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/align-content/masonry-align-content-003-ref.html
@@ -8,31 +8,31 @@
   <title>Reference: Masonry layout with `align-content` in grid axis</title>
   <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
   <style>
-html,body {
-  color:black; background-color:white; font:15px/1 monospace; padding:0; margin:0;
-}
+    html,body {
+      color:black; background-color:white; font:15px/1 monospace; padding:0; margin:0;
+    }
 
-grid {
-  display: inline-grid;
-  gap: 1px 2px;
-  grid-template-columns: 1ch auto;
-  grid-template-rows: repeat(4,auto);
-  background: content-box silver;
-  border: 1px solid;
-  padding: 0 3px 2px 0;
-  width: 100px;
-  height: 120px;
-  align-content: center;
-  justify-items: start;
-}
+    grid {
+      display: inline-grid;
+      gap: 1px 2px;
+      grid-template-columns: 1ch auto;
+      grid-template-rows: repeat(4,19px);
+      background: content-box silver;
+      border: 1px solid;
+      padding: 0 3px 2px 0;
+      width: 100px;
+      height: 120px;
+      align-content: center;
+      justify-items: start;
+    }
 
-item {
-  background-color: #444;
-  color: #fff;
-}
+    item {
+      background-color: #444;
+      color: #fff;
+    }
 
-.tall { grid-row: span 2; padding: 3px 11px 1px 13px; }
-</style>
+    .tall { grid-row: span 2; padding: 3px 11px 1px 13px; }
+  </style>
 </head>
 <body>
 
@@ -90,7 +90,7 @@
   <item style="grid-row:3/4">6</item>
 </grid>
 
-<grid style="align-content:stretch">
+<grid style="align-content:stretch; grid-template-rows: repeat(4,29.25px);">
   <item class="tall" style="grid-row:1/2">1</item>
   <item style="grid-row:2/3">2</item>
   <item style="grid-row:3/4">3</item>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-grid-template-columns-computed-withcontent.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-grid-template-columns-computed-withcontent.html
index b36efb6..a799955 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-grid-template-columns-computed-withcontent.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-grid-template-columns-computed-withcontent.html
@@ -1,34 +1,34 @@
 <!DOCTYPE html>
 <html>
 <head>
-<meta charset="utf-8">
-<title>CSS Masonry Test: getComputedStyle().gridTemplateColumns</title>
-<link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-template-columns">
-<meta name="assert" content="grid-template-columns computed value is the keyword none or a computed track list.">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/css/support/computed-testcommon.js"></script>
-<style>
-  #target {
-    display: grid;
-    grid-template-rows: masonry;
-    font-size: 40px;
-    min-width: 200px;
-    width: 300px;
-    max-width: 400px;
-    min-height: 500px;
-    height: 600px;
-    max-height: 700px;
-  }
-  #child {
-    min-width: 20px;
-    width: 30px;
-    max-width: 40px;
-    min-height: 50px;
-    height: 60px;
-    max-height: 70px;
-  }
-</style>
+  <meta charset="utf-8">
+  <title>CSS Masonry Test: getComputedStyle().gridTemplateColumns</title>
+  <link rel="help" href="https://drafts.csswg.org/css-grid-1/#propdef-grid-template-columns">
+  <meta name="assert" content="grid-template-columns computed value is the keyword none or a computed track list.">
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/css/support/computed-testcommon.js"></script>
+  <style>
+    #target {
+      display: grid;
+      grid-template-rows: masonry;
+      font-size: 40px;
+      min-width: 200px;
+      width: 300px;
+      max-width: 400px;
+      min-height: 500px;
+      height: 600px;
+      max-height: 700px;
+    }
+    #child {
+      min-width: 20px;
+      width: 30px;
+      max-width: 40px;
+      min-height: 50px;
+      height: 60px;
+      max-height: 70px;
+    }
+  </style>
 </head>
 <body>
 <div id="container">
@@ -37,59 +37,59 @@
   </div>
 </div>
 <script>
-test_computed_value("grid-template-rows", 'masonry', 'masonry');
-test_computed_value("grid-template-columns", 'none', 'none'); // "none" without #child
+  test_computed_value("grid-template-rows", 'masonry', 'masonry');
+  test_computed_value("grid-template-columns", 'none', 'none'); // "none" without #child
 
-// track-size <fixed-breadth> = <length-percentage> | <flex> | min-content | max-content | auto
-test_computed_value("grid-template-columns", '20%', '60px'); // 20% * width
-test_computed_value("grid-template-columns", 'calc(-0.5em + 10px)', '0px');
-test_computed_value("grid-template-columns", 'calc(0.5em + 10px)', '30px');
-test_computed_value("grid-template-columns", 'calc(30% + 40px)', '130px'); // 30% * width + 40px
-test_computed_value("grid-template-columns", '5fr', '300px'); // width
-test_computed_value("grid-template-columns", 'min-content', '30px');
-test_computed_value("grid-template-columns", 'max-content', '30px');
-test_computed_value("grid-template-columns", 'auto', '300px'); // width
+  // track-size <fixed-breadth> = <length-percentage> | <flex> | min-content | max-content | auto
+  test_computed_value("grid-template-columns", '20%', '60px'); // 20% * width
+  test_computed_value("grid-template-columns", 'calc(-0.5em + 10px)', '0px');
+  test_computed_value("grid-template-columns", 'calc(0.5em + 10px)', '30px');
+  test_computed_value("grid-template-columns", 'calc(30% + 40px)', '130px'); // 30% * width + 40px
+  test_computed_value("grid-template-columns", '5fr', '300px'); // width
+  test_computed_value("grid-template-columns", 'min-content', '30px');
+  test_computed_value("grid-template-columns", 'max-content', '30px');
+  test_computed_value("grid-template-columns", 'auto', '300px'); // width
 
-// track-size minmax( <inflexible-breadth> , <track-breadth> )
-test_computed_value("grid-template-columns", 'minmax(10px, auto)', '300px'); // width
-test_computed_value("grid-template-columns", 'minmax(20%, max-content)', '60px'); // 20% * width
-test_computed_value("grid-template-columns", 'minmax(min-content, calc(-0.5em + 10px))', '30px');
-test_computed_value("grid-template-columns", 'minmax(auto, 0)', '30px');
+  // track-size minmax( <inflexible-breadth> , <track-breadth> )
+  test_computed_value("grid-template-columns", 'minmax(10px, auto)', '300px'); // width
+  test_computed_value("grid-template-columns", 'minmax(20%, max-content)', '60px'); // 20% * width
+  test_computed_value("grid-template-columns", 'minmax(min-content, calc(-0.5em + 10px))', '30px');
+  test_computed_value("grid-template-columns", 'minmax(auto, 0)', '30px');
 
-// track-size fit-content( <length-percentage> )
-test_computed_value("grid-template-columns", 'fit-content(70px)', '30px');
-test_computed_value("grid-template-columns", 'fit-content(20%)', '30px');
-test_computed_value("grid-template-columns", 'fit-content(calc(-0.5em + 10px))', '30px');
+  // track-size fit-content( <length-percentage> )
+  test_computed_value("grid-template-columns", 'fit-content(70px)', '30px');
+  test_computed_value("grid-template-columns", 'fit-content(20%)', '30px');
+  test_computed_value("grid-template-columns", 'fit-content(calc(-0.5em + 10px))', '30px');
 
-// <track-repeat> = repeat( [ <positive-integer> ] , [ <line-names>? <track-size> ]+ <line-names>? )
-test_computed_value("grid-template-columns", 'repeat(1, 10px)', '10px');
-test_computed_value("grid-template-columns", 'repeat(1, [one two] 20%)', '[one two] 60px');
-test_computed_value("grid-template-columns", 'repeat(2, minmax(10px, auto))', '160px 140px');
+  // <track-repeat> = repeat( [ <positive-integer> ] , [ <line-names>? <track-size> ]+ <line-names>? )
+  test_computed_value("grid-template-columns", 'repeat(1, 10px)', '10px');
+  test_computed_value("grid-template-columns", 'repeat(1, [one two] 20%)', '[one two] 60px');
+  test_computed_value("grid-template-columns", 'repeat(2, minmax(10px, auto))', '150px 150px');
 
-test_computed_value("grid-template-columns", 'repeat(2, fit-content(20%) [three four] 30px 40px [five six])',
-                    '30px [three four] 30px 40px [five six] 0px [three four] 30px 40px [five six]');
+  test_computed_value("grid-template-columns", 'repeat(2, fit-content(20%) [three four] 30px 40px [five six])',
+          '30px [three four] 30px 40px [five six] 30px [three four] 30px 40px [five six]');
 
-// <track-list> = [ <line-names>? [ <track-size> | <track-repeat> ] ]+ <line-names>?
-test_computed_value("grid-template-columns", 'min-content repeat(5, minmax(10px, auto))',
-                    '30px 54px 54px 54px 54px 54px');
-test_computed_value("grid-template-columns", '[] 150px [] 1fr []', '150px 150px');
+  // <track-list> = [ <line-names>? [ <track-size> | <track-repeat> ] ]+ <line-names>?
+  test_computed_value("grid-template-columns", 'min-content repeat(5, minmax(10px, auto))',
+          '30px 54px 54px 54px 54px 54px');
+  test_computed_value("grid-template-columns", '[] 150px [] 1fr []', '150px 150px');
 
-// <auto-repeat> = repeat( [ auto-fill | auto-fit ] , [ <line-names>? <fixed-size> ]+ <line-names>? )
-test_computed_value("grid-template-columns", 'repeat(auto-fill, 200px)', '200px');
-test_computed_value("grid-template-columns", 'repeat(auto-fit, [one] 20%)',
-                    '[one] 60px [one] 60px [one] 60px [one] 60px [one] 60px');
-test_computed_value("grid-template-columns", 'repeat(auto-fill, minmax(100px, 5fr) [two])',
-                    '100px [two] 100px [two] 100px [two]');
-test_computed_value("grid-template-columns", 'repeat(auto-fit, [three] minmax(max-content, 6em) [four])',
-                    '[three] 240px [four]');
+  // <auto-repeat> = repeat( [ auto-fill | auto-fit ] , [ <line-names>? <fixed-size> ]+ <line-names>? )
+  test_computed_value("grid-template-columns", 'repeat(auto-fill, 200px)', '200px');
+  test_computed_value("grid-template-columns", 'repeat(auto-fit, [one] 20%)',
+          '[one] 60px [one] 60px [one] 60px [one] 60px [one] 60px');
+  test_computed_value("grid-template-columns", 'repeat(auto-fill, minmax(100px, 5fr) [two])',
+          '100px [two] 100px [two] 100px [two]');
+  test_computed_value("grid-template-columns", 'repeat(auto-fit, [three] minmax(max-content, 6em) [four])',
+          '[three] 240px [four]');
 
-// <auto-track-list> =
-// [ <line-names>? [ <fixed-size> | <fixed-repeat> ] ]* <line-names>?
-// <auto-repeat>
-// [ <line-names>? [ <fixed-size> | <fixed-repeat> ] ]* <line-names>?
+  // <auto-track-list> =
+  // [ <line-names>? [ <fixed-size> | <fixed-repeat> ] ]* <line-names>?
+  // <auto-repeat>
+  // [ <line-names>? [ <fixed-size> | <fixed-repeat> ] ]* <line-names>?
 
-test_computed_value("grid-template-columns", '[one] repeat(2, minmax(50px, auto)) [two] 30px [three] repeat(auto-fill, 10px) 40px [four five] repeat(2, minmax(200px, auto)) [six]',
-                    '[one] 50px 50px [two] 30px [three] 10px 40px [four five] 200px 200px [six]');
+  test_computed_value("grid-template-columns", '[one] repeat(2, minmax(50px, auto)) [two] 30px [three] repeat(auto-fill, 10px) 40px [four five] repeat(2, minmax(200px, auto)) [six]',
+          '[one] 50px 50px [two] 30px [three] 10px 40px [four five] 200px 200px [six]');
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-viewport/zoom/scroll-top-test-with-zoom.html b/third_party/blink/web_tests/external/wpt/css/css-viewport/zoom/scroll-top-test-with-zoom.html
new file mode 100644
index 0000000..290fa60
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-viewport/zoom/scroll-top-test-with-zoom.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<title>Scroll Top Test with Zoom</title>
+<link rel="help" href="https://drafts.csswg.org/css-viewport/#zoom-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  #container {
+    width: 200px;
+    height: 100px;
+    border: solid thick;
+    overflow: auto;
+  }
+</style>
+<div id="container">
+  <div style="width: 100px; height: 2000px"></div>
+</div>
+
+<script>
+  var container = document.getElementById('container');
+  container.scrollTop = 77;
+  test(function() {
+    assert_equals(container.scrollTop, 77, "Initial scrollTop should be 77");
+  }, "Initial scrollTop with no zoom");
+
+  document.body.style.zoom = 1.2;
+  test(function() {
+    assert_approx_equals(container.scrollTop, 77, 0.99, "scrollTop should remain consistent within 1 px after zooming in");
+  }, "scrollTop after increasing zoom level");
+
+  document.body.style.zoom = 1;
+  test(function() {
+    assert_equals(container.scrollTop, 77, "scrollTop should remain consistent after resetting zoom");
+  }, "scrollTop after resetting zoom");
+  done();
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/images/img-sizes-auto-expected.txt b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/images/img-sizes-auto-expected.txt
index e7778d2f..57d5088a 100644
--- a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/images/img-sizes-auto-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/images/img-sizes-auto-expected.txt
@@ -1,26 +1,4 @@
 This is a testharness.js-based test.
-[FAIL] <img sizes="auto"> - contain
-  assert_equals: expected "size" but got "none"
-[FAIL] <img sizes="auto"> - contain-intrinsic-size
-  assert_equals: expected "300px 150px" but got "none"
-[FAIL] <img sizes="auto" width="10" height="20"> - contain
-  assert_equals: expected "size" but got "none"
-[FAIL] <img sizes="auto" width="10" height="20"> - contain-intrinsic-size
-  assert_equals: expected "300px 150px" but got "none"
-[FAIL] <img sizes="AuTo"> - contain
-  assert_equals: expected "size" but got "none"
-[FAIL] <img sizes="AuTo"> - contain-intrinsic-size
-  assert_equals: expected "300px 150px" but got "none"
-[FAIL] <img sizes="auto,xyz"> - contain
-  assert_equals: expected "size" but got "none"
-[FAIL] <img sizes="auto,xyz"> - contain-intrinsic-size
-  assert_equals: expected "300px 150px" but got "none"
-[FAIL] <img sizes="AuTo,xyz"> - contain
-  assert_equals: expected "size" but got "none"
-[FAIL] <img sizes="AuTo,xyz"> - contain-intrinsic-size
-  assert_equals: expected "300px 150px" but got "none"
-[FAIL] <img sizes="auto" class="test-important"> - contain
-  assert_equals: expected "size" but got "style"
 [FAIL] <img sizes="auto" class="test-important"> - contain-intrinsic-size
   assert_equals: expected "300px 150px" but got "30px 15px"
 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/sizes-auto-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/sizes-auto-expected.txt
deleted file mode 100644
index d8660751..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/sizes-auto-expected.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-This is a testharness.js-based test.
-Found 8 FAIL, 0 TIMEOUT, 0 NOTRUN.
-[FAIL] <img loading="lazy" sizes="auto" data-ref="ref2" srcset="/images/green-1x1.png?img14 50w, /images/green-16x16.png?img14 51w">
-  assert_equals: expected "http://web-platform.test:8001/images/green-16x16.png" but got "http://web-platform.test:8001/images/green-1x1.png"
-[FAIL] <picture><source srcset="/images/green-1x1.png?picture14 50w, /images/green-16x16.png?picture14 51w"><img loading="lazy" sizes="auto" data-ref="ref2"></picture>
-  assert_equals: expected "http://web-platform.test:8001/images/green-16x16.png" but got "http://web-platform.test:8001/images/green-1x1.png"
-[FAIL] <img loading="lazy" sizes="auto" style="min-inline-size: 10px" data-ref="ref2" srcset="/images/green-1x1.png?img25 50w, /images/green-16x16.png?img25 51w">
-  assert_equals: expected "http://web-platform.test:8001/images/green-16x16.png" but got "http://web-platform.test:8001/images/green-1x1.png"
-[FAIL] <picture><source srcset="/images/green-1x1.png?picture25 50w, /images/green-16x16.png?picture25 51w"><img loading="lazy" sizes="auto" style="min-inline-size: 10px" data-ref="ref2"></picture>
-  assert_equals: expected "http://web-platform.test:8001/images/green-16x16.png" but got "http://web-platform.test:8001/images/green-1x1.png"
-[FAIL] <img loading="lazy" sizes="auto" style="min-block-size: 10px; writing-mode: vertical-rl" data-ref="ref2" srcset="/images/green-1x1.png?img29 50w, /images/green-16x16.png?img29 51w">
-  assert_equals: expected "http://web-platform.test:8001/images/green-16x16.png" but got "http://web-platform.test:8001/images/green-1x1.png"
-[FAIL] <picture><source srcset="/images/green-1x1.png?picture29 50w, /images/green-16x16.png?picture29 51w"><img loading="lazy" sizes="auto" style="min-block-size: 10px; writing-mode: vertical-rl" data-ref="ref2"></picture>
-  assert_equals: expected "http://web-platform.test:8001/images/green-16x16.png" but got "http://web-platform.test:8001/images/green-1x1.png"
-[FAIL] <img loading="lazy" sizes="auto" style="position: absolute; left: 50%; right: 49%" data-ref="ref2" srcset="/images/green-1x1.png?img34 50w, /images/green-16x16.png?img34 51w">
-  assert_equals: expected "http://web-platform.test:8001/images/green-16x16.png" but got "http://web-platform.test:8001/images/green-1x1.png"
-[FAIL] <picture><source srcset="/images/green-1x1.png?picture34 50w, /images/green-16x16.png?picture34 51w"><img loading="lazy" sizes="auto" style="position: absolute; left: 50%; right: 49%" data-ref="ref2"></picture>
-  assert_equals: expected "http://web-platform.test:8001/images/green-16x16.png" but got "http://web-platform.test:8001/images/green-1x1.png"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/x-frame-options/invalid.html b/third_party/blink/web_tests/external/wpt/x-frame-options/invalid.html
index 26b2905..6c0ed90 100644
--- a/third_party/blink/web_tests/external/wpt/x-frame-options/invalid.html
+++ b/third_party/blink/web_tests/external/wpt/x-frame-options/invalid.html
@@ -40,6 +40,12 @@
 });
 
 xfo_simple_tests({
+  headerValue: `DE NY`,
+  sameOriginAllowed: true,
+  crossOriginAllowed: true
+});
+
+xfo_simple_tests({
   headerValue: `"SAMEORIGIN"`,
   sameOriginAllowed: true,
   crossOriginAllowed: true
diff --git a/third_party/blink/web_tests/fast/loader/javascript-url-hierarchical-execution-expected.txt b/third_party/blink/web_tests/fast/loader/javascript-url-hierarchical-execution-expected.txt
index 55c00ef5..d8f6c82 100644
--- a/third_party/blink/web_tests/fast/loader/javascript-url-hierarchical-execution-expected.txt
+++ b/third_party/blink/web_tests/fast/loader/javascript-url-hierarchical-execution-expected.txt
@@ -1,10 +1,9 @@
-<rdar://problem/6904941> and https://bugs.webkit.org/show_bug.cgi?id=25300
-
-This tests to see what WebKit does with javascript urls of the form "javascript://".
-On the one hand, these are detected as hierarchical urls and usually marked invalid.
-On the other hand, the contents after "javascript:" are valid javascript code - a comment - that should be executed.
-If you click the link below and WebKit navigates - probably to an error page - then we're marking it as an invalid hierarchical URL and not trying to execute it.
-Instead, clicking it should appear to do nothing and you should remain at this page.
+This tests to see what Chromium does with invalid javascript urls of the form "javascript://".
+These should be detected as hierarchical, but invalid urls if the host part includes spaces.
+JavaScript execution nor navigation should not happen and you should remain at this page.
+On the other hand, if the contents after "javascript:" are considered valid javascript code, a comment, that may be executed and you should remain at this page too.
+See wpt/url/javascript-urls.window.js, which tests whether javascript code is executed or not.
+If you click the link below and Chromium tries to navigate - probably to an error page - then the test failed.
 In DumpRenderTree, if the custom policy delegate indicates that a load was attempted, then the test failed.
 
 Click me to test
diff --git a/third_party/blink/web_tests/fast/loader/javascript-url-hierarchical-execution.html b/third_party/blink/web_tests/fast/loader/javascript-url-hierarchical-execution.html
index 4cb1491..627ee4e 100644
--- a/third_party/blink/web_tests/fast/loader/javascript-url-hierarchical-execution.html
+++ b/third_party/blink/web_tests/fast/loader/javascript-url-hierarchical-execution.html
@@ -1,3 +1,4 @@
+<!doctype html>
 <html>
 <script>
 if (window.testRunner) {
@@ -13,12 +14,12 @@
 }
 </script>
 <body onload="runTest();">
-&lt;<a href="rdar://problem/6904941">rdar://problem/6904941</a>&gt; and <a href="https://bugs.webkit.org/show_bug.cgi?id=25300">https://bugs.webkit.org/show_bug.cgi?id=25300</a><br><br>
-This tests to see what WebKit does with javascript urls of the form "javascript://".<br>
-On the one hand, these are detected as hierarchical urls and usually marked invalid.<br>
-On the other hand, the contents after "javascript:" are valid javascript code - a comment - that should be executed.<br>
-If you click the link below and WebKit navigates - probably to an error page - then we're marking it as an invalid hierarchical URL and not trying to execute it.<br>
-Instead, clicking it should appear to do nothing and you should remain at this page.<br>
+This tests to see what Chromium does with invalid javascript urls of the form "javascript://".<br>
+These should be detected as hierarchical, but invalid urls if the host part includes spaces.<br>
+JavaScript execution nor navigation should not happen and you should remain at this page.<br>
+On the other hand, if the contents after "javascript:" are considered valid javascript code, a comment, that may be executed and you should remain at this page too.<br>
+See wpt/url/javascript-urls.window.js, which tests whether javascript code is executed or not.<br>
+If you click the link below and Chromium tries to navigate - probably to an error page - then the test failed.<br>
 In DumpRenderTree, if the custom policy delegate indicates that a load was attempted, then the test failed.<br><br>
 <a id="clickTest" href="javascript://Spaceballs: The Comment!">Click me to test</a>
 </body>
diff --git a/third_party/blink/web_tests/fast/scrolling/fractional-scroll-offset-document.html b/third_party/blink/web_tests/fast/scrolling/fractional-scroll-offset-document.html
index c7d33ed8..1e71ca09 100644
--- a/third_party/blink/web_tests/fast/scrolling/fractional-scroll-offset-document.html
+++ b/third_party/blink/web_tests/fast/scrolling/fractional-scroll-offset-document.html
@@ -31,18 +31,8 @@
         await waitForCompositorCommit();
       }
 
-      let expected_scroll = distance / window.visualViewport.scale;
-
-      // If fractional scroll offsets are enabled, the expected scroll offset
-      // should be the actuall fractional distance we scrolled. Otherwise the
-      // offset should be truncated.
-      if (internals.runtimeFlags.fractionalScrollOffsetsEnabled) {
-        assert_not_equals(expected_scroll,
-                          Math.round(expected_scroll),
-                          'Expected scroll should be fractional');
-      } else {
-        expected_scroll = Math.floor(expected_scroll);
-      }
+      // We always truncate the scroll offset.
+      let expected_scroll = Math.floor(distance / window.visualViewport.scale);
 
       // Scroll Vertically
       await smoothScroll(distance,
diff --git a/third_party/blink/web_tests/fast/scrolling/scrollbars/touch-scrolling-on-root-scrollbar.html b/third_party/blink/web_tests/fast/scrolling/scrollbars/touch-scrolling-on-root-scrollbar.html
index 1bc08fc..04273b1 100644
--- a/third_party/blink/web_tests/fast/scrolling/scrollbars/touch-scrolling-on-root-scrollbar.html
+++ b/third_party/blink/web_tests/fast/scrolling/scrollbars/touch-scrolling-on-root-scrollbar.html
@@ -63,7 +63,7 @@
     position.y -= trackOffset;
     await touchTapScroll(position.x, position.y, document);
 
-    assert_true(Math.abs(window.scrollY - 512) < 1,
+    assert_true(Math.abs(window.scrollY - 512) <= 1,
                 "Pressing the down trackpart didn't scroll.");
 
     // Tap on the track part just below the up arrow.
@@ -77,7 +77,7 @@
     position = rightArrow();
     position.x -= trackOffset;
     await touchTapScroll(position.x, position.y, document);
-    assert_true(Math.abs(window.scrollX - 687) < 1,
+    assert_true(Math.abs(window.scrollX - 687) <= 1,
                 "Pressing the right trackpart didn't scroll.");
 
     // Tap on the track part just to the right of the left arrow.
diff --git a/third_party/blink/web_tests/fast/scrolling/scrolling-apis-subpixel.html b/third_party/blink/web_tests/fast/scrolling/scrolling-apis-subpixel.html
index 72edd25..60a4ef3 100644
--- a/third_party/blink/web_tests/fast/scrolling/scrolling-apis-subpixel.html
+++ b/third_party/blink/web_tests/fast/scrolling/scrolling-apis-subpixel.html
@@ -55,11 +55,6 @@
   const setOffset = 4.2;
   let expectedOffset = 4;
 
-  // When fractional offsets are enabled, we should allow setting a fractional
-  // scroll offset.
-  if (internals.runtimeFlags.fractionalScrollOffsetsEnabled)
-    expectedOffset = 4.2;
-
   testScroll(setOffset, expectedOffset);
 }, "Set fractional scroll offset without zoom");
 
@@ -80,11 +75,6 @@
   const setOffset = 4.6;
   let expectedOffset = 4.5;
 
-  // When fractional offsets are enabled, we should allow setting a fractional
-  // scroll offset.
-  if (internals.runtimeFlags.fractionalScrollOffsetsEnabled)
-    expectedOffset = 4.6;
-
   testScroll(setOffset, expectedOffset);
 }, "Set fractional scroll offset to higher granularity when zoomed.");
 
diff --git a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/javascript-urls.window-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/javascript-urls.window-expected.txt
index 8b13789..d2490db 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/javascript-urls.window-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/javascript-urls.window-expected.txt
@@ -1 +1,3 @@
+This is a testharness.js-based test.
+Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/fast/loader/javascript-url-hierarchical-execution-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/fast/loader/javascript-url-hierarchical-execution-expected.txt
deleted file mode 100644
index e211841a1..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/fast/loader/javascript-url-hierarchical-execution-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Policy delegate: attempt to load javascript://Spaceballs:%20The%20Comment! with navigation type 'link clicked'
-
diff --git a/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/reduction.https.any-expected.txt b/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/reduction.https.any-expected.txt
new file mode 100644
index 0000000..d2490db
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/reduction.https.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/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/reduction.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/reduction.https.any.worker-expected.txt
new file mode 100644
index 0000000..d2490db
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/reduction.https.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/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/reduction.https.any-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/reduction.https.any-expected.txt
index 382308bb..7578bb7f 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/reduction.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/reduction.https.any-expected.txt
@@ -1,322 +1,88 @@
 This is a testharness.js-based test.
-Found 159 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 42 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] reduceL1 float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceL1 float32 actual 1092.4423828125 should be close enough to expected 1092.72021484375 by the acceptable 24 ULP distance, but they have 2276 ULP distance expected true got false
 [FAIL] reduceL2 float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceL2 float32 actual 272.0086669921875 should be close enough to expected 272.0996398925781 by the acceptable 49 ULP distance, but they have 2981 ULP distance expected true got false
 [FAIL] reduceLogSum float32 1D constant tensor all non-negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 1D tensor all non-negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 1D tensor all non-negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSum float32 actual 7.038625717163086 should be close enough to expected 7.039101600646973 by the acceptable 42 ULP distance, but they have 998 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 1.1667110919952393 should be close enough to expected 1.1666961908340454 by the acceptable 66 ULP distance, but they have 125 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 9.606844902038574 should be close enough to expected 9.607237815856934 by the acceptable 66 ULP distance, but they have 412 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 0.699594259262085 should be close enough to expected 0.7001367211341858 by the acceptable 66 ULP distance, but they have 9101 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 8.547489166259766 should be close enough to expected 8.55212688446045 by the acceptable 26 ULP distance, but they have 4863 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 4.666667461395264 should be close enough to expected 4.66951847076416 by the acceptable 26 ULP distance, but they have 5979 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 8.559198379516602 should be close enough to expected 8.563796997070312 by the acceptable 30 ULP distance, but they have 4822 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 8.559198379516602 should be close enough to expected 8.563796997070312 by the acceptable 30 ULP distance, but they have 4822 ULP distance expected true got false
 [FAIL] reduceMax float32 1D constant tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 1D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceMax float32 actual 99.75 should be close enough to expected 99.77313232421875 by the acceptable 0 ULP distance, but they have 3032 ULP distance expected true got false
 [FAIL] reduceMean float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceMean float32 actual 40.29948043823242 should be close enough to expected 40.31047439575195 by the acceptable 26 ULP distance, but they have 2882 ULP distance expected true got false
 [FAIL] reduceMin float32 1D constant tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 1D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceMin float32 actual -87.9375 should be close enough to expected -87.9623031616211 by the acceptable 0 ULP distance, but they have 3251 ULP distance expected true got false
 [FAIL] reduceProduct float32 1D constant tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 1D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceProduct float32 actual 1.5725944736131119e+37 should be close enough to expected 1.5855958784642327e+37 by the acceptable 24 ULP distance, but they have 102563 ULP distance expected true got false
 [FAIL] reduceSum float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSum float32 actual 1313.4765625 should be close enough to expected 1313.87939453125 by the acceptable 24 ULP distance, but they have 3300 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 79968.96875 should be close enough to expected 80052.015625 by the acceptable 48 ULP distance, but they have 10630 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 71329.5 should be close enough to expected 71347 by the acceptable 48 ULP distance, but they have 2240 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73619.4375 should be close enough to expected 73634 by the acceptable 48 ULP distance, but they have 1864 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 9696.140625 should be close enough to expected 9709.013671875 by the acceptable 8 ULP distance, but they have 13182 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 8576.25 should be close enough to expected 8585.87109375 by the acceptable 8 ULP distance, but they have 9852 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 12288.390625 should be close enough to expected 12302.474609375 by the acceptable 12 ULP distance, but they have 14422 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 12288.390625 should be close enough to expected 12302.474609375 by the acceptable 12 ULP distance, but they have 14422 ULP distance expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/reduction.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/reduction.https.any.worker-expected.txt
index 382308bb..7578bb7f 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/reduction.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gpu/reduction.https.any.worker-expected.txt
@@ -1,322 +1,88 @@
 This is a testharness.js-based test.
-Found 159 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 42 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] reduceL1 float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL1 float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceL1 float32 actual 1092.4423828125 should be close enough to expected 1092.72021484375 by the acceptable 24 ULP distance, but they have 2276 ULP distance expected true got false
 [FAIL] reduceL2 float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceL2 float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceL2 float32 actual 272.0086669921875 should be close enough to expected 272.0996398925781 by the acceptable 49 ULP distance, but they have 2981 ULP distance expected true got false
 [FAIL] reduceLogSum float32 1D constant tensor all non-negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 1D tensor all non-negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 1D tensor all non-negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceLogSum float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSum float32 actual 7.038625717163086 should be close enough to expected 7.039101600646973 by the acceptable 42 ULP distance, but they have 998 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 1.1667110919952393 should be close enough to expected 1.1666961908340454 by the acceptable 66 ULP distance, but they have 125 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 9.606844902038574 should be close enough to expected 9.607237815856934 by the acceptable 66 ULP distance, but they have 412 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 0.699594259262085 should be close enough to expected 0.7001367211341858 by the acceptable 66 ULP distance, but they have 9101 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 8.547489166259766 should be close enough to expected 8.55212688446045 by the acceptable 26 ULP distance, but they have 4863 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 4.666667461395264 should be close enough to expected 4.66951847076416 by the acceptable 26 ULP distance, but they have 5979 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 10.39249324798584 should be close enough to expected 10.39477825164795 by the acceptable 66 ULP distance, but they have 2396 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 8.559198379516602 should be close enough to expected 8.563796997070312 by the acceptable 30 ULP distance, but they have 4822 ULP distance expected true got false
 [FAIL] reduceLogSumExp float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceLogSumExp float32 actual 8.559198379516602 should be close enough to expected 8.563796997070312 by the acceptable 30 ULP distance, but they have 4822 ULP distance expected true got false
 [FAIL] reduceMax float32 1D constant tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 1D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMax float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceMax float32 actual 99.75 should be close enough to expected 99.77313232421875 by the acceptable 0 ULP distance, but they have 3032 ULP distance expected true got false
 [FAIL] reduceMean float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMean float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceMean float32 actual 40.29948043823242 should be close enough to expected 40.31047439575195 by the acceptable 26 ULP distance, but they have 2882 ULP distance expected true got false
 [FAIL] reduceMin float32 1D constant tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 1D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceMin float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceMin float32 actual -87.9375 should be close enough to expected -87.9623031616211 by the acceptable 0 ULP distance, but they have 3251 ULP distance expected true got false
 [FAIL] reduceProduct float32 1D constant tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 1D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceProduct float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceProduct float32 actual 1.5725944736131119e+37 should be close enough to expected 1.5855958784642327e+37 by the acceptable 24 ULP distance, but they have 102563 ULP distance expected true got false
 [FAIL] reduceSum float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
-[FAIL] reduceSum float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSum float32 actual 1313.4765625 should be close enough to expected 1313.87939453125 by the acceptable 24 ULP distance, but they have 3300 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 79968.96875 should be close enough to expected 80052.015625 by the acceptable 48 ULP distance, but they have 10630 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 71329.5 should be close enough to expected 71347 by the acceptable 48 ULP distance, but they have 2240 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73619.4375 should be close enough to expected 73634 by the acceptable 48 ULP distance, but they have 1864 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 9696.140625 should be close enough to expected 9709.013671875 by the acceptable 8 ULP distance, but they have 13182 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 8576.25 should be close enough to expected 8585.87109375 by the acceptable 8 ULP distance, but they have 9852 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 73193.703125 should be close enough to expected 73275.859375 by the acceptable 48 ULP distance, but they have 10516 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 12288.390625 should be close enough to expected 12302.474609375 by the acceptable 12 ULP distance, but they have 14422 ULP distance expected true got false
 [FAIL] reduceSumSquare float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': This operator is not implemented."
+  assert_true: assert_array_approx_equals_ulp: test reduceSumSquare float32 actual 12288.390625 should be close enough to expected 12302.474609375 by the acceptable 12 ULP distance, but they have 14422 ULP distance expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/wpt_internal/credential-management/fedcm-continueon-bundle-origin-trial.https.html b/third_party/blink/web_tests/wpt_internal/credential-management/fedcm-continueon-bundle-origin-trial.https.html
new file mode 100644
index 0000000..07893e6f
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/credential-management/fedcm-continueon-bundle-origin-trial.https.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Federated Credential Management API continue_on bundle origin trial tests.</title>
+<link rel="help" href="https://fedidcg.github.io/FedCM">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<!--
+Token generated with:
+generate_token.py https://web-platform.test:8444/ FedCmContinueOnBundle --expire-timestamp=2000000000
+-->
+<meta http-equiv="origin-trial"
+  content="A2t+kt2KUe7JyS8aAQ+nvuycueGWpr3uiVHtyG3WfvF8ppFyOopY5Xrd8Ag8mh1LKBolZQmhwpGmcEUJNWn8bg0AAABmeyJvcmlnaW4iOiAiaHR0cHM6Ly93ZWItcGxhdGZvcm0udGVzdDo4NDQ0IiwgImZlYXR1cmUiOiAiRmVkQ21Db250aW51ZU9uQnVuZGxlIiwgImV4cGlyeSI6IDIwMDAwMDAwMDB9">
+
+<body>
+
+<script type="module">
+import {fedcm_test,
+        alt_request_options_with_mediation_required,
+        select_manifest,
+        fedcm_get_and_select_first_account} from '/credential-management/support/fedcm-helper.sub.js';
+
+promise_test(async t => {
+  assert_true("resolve" in IdentityProvider);
+}, "Test that functions exist where we expect them.");
+
+fedcm_test(async t => {
+  const options = alt_request_options_with_mediation_required('../../../wpt_internal/credential-management/resources/fedcm/manifest_with_continue_on.json');
+  await select_manifest(t, options);
+  const cred = await fedcm_get_and_select_first_account(t, options);
+  assert_equals(cred.token, "account=1234");
+}, "Test that continue_on works as expected");
+</script>
+
diff --git a/third_party/blink/web_tests/wpt_internal/credential-management/resources/fedcm/continue_on.py b/third_party/blink/web_tests/wpt_internal/credential-management/resources/fedcm/continue_on.py
new file mode 100644
index 0000000..f8aa034
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/credential-management/resources/fedcm/continue_on.py
@@ -0,0 +1,19 @@
+import importlib
+
+error_checker = importlib.import_module(
+    "credential-management.support.fedcm.request-params-check")
+
+
+def main(request, response):
+    request_error = error_checker.tokenCheck(request)
+    if (request_error):
+        return request_error
+
+    response.headers.set(b"Content-Type", b"application/json")
+    response.headers.set(b"Access-Control-Allow-Origin",
+                         request.headers.get(b"Origin"))
+    response.headers.set(b"Access-Control-Allow-Credentials", "true")
+
+    account = request.POST.get(b"account_id").decode("utf-8")
+    return "{\"continue_on\": \"resolve_with_ot_token.html?selected=%s\"}" % (
+        account)
diff --git a/third_party/blink/web_tests/wpt_internal/credential-management/resources/fedcm/manifest_with_continue_on.json b/third_party/blink/web_tests/wpt_internal/credential-management/resources/fedcm/manifest_with_continue_on.json
new file mode 100644
index 0000000..788b1940
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/credential-management/resources/fedcm/manifest_with_continue_on.json
@@ -0,0 +1,6 @@
+{
+  "accounts_endpoint": "/credential-management/support/fedcm/accounts_no_approved_clients.py",
+  "id_assertion_endpoint": "continue_on.py",
+  "login_url": "/credential-management/support/fedcm/login.html"
+}
+
diff --git a/third_party/blink/web_tests/wpt_internal/credential-management/resources/fedcm/resolve_with_ot_token.html b/third_party/blink/web_tests/wpt_internal/credential-management/resources/fedcm/resolve_with_ot_token.html
new file mode 100644
index 0000000..057a6bf
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/credential-management/resources/fedcm/resolve_with_ot_token.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<!--
+Token generated with:
+generate_token.py https://not-web-platform.test:8444/ FedCmContinueOnBundle --expire-timestamp=2000000000
+-->
+<meta http-equiv="origin-trial"
+  content="A/ffmkhXGcnDAM30fvtHxYrAQ7mbjfsUY6Icx8jaRPRw6nt1ICOHbz9arNEi6QwdYtv2LquKjgANjGWl4jB5PAEAAABqeyJvcmlnaW4iOiAiaHR0cHM6Ly9ub3Qtd2ViLXBsYXRmb3JtLnRlc3Q6ODQ0NCIsICJmZWF0dXJlIjogIkZlZENtQ29udGludWVPbkJ1bmRsZSIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ==">
+<script>
+async function doResolve() {
+  const params = new URLSearchParams(document.location.search);
+  const token = "account=" + params.get("selected");
+  IdentityProvider.resolve(token, {});
+}
+window.onload = doResolve;
+</script>
+
diff --git a/third_party/catapult b/third_party/catapult
index 704b021..13025491 160000
--- a/third_party/catapult
+++ b/third_party/catapult
@@ -1 +1 @@
-Subproject commit 704b0216566e888ea8c3c1680d21bbf2e721faae
+Subproject commit 13025491e512e6e7b4c7fca376267fb82acad09b
diff --git a/third_party/chromium-variations b/third_party/chromium-variations
index 1b58345..2c42322 160000
--- a/third_party/chromium-variations
+++ b/third_party/chromium-variations
@@ -1 +1 @@
-Subproject commit 1b58345810cd9c9a284efbe6312e1fa7305acd71
+Subproject commit 2c423221c10e3c749e2ff9d952424544e8919d7d
diff --git a/third_party/dawn b/third_party/dawn
index ba00f41c..b4d05de 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit ba00f41c0e3365e638fee70983ca10ddfbe2a2ee
+Subproject commit b4d05dec16507b5a6fc832dfb56a9e6489a13302
diff --git a/third_party/depot_tools b/third_party/depot_tools
index 05d20bc..332c4eb 160000
--- a/third_party/depot_tools
+++ b/third_party/depot_tools
@@ -1 +1 @@
-Subproject commit 05d20bc699768f6185938cbc426876986cc68a69
+Subproject commit 332c4eb546eccaa4fa1a524d89c9c82194b8b998
diff --git a/third_party/lit/v3_0/lit.ts b/third_party/lit/v3_0/lit.ts
index 5bf4d45..94a387ed 100644
--- a/third_party/lit/v3_0/lit.ts
+++ b/third_party/lit/v3_0/lit.ts
@@ -2,5 +2,5 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-export {css, CSSResultGroup, html, LitElement, nothing, PropertyValues} from 'lit/index.js';
+export {css, CSSResultGroup, html, LitElement, nothing, render, PropertyValues} from 'lit/index.js';
 export {CrLitElement} from './cr_lit_element.js';
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium
index a891cfa..343798a 100644
--- a/third_party/nearby/README.chromium
+++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@
 Name: Nearby Connections Library
 Short Name: Nearby
 URL: https://github.com/google/nearby
-Version: f788b891908dd93274918e5b919e09136f3f1efd
+Version: 35a8289ef40bf67c6f4586a21f9325e7ad9b1c43
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/third_party/nearby/src b/third_party/nearby/src
index f788b891..35a8289 160000
--- a/third_party/nearby/src
+++ b/third_party/nearby/src
@@ -1 +1 @@
-Subproject commit f788b891908dd93274918e5b919e09136f3f1efd
+Subproject commit 35a8289ef40bf67c6f4586a21f9325e7ad9b1c43
diff --git a/third_party/skia b/third_party/skia
index 98dbba2..e335a0a 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 98dbba281a8443156105ecdb5aeece0b7fd0345f
+Subproject commit e335a0a11aa08b3926d179e84e26eae229a2e779
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps
index 8dc5cb5..1517f06 160000
--- a/third_party/vulkan-deps
+++ b/third_party/vulkan-deps
@@ -1 +1 @@
-Subproject commit 8dc5cb57074c42295aa647ea407e1adb85f6ec93
+Subproject commit 1517f06f64fc0b4181a15a188c8e851ba067dfb9
diff --git a/third_party/webgpu-cts/src b/third_party/webgpu-cts/src
index f648fd6..a75ea0e 160000
--- a/third_party/webgpu-cts/src
+++ b/third_party/webgpu-cts/src
@@ -1 +1 @@
-Subproject commit f648fd6de71e4888b05e247087e77273eb4871da
+Subproject commit a75ea0e849f517c52b993f0b69f75f1b7c286a49
diff --git a/third_party/webgpu-cts/ts_sources.txt b/third_party/webgpu-cts/ts_sources.txt
index 8c1e27a..82e22290 100644
--- a/third_party/webgpu-cts/ts_sources.txt
+++ b/third_party/webgpu-cts/ts_sources.txt
@@ -786,6 +786,7 @@
 src/webgpu/shader/validation/expression/call/builtin/pack4xI8Clamp.spec.ts
 src/webgpu/shader/validation/expression/call/builtin/pack4xU8.spec.ts
 src/webgpu/shader/validation/expression/call/builtin/pack4xU8Clamp.spec.ts
+src/webgpu/shader/validation/expression/call/builtin/pow.spec.ts
 src/webgpu/shader/validation/expression/call/builtin/quantizeToF16.spec.ts
 src/webgpu/shader/validation/expression/call/builtin/radians.spec.ts
 src/webgpu/shader/validation/expression/call/builtin/reflect.spec.ts
@@ -845,19 +846,25 @@
 src/webgpu/shader/validation/parse/diagnostic.spec.ts
 src/webgpu/shader/validation/parse/discard.spec.ts
 src/webgpu/shader/validation/parse/enable.spec.ts
+src/webgpu/shader/validation/parse/for.spec.ts
 src/webgpu/shader/validation/parse/identifiers.spec.ts
+src/webgpu/shader/validation/parse/if.spec.ts
 src/webgpu/shader/validation/parse/increment_decrement.spec.ts
 src/webgpu/shader/validation/parse/literal.spec.ts
+src/webgpu/shader/validation/parse/loop.spec.ts
 src/webgpu/shader/validation/parse/must_use.spec.ts
 src/webgpu/shader/validation/parse/phony.spec.ts
 src/webgpu/shader/validation/parse/pipeline_stage.spec.ts
 src/webgpu/shader/validation/parse/requires.spec.ts
+src/webgpu/shader/validation/parse/return.spec.ts
 src/webgpu/shader/validation/parse/semicolon.spec.ts
 src/webgpu/shader/validation/parse/shadow_builtins.spec.ts
 src/webgpu/shader/validation/parse/source.spec.ts
 src/webgpu/shader/validation/parse/statement_behavior.spec.ts
+src/webgpu/shader/validation/parse/switch.spec.ts
 src/webgpu/shader/validation/parse/unary_ops.spec.ts
 src/webgpu/shader/validation/parse/var_and_let.spec.ts
+src/webgpu/shader/validation/parse/while.spec.ts
 src/webgpu/shader/validation/shader_io/binding.spec.ts
 src/webgpu/shader/validation/shader_io/util.ts
 src/webgpu/shader/validation/shader_io/builtins.spec.ts
@@ -871,8 +878,14 @@
 src/webgpu/shader/validation/shader_io/locations.spec.ts
 src/webgpu/shader/validation/shader_io/size.spec.ts
 src/webgpu/shader/validation/shader_io/workgroup_size.spec.ts
+src/webgpu/shader/validation/statement/for.spec.ts
+src/webgpu/shader/validation/statement/if.spec.ts
 src/webgpu/shader/validation/statement/increment_decrement.spec.ts
+src/webgpu/shader/validation/statement/loop.spec.ts
 src/webgpu/shader/validation/statement/phony.spec.ts
+src/webgpu/shader/validation/statement/return.spec.ts
+src/webgpu/shader/validation/statement/switch.spec.ts
+src/webgpu/shader/validation/statement/while.spec.ts
 src/webgpu/shader/validation/types/alias.spec.ts
 src/webgpu/shader/validation/types/array.spec.ts
 src/webgpu/shader/validation/types/atomics.spec.ts
diff --git a/third_party/webrtc b/third_party/webrtc
index de7e4ad..655c890 160000
--- a/third_party/webrtc
+++ b/third_party/webrtc
@@ -1 +1 @@
-Subproject commit de7e4ad1b1cb9b6d15cac281820399a613d6d971
+Subproject commit 655c89088f563cd553595ec707b312c62a6efc02
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index 7f9f056..023fc28 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -2575,6 +2575,15 @@
   </summary>
 </histogram>
 
+<histogram name="Android.Omnibox.SearchActivity.LaunchedWithQuery"
+    enum="Boolean" expires_after="2024-09-01">
+  <owner>ender@chromium.org</owner>
+  <summary>
+    Records whether intent used to launch / update SearchActivity carried an
+    (optional) User Query. Recorded once per intent.
+  </summary>
+</histogram>
+
 <histogram name="Android.Omnibox.SetGeolocationHeadersTime" units="ms"
     expires_after="2024-04-28">
   <owner>spelchat@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index 3c7e528f..c4db198a 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -37,6 +37,8 @@
   <variant name=".AppInstallUriLauncher"
       summary="URI navigation from Launcher"/>
   <variant name=".AppInstallUriMall" summary="URI navigation from Mall"/>
+  <variant name=".AppInstallUriPeripherals"
+      summary="URI navigation from peripherals"/>
   <variant name=".AppInstallUriShowoff" summary="URI navigation from Showoff"/>
   <variant name=".AppInstallUriUnknown" summary="URI navigation from unknown"/>
   <variant name=".AppPreloadServiceDefault" summary="Default preload"/>
diff --git a/tools/metrics/histograms/metadata/nearby/histograms.xml b/tools/metrics/histograms/metadata/nearby/histograms.xml
index 87804dd..d98f33f3 100644
--- a/tools/metrics/histograms/metadata/nearby/histograms.xml
+++ b/tools/metrics/histograms/metadata/nearby/histograms.xml
@@ -429,6 +429,20 @@
 </histogram>
 
 <histogram
+    name="Nearby.Presence.Credentials.Storage.LocalPublicDatabaseInitializationDuration"
+    units="microseconds" expires_after="2025-04-10">
+  <owner>hansberry@chromium.org</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    Records time spent to retrieve local public credentials database in the
+    Nearby Presence Credential Storage component. Emitted after a successful
+    retrieval from the database. No metric is emitted on failure.
+
+    Note: This is only recorded on devices with high-resolution clocks.
+  </summary>
+</histogram>
+
+<histogram
     name="Nearby.Presence.Credentials.Storage.LocalPublicDatabaseInitializationResult"
     enum="BooleanSuccess" expires_after="2024-07-10">
   <owner>polner@google.com</owner>
@@ -441,6 +455,20 @@
 </histogram>
 
 <histogram
+    name="Nearby.Presence.Credentials.Storage.PrivateDatabaseInitializationDuration"
+    units="microseconds" expires_after="2025-04-10">
+  <owner>hansberry@chromium.org</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    Records time spent to initialize the private credentials database in the
+    Nearby Presence Credential Storage component. Emitted after a successful
+    retrieval from the database. No metric is emitted on failure.
+
+    Note: This is only recorded on devices with high-resolution clocks.
+  </summary>
+</histogram>
+
+<histogram
     name="Nearby.Presence.Credentials.Storage.PrivateDatabaseInitializationResult"
     enum="BooleanSuccess" expires_after="2024-07-10">
   <owner>polner@google.com</owner>
@@ -453,6 +481,20 @@
 </histogram>
 
 <histogram
+    name="Nearby.Presence.Credentials.Storage.RemotePublicDatabaseInitializationDuration"
+    units="microseconds" expires_after="2025-04-10">
+  <owner>hansberry@chromium.org</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    Records time spent to initialize the remote public credentials database in
+    the Nearby Presence Credential Storage component. Emitted after a successful
+    retrieval from the database. No metric is emitted on failure.
+
+    Note: This is only recorded on devices with high-resolution clocks.
+  </summary>
+</histogram>
+
+<histogram
     name="Nearby.Presence.Credentials.Storage.RemotePublicDatabaseInitializationResult"
     enum="BooleanSuccess" expires_after="2024-07-10">
   <owner>polner@google.com</owner>
@@ -465,6 +507,48 @@
 </histogram>
 
 <histogram
+    name="Nearby.Presence.Credentials.Storage.RetrieveLocalPublicCredentialsDuration"
+    units="microseconds" expires_after="2025-04-10">
+  <owner>hansberry@chromium.org</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    Records time spent to retrieve local public credentials from the Nearby
+    Presence Credential Storage component. Emitted after a successful retrieval
+    from the database. No metric is emitted on failure.
+
+    Note: This is only recorded on devices with high-resolution clocks.
+  </summary>
+</histogram>
+
+<histogram
+    name="Nearby.Presence.Credentials.Storage.RetrievePrivateCredentialsDuration"
+    units="microseconds" expires_after="2025-04-10">
+  <owner>hansberry@chromium.org</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    Records time spent to retrieve private credentials from the Nearby Presence
+    Credential Storage component. Emitted after a successful retrieval from the
+    database. No metric is emitted on failure.
+
+    Note: This is only recorded on devices with high-resolution clocks.
+  </summary>
+</histogram>
+
+<histogram
+    name="Nearby.Presence.Credentials.Storage.RetrieveRemotePublicCredentialsDuration"
+    units="microseconds" expires_after="2025-04-10">
+  <owner>hansberry@chromium.org</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    Records time spent to retrieve remote public credentials from the Nearby
+    Presence Credential Storage component. Emitted after a successful retrieval
+    from the database. No metric is emitted on failure.
+
+    Note: This is only recorded on devices with high-resolution clocks.
+  </summary>
+</histogram>
+
+<histogram
     name="Nearby.Presence.Credentials.Storage.SaveLocalPublicCredentials.Result"
     enum="BooleanSuccess" expires_after="2024-07-10">
   <owner>polner@google.com</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 82f4290..91d12cc1 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,7 +6,7 @@
         },
         "win": {
             "hash": "e9546a228dde6370daa783df4651dd5a658fa0de",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/5d734eb03fa2bd8b58c8b7504c33827a3f3888ce/trace_processor_shell.exe"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/300953f95157afdb385bb1ec41a1ec9c6f7ed38b/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "d8e27d961be1db97db098c6826017aec0397ecfd",
@@ -21,8 +21,8 @@
             "full_remote_path": "perfetto-luci-artifacts/v44.0/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "52e07f1ed20fa894064fb887dba67821e422df71",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/5d734eb03fa2bd8b58c8b7504c33827a3f3888ce/trace_processor_shell"
+            "hash": "18ffa72b1531ede7e5620e2b408234d05d396d4e",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/300953f95157afdb385bb1ec41a1ec9c6f7ed38b/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/utr/recipe.py b/tools/utr/recipe.py
index 45c03f6f..1687a62 100644
--- a/tools/utr/recipe.py
+++ b/tools/utr/recipe.py
@@ -150,20 +150,20 @@
     }
     self._input_props = input_props
 
-  def _run(self, adapter, additional_props=None):
+  def _run(self, adapter, rerun_props=None):
     """Internal implementation of invoking `recipes.py run`.
 
     Args:
       adapter: A output_adapter.Adapter for parsing recipe output.
-      additional_props: Dict containing additional props to pass to the recipe.
+      rerun_props: Dict containing additional props to pass to the recipe.
     Returns:
       Tuple of
         exit code of the `recipes.py` invocation,
         summary markdown of the `recipes.py` invocation,
-        a dict of additional_props the recipe should be re-invoked with
+        a dict of rerun_props the recipe should be re-invoked with
     """
     input_props = self._input_props.copy()
-    input_props.update(additional_props or {})
+    input_props['rerun_options'] = rerun_props or {}
     with tempfile.TemporaryDirectory() as tmp_dir:
 
       # TODO(crbug.com/41492688): Support both chrome and chromium realms. Just
@@ -255,7 +255,7 @@
     Returns:
       Tuple of (exit code, error message) of the `recipes.py` invocation.
     """
-    props_to_use = None
+    rerun_props = None
     if filter_stdout:
       adapter = output_adapter.LegacyOutputAdapter()
     else:
@@ -264,7 +264,7 @@
     # final result. Put a cap on the amount of re-runs though, just in case.
     for _ in range(10):
       exit_code, failure_md, rerun_prop_options = self._run(
-          adapter, props_to_use)
+          adapter, rerun_props)
       # For in-line code snippets in markdown, style them as python. This
       # seems the least weird-looking.
       pretty_md = markdown.Markdown(failure_md, inline_code_lexer='python')
@@ -287,7 +287,7 @@
       self._console_printer.print(pretty_md)
       logging.warning('')
       if not self._skip_prompts:
-        props_to_use = get_prompt_resp(rerun_prop_options)
+        rerun_props = get_prompt_resp(rerun_prop_options)
       else:
         logging.warning(
             '[yellow]Proceeding despite the recipe warning due to the presence '
@@ -295,7 +295,7 @@
         if len(rerun_prop_options) < 1 or len(rerun_prop_options[0]) < 2:
           return 1, 'Received bad run options from the recipe'
         # Properties of the first option is the default path
-        props_to_use = rerun_prop_options[0].properties
-      if not props_to_use:
+        rerun_props = rerun_prop_options[0].properties
+      if not rerun_props:
         return exit_code, 'User-aborted due to warning'
     return 1, 'Exceeded too many recipe re-runs'
diff --git a/ui/accessibility/BUILD.gn b/ui/accessibility/BUILD.gn
index 9b56ebc..728c359b 100644
--- a/ui/accessibility/BUILD.gn
+++ b/ui/accessibility/BUILD.gn
@@ -72,8 +72,6 @@
     "ax_event.h",
     "ax_event_intent.cc",
     "ax_event_intent.h",
-    "ax_event_notification_details.cc",
-    "ax_event_notification_details.h",
     "ax_mode.cc",
     "ax_mode.h",
     "ax_mode_histogram_logger.cc",
@@ -97,6 +95,8 @@
     "ax_tree_update.cc",
     "ax_tree_update.h",
     "ax_tree_update_forward.h",
+    "ax_updates_and_events.cc",
+    "ax_updates_and_events.h",
   ]
 
   if (!is_chromeos) {
diff --git a/ui/accessibility/ax_event_notification_details.cc b/ui/accessibility/ax_event_notification_details.cc
deleted file mode 100644
index 25bb58d..0000000
--- a/ui/accessibility/ax_event_notification_details.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/accessibility/ax_event_notification_details.h"
-
-#include "ui/accessibility/ax_event.h"
-
-namespace ui {
-
-AXEventNotificationDetails::AXEventNotificationDetails()
-    : ax_tree_id(ui::AXTreeIDUnknown()) {}
-
-AXEventNotificationDetails::~AXEventNotificationDetails() {}
-
-AXLocationChangeNotificationDetails::AXLocationChangeNotificationDetails()
-    : id(-1), ax_tree_id(ui::AXTreeIDUnknown()) {}
-
-AXLocationChangeNotificationDetails::AXLocationChangeNotificationDetails(
-    const AXLocationChangeNotificationDetails& other) = default;
-
-AXLocationChangeNotificationDetails::~AXLocationChangeNotificationDetails() {}
-
-
-}  // namespace ui
diff --git a/ui/accessibility/ax_event_notification_details.h b/ui/accessibility/ax_event_notification_details.h
deleted file mode 100644
index 8bc6bb8..0000000
--- a/ui/accessibility/ax_event_notification_details.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_ACCESSIBILITY_AX_EVENT_NOTIFICATION_DETAILS_H_
-#define UI_ACCESSIBILITY_AX_EVENT_NOTIFICATION_DETAILS_H_
-
-#include <vector>
-
-#include "ui/accessibility/ax_base_export.h"
-#include "ui/accessibility/ax_event.h"
-#include "ui/accessibility/ax_node_data.h"
-#include "ui/accessibility/ax_relative_bounds.h"
-#include "ui/accessibility/ax_tree_data.h"
-#include "ui/accessibility/ax_tree_update.h"
-
-namespace ui {
-
-struct AX_BASE_EXPORT AXEventNotificationDetails {
- public:
-  AXEventNotificationDetails();
-
-  AXEventNotificationDetails(const AXEventNotificationDetails& other) = delete;
-  AXEventNotificationDetails& operator=(
-      const AXEventNotificationDetails& other) = delete;
-
-  ~AXEventNotificationDetails();
-
-  // The unique ID of the accessibility tree this event bundle applies to.
-  ui::AXTreeID ax_tree_id;
-
-  // Zero or more updates to the accessibility tree to apply first.
-  std::vector<ui::AXTreeUpdate> updates;
-
-  // Zero or more events to fire after the tree updates have been applied.
-  std::vector<ui::AXEvent> events;
-};
-
-struct AX_BASE_EXPORT AXLocationChangeNotificationDetails {
- public:
-  AXLocationChangeNotificationDetails();
-  AXLocationChangeNotificationDetails(
-      const AXLocationChangeNotificationDetails& other);
-  ~AXLocationChangeNotificationDetails();
-
-  int id;
-  ui::AXTreeID ax_tree_id;
-  ui::AXRelativeBounds new_location;
-};
-
-}  // namespace ui
-
-#endif  // UI_ACCESSIBILITY_AX_EVENT_NOTIFICATION_DETAILS_H_
diff --git a/ui/accessibility/ax_updates_and_events.cc b/ui/accessibility/ax_updates_and_events.cc
new file mode 100644
index 0000000..31f22c45
--- /dev/null
+++ b/ui/accessibility/ax_updates_and_events.cc
@@ -0,0 +1,22 @@
+// Copyright 2014 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/accessibility/ax_updates_and_events.h"
+
+#include "ui/accessibility/ax_event.h"
+
+namespace ui {
+
+AXUpdatesAndEvents::AXUpdatesAndEvents() : ax_tree_id(ui::AXTreeIDUnknown()) {}
+
+AXUpdatesAndEvents::~AXUpdatesAndEvents() {}
+
+AXLocationChanges::AXLocationChanges()
+    : id(-1), ax_tree_id(ui::AXTreeIDUnknown()) {}
+
+AXLocationChanges::AXLocationChanges(const AXLocationChanges& other) = default;
+
+AXLocationChanges::~AXLocationChanges() {}
+
+}  // namespace ui
diff --git a/ui/accessibility/ax_updates_and_events.h b/ui/accessibility/ax_updates_and_events.h
new file mode 100644
index 0000000..0b0c7fc
--- /dev/null
+++ b/ui/accessibility/ax_updates_and_events.h
@@ -0,0 +1,53 @@
+// Copyright 2014 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCESSIBILITY_AX_UPDATES_AND_EVENTS_H_
+#define UI_ACCESSIBILITY_AX_UPDATES_AND_EVENTS_H_
+
+#include <vector>
+
+#include "ui/accessibility/ax_base_export.h"
+#include "ui/accessibility/ax_event.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_relative_bounds.h"
+#include "ui/accessibility/ax_tree_data.h"
+#include "ui/accessibility/ax_tree_update.h"
+
+namespace ui {
+
+struct AX_BASE_EXPORT AXUpdatesAndEvents {
+ public:
+  AXUpdatesAndEvents();
+
+  AXUpdatesAndEvents(const AXUpdatesAndEvents& other) = delete;
+  AXUpdatesAndEvents& operator=(
+      const AXUpdatesAndEvents& other) = delete;
+
+  ~AXUpdatesAndEvents();
+
+  // The unique ID of the accessibility tree this event bundle applies to.
+  ui::AXTreeID ax_tree_id;
+
+  // Zero or more updates to the accessibility tree to apply first.
+  std::vector<ui::AXTreeUpdate> updates;
+
+  // Zero or more events to fire after the tree updates have been applied.
+  std::vector<ui::AXEvent> events;
+};
+
+struct AX_BASE_EXPORT AXLocationChanges {
+ public:
+  AXLocationChanges();
+  AXLocationChanges(
+      const AXLocationChanges& other);
+  ~AXLocationChanges();
+
+  int id;
+  ui::AXTreeID ax_tree_id;
+  ui::AXRelativeBounds new_location;
+};
+
+}  // namespace ui
+
+#endif  // UI_ACCESSIBILITY_AX_UPDATES_AND_EVENTS_H_
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index 875d84c..eeff5a0 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -1488,7 +1488,6 @@
 
 void Layer::SetScrollable(const gfx::Size& container_bounds) {
   cc_layer_->SetScrollable(container_bounds);
-  cc_layer_->SetUserScrollable(true, true);
 }
 
 gfx::PointF Layer::CurrentScrollOffset() const {
diff --git a/ui/shell_dialogs/select_file_dialog_mac_unittest.mm b/ui/shell_dialogs/select_file_dialog_mac_unittest.mm
index 0507bf8..b3c97ab6 100644
--- a/ui/shell_dialogs/select_file_dialog_mac_unittest.mm
+++ b/ui/shell_dialogs/select_file_dialog_mac_unittest.mm
@@ -179,32 +179,33 @@
   // passed and no default extension was provided.
   EXPECT_EQ(0, popup.indexOfSelectedItem);
 
-  if (@available(macOS 11, *)) {
-    ASSERT_EQ(1lu, panel.allowedContentTypes.count);
-    EXPECT_NSEQ(UTTypeHTML, panel.allowedContentTypes[0]);
-  } else {
-    EXPECT_TRUE([panel.allowedFileTypes containsObject:@"htm"]);
-    EXPECT_TRUE([panel.allowedFileTypes containsObject:@"html"]);
-    // Extensions should appear in order of input.
-    EXPECT_LT([panel.allowedFileTypes indexOfObject:@"html"],
-              [panel.allowedFileTypes indexOfObject:@"htm"]);
-    EXPECT_FALSE([panel.allowedFileTypes containsObject:@"jpg"]);
-  }
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+  NSArray<NSString*>* file_types = panel.allowedFileTypes;
+#pragma clang diagnostic pop
+
+  EXPECT_TRUE([file_types containsObject:@"htm"]);
+  EXPECT_TRUE([file_types containsObject:@"html"]);
+  // Extensions should appear in order of input.
+  EXPECT_LT([file_types indexOfObject:@"html"],
+            [file_types indexOfObject:@"htm"]);
+  EXPECT_FALSE([file_types containsObject:@"jpg"]);
 
   // Select the second item.
   [popup.menu performActionForItemAtIndex:1];
   EXPECT_EQ(1, popup.indexOfSelectedItem);
-  if (@available(macOS 11, *)) {
-    ASSERT_EQ(1lu, panel.allowedContentTypes.count);
-    EXPECT_NSEQ(UTTypeJPEG, panel.allowedContentTypes[0]);
-  } else {
-    EXPECT_TRUE([panel.allowedFileTypes containsObject:@"jpg"]);
-    EXPECT_TRUE([panel.allowedFileTypes containsObject:@"jpeg"]);
-    // Extensions should appear in order of input.
-    EXPECT_LT([panel.allowedFileTypes indexOfObject:@"jpeg"],
-              [panel.allowedFileTypes indexOfObject:@"jpg"]);
-    EXPECT_FALSE([panel.allowedFileTypes containsObject:@"html"]);
-  }
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+  file_types = panel.allowedFileTypes;
+#pragma clang diagnostic pop
+
+  EXPECT_TRUE([file_types containsObject:@"jpg"]);
+  EXPECT_TRUE([file_types containsObject:@"jpeg"]);
+  // Extensions should appear in order of input.
+  EXPECT_LT([file_types indexOfObject:@"jpeg"],
+            [file_types indexOfObject:@"jpg"]);
+  EXPECT_FALSE([file_types containsObject:@"html"]);
 }
 
 // Verify file_type_info.include_all_files argument is respected.
@@ -265,14 +266,15 @@
   // Verify that the `file_type_index` causes the second item to be initially
   // selected.
   EXPECT_EQ(1, popup.indexOfSelectedItem);
-  if (@available(macOS 11, *)) {
-    ASSERT_EQ(1lu, panel.allowedContentTypes.count);
-    EXPECT_NSEQ(UTTypeJPEG, panel.allowedContentTypes[0]);
-  } else {
-    EXPECT_TRUE([panel.allowedFileTypes containsObject:@"jpg"]);
-    EXPECT_TRUE([panel.allowedFileTypes containsObject:@"jpeg"]);
-    EXPECT_FALSE([panel.allowedFileTypes containsObject:@"html"]);
-  }
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+  NSArray<NSString*>* file_types = panel.allowedFileTypes;
+#pragma clang diagnostic pop
+
+  EXPECT_TRUE([file_types containsObject:@"jpg"]);
+  EXPECT_TRUE([file_types containsObject:@"jpeg"]);
+  EXPECT_FALSE([file_types containsObject:@"html"]);
 
   ResetDialog();
   args.file_type_index = 0;
@@ -284,15 +286,16 @@
   // Verify that the first item was selected, since the default extension passed
   // was not present in the extension list.
   EXPECT_EQ(0, popup.indexOfSelectedItem);
-  if (@available(macOS 11, *)) {
-    ASSERT_EQ(1lu, panel.allowedContentTypes.count);
-    EXPECT_NSEQ(UTTypeHTML, panel.allowedContentTypes[0]);
-  } else {
-    EXPECT_TRUE([panel.allowedFileTypes containsObject:@"html"]);
-    EXPECT_TRUE([panel.allowedFileTypes containsObject:@"htm"]);
-    EXPECT_FALSE([panel.allowedFileTypes containsObject:@"pdf"]);
-    EXPECT_FALSE([panel.allowedFileTypes containsObject:@"jpeg"]);
-  }
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+  file_types = panel.allowedFileTypes;
+#pragma clang diagnostic pop
+
+  EXPECT_TRUE([file_types containsObject:@"html"]);
+  EXPECT_TRUE([file_types containsObject:@"htm"]);
+  EXPECT_FALSE([file_types containsObject:@"pdf"]);
+  EXPECT_FALSE([file_types containsObject:@"jpeg"]);
 
   ResetDialog();
   args.file_type_index = 0;
@@ -304,14 +307,15 @@
   // Verify that the extension group corresponding to the default extension is
   // initially selected.
   EXPECT_EQ(1, popup.indexOfSelectedItem);
-  if (@available(macOS 11, *)) {
-    ASSERT_EQ(1lu, panel.allowedContentTypes.count);
-    EXPECT_NSEQ(UTTypeJPEG, panel.allowedContentTypes[0]);
-  } else {
-    EXPECT_TRUE([panel.allowedFileTypes containsObject:@"jpg"]);
-    EXPECT_TRUE([panel.allowedFileTypes containsObject:@"jpeg"]);
-    EXPECT_FALSE([panel.allowedFileTypes containsObject:@"html"]);
-  }
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+  file_types = panel.allowedFileTypes;
+#pragma clang diagnostic pop
+
+  EXPECT_TRUE([file_types containsObject:@"jpg"]);
+  EXPECT_TRUE([file_types containsObject:@"jpeg"]);
+  EXPECT_FALSE([file_types containsObject:@"html"]);
 }
 
 // Verify that an appropriate extension description is shown even if an empty
diff --git a/ui/views/accessibility/view_accessibility.cc b/ui/views/accessibility/view_accessibility.cc
index 9e25824d..7c0ee61d 100644
--- a/ui/views/accessibility/view_accessibility.cc
+++ b/ui/views/accessibility/view_accessibility.cc
@@ -183,9 +183,8 @@
   }
 
   view_->GetAccessibleNodeData(data);
-  if (override_data_.role != ax::mojom::Role::kUnknown) {
-    data->role = override_data_.role;
-  }
+
+  // TODO(accessibility): This next check should be added to SetRole.
   if (data->role == ax::mojom::Role::kAlertDialog) {
     // When an alert dialog is used, indicate this with xml-roles. This helps
     // JAWS understand that it's a dialog and not just an ordinary alert, even
@@ -196,77 +195,7 @@
     data->AddStringAttribute(ax::mojom::StringAttribute::kRole, "alertdialog");
   }
 
-  std::string name;
-  if (override_data_.GetStringAttribute(ax::mojom::StringAttribute::kName,
-                                        &name)) {
-    if (!name.empty())
-      data->SetNameChecked(name);
-    else
-      data->SetNameExplicitlyEmpty();
-  }
-
-  std::string description;
-  if (override_data_.GetStringAttribute(
-          ax::mojom::StringAttribute::kDescription, &description)) {
-    if (!description.empty())
-      data->SetDescription(description);
-    else
-      data->SetDescriptionExplicitlyEmpty();
-  }
-
-  if (override_data_.GetHasPopup() != ax::mojom::HasPopup::kFalse) {
-    data->SetHasPopup(override_data_.GetHasPopup());
-  }
-
-  static constexpr ax::mojom::IntAttribute kOverridableIntAttributes[]{
-      ax::mojom::IntAttribute::kDescriptionFrom,
-      ax::mojom::IntAttribute::kNameFrom,
-      ax::mojom::IntAttribute::kPosInSet,
-      ax::mojom::IntAttribute::kSetSize,
-  };
-  for (auto attribute : kOverridableIntAttributes) {
-    if (override_data_.HasIntAttribute(attribute)) {
-      data->AddIntAttribute(attribute,
-                            override_data_.GetIntAttribute(attribute));
-    }
-  }
-
-  static constexpr ax::mojom::IntListAttribute kOverridableIntListAttributes[]{
-      ax::mojom::IntListAttribute::kLabelledbyIds,
-      ax::mojom::IntListAttribute::kDescribedbyIds,
-      ax::mojom::IntListAttribute::kCharacterOffsets,
-      ax::mojom::IntListAttribute::kWordStarts,
-      ax::mojom::IntListAttribute::kWordEnds,
-  };
-  for (auto attribute : kOverridableIntListAttributes) {
-    if (override_data_.HasIntListAttribute(attribute)) {
-      data->AddIntListAttribute(attribute,
-                                override_data_.GetIntListAttribute(attribute));
-    }
-  }
-
-  if (override_data_.HasBoolAttribute(ax::mojom::BoolAttribute::kSelected)) {
-    data->AddBoolAttribute(
-        ax::mojom::BoolAttribute::kSelected,
-        override_data_.GetBoolAttribute(ax::mojom::BoolAttribute::kSelected));
-  }
-
   data->relative_bounds.bounds = gfx::RectF(view_->GetBoundsInScreen());
-  if (!override_data_.relative_bounds.bounds.IsEmpty()) {
-    data->relative_bounds.bounds = override_data_.relative_bounds.bounds;
-  }
-
-  // We need to add the ignored state to all ignored Views, similar to how Blink
-  // exposes ignored DOM nodes. Calling AXNodeData::IsIgnored() would also check
-  // if the role is in the list of roles that are inherently ignored.
-  // Furthermore, we add the ignored state if this View is a descendant of a
-  // leaf View. We call this class's "IsChildOfLeaf" method instead of the one
-  // in our platform specific subclass because subclasses determine if a node is
-  // a leaf by (among other things) counting the number of unignored children,
-  // which would create a circular definition of the ignored state.
-  if (data->IsIgnored() || ViewAccessibility::IsChildOfLeaf()) {
-    data->AddState(ax::mojom::State::kIgnored);
-  }
 
   if (ViewAccessibility::IsAccessibilityFocusable())
     data->AddState(ax::mojom::State::kFocusable);
diff --git a/ui/views/accessibility/view_accessibility.h b/ui/views/accessibility/view_accessibility.h
index ae2dc5a..a04ff4a 100644
--- a/ui/views/accessibility/view_accessibility.h
+++ b/ui/views/accessibility/view_accessibility.h
@@ -390,10 +390,6 @@
 
   const ui::AXUniqueId unique_id_;
 
-  // Contains data set explicitly via OverrideRole etc. that
-  // overrides anything provided by GetAccessibleNodeData().
-  ui::AXNodeData override_data_;
-
   // Contains data that is populated by the setters in this class.
   // This member is tied to the ViewsAX project. Which is introducing a new
   // system to set accessible properties in a "push" fashion (instead of pull).
diff --git a/ui/views/accessibility/view_accessibility_utils.cc b/ui/views/accessibility/view_accessibility_utils.cc
index a039879..4a74a6c1 100644
--- a/ui/views/accessibility/view_accessibility_utils.cc
+++ b/ui/views/accessibility/view_accessibility_utils.cc
@@ -68,6 +68,10 @@
     destination.AddStringListAttribute(attr.first, attr.second);
   }
 
+  if (!source.relative_bounds.bounds.IsEmpty()) {
+    destination.relative_bounds.bounds = source.relative_bounds.bounds;
+  }
+
   // TODO(javiercon): Add checking for all the states, and add DCHECK for them
   // as well. Do the same thing for the Restrictions.
   if (source.HasState(ax::mojom::State::kIgnored)) {
diff --git a/ui/webui/resources/cr_components/history_embeddings/history_embeddings.html b/ui/webui/resources/cr_components/history_embeddings/history_embeddings.html
index 53c73ff..6054f54 100644
--- a/ui/webui/resources/cr_components/history_embeddings/history_embeddings.html
+++ b/ui/webui/resources/cr_components/history_embeddings/history_embeddings.html
@@ -118,3 +118,18 @@
     </div>
   </div>
 </div>
+
+<cr-lazy-render id="sharedMenu">
+  <template>
+    <cr-action-menu role-description="$i18n{actionMenuDescription}">
+      <button id="moreFromSiteOption" class="dropdown-item"
+          on-click="onMoreFromSiteClick_">
+        $i18n{moreFromSite}
+      </button>
+      <button id="removeFromHistoryOption"
+          class="dropdown-item" on-click="onRemoveFromHistoryClick_">
+        $i18n{removeFromHistory}
+      </button>
+    </cr-action-menu>
+  </template>
+</cr-lazy-render>
diff --git a/ui/webui/resources/cr_components/history_embeddings/history_embeddings.mojom b/ui/webui/resources/cr_components/history_embeddings/history_embeddings.mojom
index 0448cd0..66f7263b4 100644
--- a/ui/webui/resources/cr_components/history_embeddings/history_embeddings.mojom
+++ b/ui/webui/resources/cr_components/history_embeddings/history_embeddings.mojom
@@ -22,6 +22,11 @@
   // A localized string for the last visit time for the above URL, from history.
   string relative_time;
 
+  // The last visit time for the above URL, from history. Used for removing
+  // history item.
+  // TODO(crbug.com/335282446): BrowsingHistoryService requires a double here.
+  double last_url_visit_timestamp;
+
   // The full source passage that was used to recall this item.
   string source_passage;
 };
diff --git a/ui/webui/resources/cr_components/history_embeddings/history_embeddings.ts b/ui/webui/resources/cr_components/history_embeddings/history_embeddings.ts
index 0990310..a4af990 100644
--- a/ui/webui/resources/cr_components/history_embeddings/history_embeddings.ts
+++ b/ui/webui/resources/cr_components/history_embeddings/history_embeddings.ts
@@ -2,13 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import '//resources/cr_elements/cr_lazy_render/cr_lazy_render.js';
+import '//resources/cr_elements/cr_action_menu/cr_action_menu.js';
 import '//resources/cr_elements/cr_feedback_buttons/cr_feedback_buttons.js';
 import '//resources/cr_elements/cr_hidden_style.css.js';
 import '//resources/cr_elements/cr_loading_gradient/cr_loading_gradient.js';
 import '//resources/cr_elements/cr_shared_vars.css.js';
 import '//resources/cr_elements/cr_url_list_item/cr_url_list_item.js';
 
+import type {CrActionMenuElement} from '//resources/cr_elements/cr_action_menu/cr_action_menu.js';
+import type {CrLazyRenderElement} from '//resources/cr_elements/cr_lazy_render/cr_lazy_render.js';
 import {I18nMixin} from '//resources/cr_elements/i18n_mixin.js';
+import {assert} from '//resources/js/assert.js';
 import type {Time} from '//resources/mojo/mojo/public/mojom/base/time.mojom-webui.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import type {DomRepeatEvent} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@@ -28,9 +33,20 @@
 export interface HistoryEmbeddingsElement {
   $: {
     heading: HTMLElement,
+    sharedMenu: CrLazyRenderElement<CrActionMenuElement>,
   };
 }
 
+export type HistoryEmbeddingsMoreActionsClickEvent =
+    CustomEvent<SearchResultItem>;
+
+declare global {
+  interface HTMLElementEventMap {
+    'more-from-site-click': HistoryEmbeddingsMoreActionsClickEvent;
+    'remove-item-click': HistoryEmbeddingsMoreActionsClickEvent;
+  }
+}
+
 const HistoryEmbeddingsElementBase = I18nMixin(PolymerElement);
 
 export class HistoryEmbeddingsElement extends HistoryEmbeddingsElementBase {
@@ -45,8 +61,15 @@
   static get properties() {
     return {
       loading_: Boolean,
+      searchResult_: Object,
       searchQuery: String,
       timeRangeStart: Object,
+      hidden: {
+        type: Boolean,
+        reflectToAttribute: true,
+        value: true,
+        computed: 'computeIsHidden_(loading_, searchResult_.items.length)',
+      },
     };
   }
 
@@ -56,12 +79,17 @@
     ];
   }
 
+  private actionMenuItem_: SearchResultItem|null = null;
   private browserProxy_ = HistoryEmbeddingsBrowserProxyImpl.getInstance();
   private loading_ = false;
   private searchResult_: SearchResult;
   searchQuery: string;
   timeRangeStart?: Date;
 
+  private computeIsHidden_(): boolean {
+    return !this.loading_ && this.searchResult_?.items.length === 0;
+  }
+
   private getHeadingText_(): string {
     if (this.loading_) {
       return this.i18n('historyEmbeddingsHeadingLoading', this.searchQuery);
@@ -70,8 +98,29 @@
   }
 
   private onMoreActionsClick_(e: DomRepeatEvent<SearchResultItem>) {
-    this.dispatchEvent(
-        new CustomEvent('more-actions-click', {detail: e.model.item}));
+    const target = e.target as HTMLElement;
+    const item = e.model.item;
+    this.actionMenuItem_ = item;
+    this.$.sharedMenu.get().showAt(target);
+  }
+
+  private onMoreFromSiteClick_() {
+    assert(this.actionMenuItem_);
+    this.dispatchEvent(new CustomEvent(
+        'more-from-site-click',
+        {detail: this.actionMenuItem_, bubbles: true, composed: true}));
+    this.$.sharedMenu.get().close();
+  }
+
+  private onRemoveFromHistoryClick_() {
+    assert(this.actionMenuItem_);
+    this.splice(
+        'searchResult_.items',
+        this.searchResult_.items.indexOf(this.actionMenuItem_), 1);
+    this.dispatchEvent(new CustomEvent(
+        'remove-item-click',
+        {detail: this.actionMenuItem_, bubbles: true, composed: true}));
+    this.$.sharedMenu.get().close();
   }
 
   private onResultClick_(e: DomRepeatEvent<SearchResultItem>) {
diff --git a/ui/webui/resources/cr_elements/BUILD.gn b/ui/webui/resources/cr_elements/BUILD.gn
index fb22ec7..95a91f2 100644
--- a/ui/webui/resources/cr_elements/BUILD.gn
+++ b/ui/webui/resources/cr_elements/BUILD.gn
@@ -73,6 +73,8 @@
       "cr_grid/cr_grid.html.ts",
       "cr_grid/cr_grid.ts",
       "cr_icon/cr_icon.ts",
+      "cr_icon/cr_iconset.html.ts",
+      "cr_icon/cr_iconset.ts",
       "cr_icon_button/cr_icon_button.html.ts",
       "cr_icon_button/cr_icon_button.ts",
       "cr_input/cr_input.html.ts",
@@ -159,6 +161,7 @@
       "cr_feedback_buttons/cr_feedback_buttons.css",
       "cr_grid/cr_grid.css",
       "cr_icon/cr_icon.css",
+      "cr_icon/cr_iconset.css",
       "cr_icon_button/cr_icon_button.css",
       "cr_input/cr_input.css",
       "cr_input/cr_input_style.css",
diff --git a/ui/webui/resources/cr_elements/cr_icon/cr_iconset.css b/ui/webui/resources/cr_elements/cr_icon/cr_iconset.css
new file mode 100644
index 0000000..b5f5b62
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_icon/cr_iconset.css
@@ -0,0 +1,12 @@
+/* Copyright 2024 The Chromium Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+/* #css_wrapper_metadata_start
+ * #type=style-lit
+ * #scheme=relative
+ * #css_wrapper_metadata_end */
+
+:host {
+  display: none;
+}
diff --git a/ui/webui/resources/cr_elements/cr_icon/cr_iconset.html.ts b/ui/webui/resources/cr_elements/cr_icon/cr_iconset.html.ts
new file mode 100644
index 0000000..a759433f
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_icon/cr_iconset.html.ts
@@ -0,0 +1,18 @@
+// 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 {html} from '//resources/lit/v3_0/lit.rollup.js';
+
+import type {CrIconsetElement} from './cr_iconset.js';
+
+export function getHtml(this: CrIconsetElement) {
+  return html`
+<svg id="baseSvg" xmlns="http://www.w3.org/2000/svg"
+     viewBox="0 0 ${this.size} ${this.size}"
+     preserveAspectRatio="xMidYMid meet" focusable="false"
+     style="pointer-events: none; display: block; width: 100%; height 100%;">
+ </svg>
+<slot></slot>
+`;
+}
diff --git a/ui/webui/resources/cr_elements/cr_icon/cr_iconset.ts b/ui/webui/resources/cr_elements/cr_icon/cr_iconset.ts
new file mode 100644
index 0000000..da62dad4
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_icon/cr_iconset.ts
@@ -0,0 +1,138 @@
+// 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 type {PropertyValues} from '//resources/lit/v3_0/lit.rollup.js';
+import {CrLitElement} from '//resources/lit/v3_0/lit.rollup.js';
+import {assert} from '//resources/js/assert.js';
+
+import type {Iconset} from './iconset_map.js';
+import {IconsetMap} from './iconset_map.js';
+import {getCss} from './cr_iconset.css.js';
+import {getHtml} from './cr_iconset.html.js';
+
+const APPLIED_ICON_CLASS: string = 'cr-iconset-svg-icon_';
+
+export interface CrIconsetElement {
+  $: {
+    baseSvg: SVGElement,
+  };
+}
+
+export class CrIconsetElement extends CrLitElement implements Iconset {
+  static get is() {
+    return 'cr-iconset';
+  }
+
+  static override get styles() {
+    return getCss();
+  }
+
+  override render() {
+    return getHtml.bind(this)();
+  }
+
+  static override get properties() {
+    return {
+      /**
+       * The name of the iconset.
+       */
+      name: {type: String},
+
+      /**
+       * The size of an individual icon. Note that icons must be square.
+       */
+      size: {type: Number},
+    };
+  }
+
+  name: string = '';
+  size: number = 24;
+
+  override updated(changedProperties: PropertyValues<this>) {
+    super.updated(changedProperties);
+
+    if (changedProperties.has('name')) {
+      assert(changedProperties.get('name') === undefined);
+      IconsetMap.getInstance().set(this.name, this);
+    }
+  }
+
+  /**
+   * Applies an icon to the given element.
+   *
+   * An svg icon is prepended to the element's shadowRoot, which should always
+   * exist.
+   * @param element Element to which the icon is applied.
+   * @param iconName Name of the icon to apply.
+   * @return The svg element which renders the icon.
+   */
+  applyIcon(element: HTMLElement, iconName: string): SVGElement|null {
+    // Remove old svg element
+    this.removeIcon(element);
+    // install new svg element
+    const svg = this.cloneIcon_(iconName);
+    if (svg) {
+      // Add special class so we can identify it in remove.
+      svg.classList.add(APPLIED_ICON_CLASS);
+      // insert svg element into shadow root
+      element.shadowRoot!.insertBefore(svg, element.shadowRoot!.childNodes[0]);
+      return svg;
+    }
+    return null;
+  }
+
+  /**
+   * Produce installable clone of the SVG element matching `id` in this
+   * iconset, or null if there is no matching element.
+   * @param iconName Name of the icon to apply.
+   */
+  createIcon(iconName: string): SVGElement|null {
+    return this.cloneIcon_(iconName);
+  }
+
+  /**
+   * Remove an icon from the given element by undoing the changes effected
+   * by `applyIcon`.
+   */
+  removeIcon(element: HTMLElement) {
+    // Remove old svg element
+    const oldSvg = element.shadowRoot!.querySelector<SVGElement>(
+        `.${APPLIED_ICON_CLASS}`);
+    if (oldSvg) {
+      oldSvg.remove();
+    }
+  }
+
+  /**
+   * Produce installable clone of the SVG element matching `id` in this
+   * iconset, or `undefined` if there is no matching element.
+   *
+   * Returns an installable clone of the SVG element matching `id` or null if
+   * no such element exists.
+   */
+  private cloneIcon_(id: string): SVGElement|null {
+    const sourceSvg = this.querySelector(`g[id="${id}"]`);
+    if (!sourceSvg) {
+      return null;
+    }
+
+    const svgClone = this.$.baseSvg.cloneNode(true) as SVGElement;
+    const content = sourceSvg.cloneNode(true) as SVGGElement;
+    content.removeAttribute('id');
+    const contentViewBox = content.getAttribute('viewBox');
+    if (contentViewBox) {
+      svgClone.setAttribute('viewBox', contentViewBox);
+    }
+    svgClone.appendChild(content);
+    return svgClone;
+  }
+}
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'cr-iconset': CrIconsetElement;
+  }
+}
+
+customElements.define(CrIconsetElement.is, CrIconsetElement);
diff --git a/ui/webui/resources/cr_elements/cr_icon/iconset_map.ts b/ui/webui/resources/cr_elements/cr_icon/iconset_map.ts
index f802708..91e3733b8c 100644
--- a/ui/webui/resources/cr_elements/cr_icon/iconset_map.ts
+++ b/ui/webui/resources/cr_elements/cr_icon/iconset_map.ts
@@ -7,7 +7,6 @@
 // Common interface implemented by CrIconsetElement and IronIconset.
 export interface Iconset {
   name: string;
-  getIconNames(): string[];
   applyIcon(element: HTMLElement, iconName: string): SVGElement|null;
   createIcon(iconName: string): SVGElement|null;
   removeIcon(element: HTMLElement): void;
diff --git a/ui/webui/resources/cr_elements/cr_shared_vars.css b/ui/webui/resources/cr_elements/cr_shared_vars.css
index c54af3a..8a46bf3 100644
--- a/ui/webui/resources/cr_elements/cr_shared_vars.css
+++ b/ui/webui/resources/cr_elements/cr_shared_vars.css
@@ -3,7 +3,7 @@
  * found in the LICENSE file. */
 
 /* #css_wrapper_metadata_start
- * #type=vars
+ * #type=vars-lit
  * #scheme=relative
  * #css_wrapper_metadata_end */