diff --git a/DEPS b/DEPS
index 5d1da502..db90a4c2 100644
--- a/DEPS
+++ b/DEPS
@@ -299,15 +299,15 @@
   # 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': '13a299964c9f66e7af63defde83b9c03055fa304',
+  'skia_revision': '3ead037d837c32c819d77607e01f208e91caca07',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '6dc75f0da012c4a9f638b78eefa86876a8349e77',
+  'v8_revision': '203782512c9e2925ca7759c22abd07f59f16366d',
   # 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': 'dcbcee8ab32af9ddc7ae1e91c42d995e5281602c',
+  'angle_revision': '65180785da62e5d12f0d2a28fa0cca1fe98f83ca',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -375,7 +375,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
-  'crossbench_revision': '85adce1424ed4df795f8c810fc1a8ee22bffe3fa',
+  'crossbench_revision': '6fc73bc2e9fcd16c236c3728eddd1532aa9c76b9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -391,7 +391,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '99d8217d44d317d2b0f378eff8c33fd302310561',
+  'devtools_frontend_revision': '0d8b60f08590e970da0c2980ac3a0f5ec2929bc2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -419,7 +419,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'quiche_revision': '8f26ded8fab679ca935e490a1a324faeccbd78e5',
+  'quiche_revision': '7802d58f2294c60cbe063fce822d4872aaa52724',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ink
   # and whatever else without interference from each other.
@@ -1486,7 +1486,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    'de8849c98f8b6f841b915b569f38ac6c7e3cbf77',
+    'dfbdf5ea48d8bb96bb4fd791866c160bd6b6d3e1',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1645,7 +1645,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': '9gK5fctsrqSL7ITHbaKR8oEVCBo_gw0XIMzM9kvuSI0C',
+          'version': 'eaknFYxsT8k1aKnroa-MOOT-nxE41krXhpS9QxURsp0C',
       },
     ],
     'condition': 'checkout_android and non_git_source',
@@ -2526,7 +2526,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '5a66f76326a04bf33f05433665cd77b7eb288fcc',
+    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + 'a9b5b095dac6ee69731e25683949fb181a57fa24',
 
   'src/base/tracing/test/data': {
     'bucket': 'perfetto',
@@ -2893,7 +2893,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'c01b768bce4a143e152c1870b6ba99ea6267d2b0',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'f5816ba68bc2ec4a0c30ef4dcea0b104f81ceb9e',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '905c7cbfeaac1cf3feb4c6056dd6f3dbaa06b074',
 
   'src/third_party/webpagereplay':
     Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'),
@@ -3021,7 +3021,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/boca_app/app',
-        'version': 'LWXcF-OX0IxmgZq6kTJs8qyMetNUYPvJF59Y5EdhKYkC',
+        'version': '5vNvnHtwyehvOEJj0-GynD5KhUmFU0GMf_YQkjRYF28C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -4619,7 +4619,7 @@
 
   'src/components/optimization_guide/internal': {
       'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' +
-        '7062789227d77cf3b9d99e973da9b0ecc29056c9',
+        'f58041bc19d8cd401fe481331f0b399ccc3a73a4',
       'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/nonembedded/component_updater/OWNERS b/android_webview/nonembedded/component_updater/OWNERS
index 3b0be42..a2febe5 100644
--- a/android_webview/nonembedded/component_updater/OWNERS
+++ b/android_webview/nonembedded/component_updater/OWNERS
@@ -1,2 +1 @@
-avvall@chromium.org
 pbirk@chromium.org
diff --git a/ash/frame/snap_controller_impl.cc b/ash/frame/snap_controller_impl.cc
index 781d77cd..5962221 100644
--- a/ash/frame/snap_controller_impl.cc
+++ b/ash/frame/snap_controller_impl.cc
@@ -79,10 +79,6 @@
     case SnapRequestSource::kWindowLayoutMenu:
       snap_action_source = WindowSnapActionSource::kSnapByWindowLayoutMenu;
       break;
-    case SnapRequestSource::kFromLacrosSnapButtonOrWindowLayoutMenu:
-      snap_action_source =
-          WindowSnapActionSource::kLacrosSnapButtonOrWindowLayoutMenu;
-      break;
   }
 
   const WindowSnapWMEvent snap_event(snap == chromeos::SnapDirection::kPrimary
diff --git a/ash/webui/shimless_rma/resources/onboarding_landing_page.html b/ash/webui/shimless_rma/resources/onboarding_landing_page.html
index e41f920..f1b47a9e 100644
--- a/ash/webui/shimless_rma/resources/onboarding_landing_page.html
+++ b/ash/webui/shimless_rma/resources/onboarding_landing_page.html
@@ -68,7 +68,8 @@
       </cr-button>
       <cr-button id="landingExit" class="pill"
           on-click="onLandingExitButtonClicked"
-          disabled="[[allButtonsDisabled]]">
+          disabled="[[allButtonsDisabled]]"
+          hidden$="[[!canExit]]">
         <span id="exitButtonLabel">
           [[i18n('exitButtonLabel')]]
         </span>
diff --git a/ash/webui/shimless_rma/resources/onboarding_landing_page.ts b/ash/webui/shimless_rma/resources/onboarding_landing_page.ts
index 0e919ec..bd98409 100644
--- a/ash/webui/shimless_rma/resources/onboarding_landing_page.ts
+++ b/ash/webui/shimless_rma/resources/onboarding_landing_page.ts
@@ -99,6 +99,14 @@
         value: false,
       },
 
+      /**
+       * Hide the exit button if user should not exit.
+       */
+      canExit: {
+        type: Boolean,
+        value: true,
+      },
+
       verificationFailedMessage: {
         type: String,
         value: '',
@@ -109,6 +117,7 @@
   allButtonsDisabled: boolean;
   getStartedButtonClicked: boolean;
   confirmExitButtonClicked: boolean;
+  canExit: boolean;
   shimlessRmaService: ShimlessRmaServiceInterface = getShimlessRmaService();
   hwVerificationObserverReceiver: HardwareVerificationStatusObserverReceiver;
   protected componentsList: string;
diff --git a/ash/webui/shimless_rma/resources/shimless_rma.ts b/ash/webui/shimless_rma/resources/shimless_rma.ts
index 3978a4ec..1b376213 100644
--- a/ash/webui/shimless_rma/resources/shimless_rma.ts
+++ b/ash/webui/shimless_rma/resources/shimless_rma.ts
@@ -104,6 +104,7 @@
   hidden?: boolean,
   errorCode?: RmadErrorCode,
   getStartedButtonClicked?: boolean,
+  canExit?: boolean,
   allButtonsDisabled?: boolean,
   onNextButtonClick?: () => Promise<{stateResult: StateResult}>,
   onExitButtonClick?: () => Promise<{stateResult: StateResult}>,
@@ -719,6 +720,7 @@
       // buttons.
       currentPageComponent.getStartedButtonClicked = false;
       currentPageComponent.confirmExitButtonClicked = false;
+      currentPageComponent.canExit = stateResult.canExit;
     }
 
     this.setAllButtonsState(
diff --git a/ash/wm/snap_group/snap_group_controller.cc b/ash/wm/snap_group/snap_group_controller.cc
index e2f728bb..b706e7d 100644
--- a/ash/wm/snap_group/snap_group_controller.cc
+++ b/ash/wm/snap_group/snap_group_controller.cc
@@ -117,7 +117,6 @@
     aura::Window* target_window = nullptr;
     switch (snap_action_source) {
       case WindowSnapActionSource::kSnapByWindowLayoutMenu:
-      case WindowSnapActionSource::kLacrosSnapButtonOrWindowLayoutMenu:
       case WindowSnapActionSource::kSnapByClamshellTabletTransition:
         // If the window was snapped via the layout menu, respect its
         // requested snap ratio. We also refresh the bounds for tablet
diff --git a/ash/wm/snap_group/snap_group_unittest.cc b/ash/wm/snap_group/snap_group_unittest.cc
index e0b23ef..ccf39cd 100644
--- a/ash/wm/snap_group/snap_group_unittest.cc
+++ b/ash/wm/snap_group/snap_group_unittest.cc
@@ -495,8 +495,6 @@
        /*should_show_partial_overview=*/true},
       {WindowSnapActionSource::kLongPressCaptionButtonToSnap,
        /*should_show_partial_overview=*/true},
-      {WindowSnapActionSource::kLacrosSnapButtonOrWindowLayoutMenu,
-       /*should_show_partial_overview=*/true},
       {WindowSnapActionSource::kKeyboardShortcutToSnap,
        /*should_show_partial_overview=*/false},
       {WindowSnapActionSource::kSnapByWindowStateRestore,
diff --git a/ash/wm/splitview/split_view_metrics_controller_unittest.cc b/ash/wm/splitview/split_view_metrics_controller_unittest.cc
index acb44ee..4875933 100644
--- a/ash/wm/splitview/split_view_metrics_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_metrics_controller_unittest.cc
@@ -252,7 +252,6 @@
       WindowSnapActionSource::kSnapByWindowLayoutMenu,
       WindowSnapActionSource::kDragWindowToEdgeToSnap,
       WindowSnapActionSource::kLongPressCaptionButtonToSnap,
-      WindowSnapActionSource::kLacrosSnapButtonOrWindowLayoutMenu,
       WindowSnapActionSource::kKeyboardShortcutToSnap,
       WindowSnapActionSource::kSnapByWindowStateRestore,
       WindowSnapActionSource::kSnapByFullRestoreOrDeskTemplateOrSavedDesk,
diff --git a/ash/wm/splitview/split_view_utils.cc b/ash/wm/splitview/split_view_utils.cc
index 7f20ce42..6612a8de 100644
--- a/ash/wm/splitview/split_view_utils.cc
+++ b/ash/wm/splitview/split_view_utils.cc
@@ -200,8 +200,6 @@
       return "SnapGroupWindowUpdate";
     case WindowSnapActionSource::kTest:
       return "Test";
-    case WindowSnapActionSource::kLacrosSnapButtonOrWindowLayoutMenu:
-      return "SnapByLacrosSnapButtonOrWindowLayoutMenu";
     case WindowSnapActionSource::kSnapBySwapWindowsInSnapGroup:
       return "SnapBySwapWindowsInSnapGroup";
   }
@@ -877,7 +875,6 @@
     case WindowSnapActionSource::kLongPressCaptionButtonToSnap:
     case WindowSnapActionSource::kDragOrSelectOverviewWindowToSnap:
     case WindowSnapActionSource::kTest:
-    case WindowSnapActionSource::kLacrosSnapButtonOrWindowLayoutMenu:
       // We only start partial overview for the above snap sources.
       return true;
     default:
diff --git a/ash/wm/wm_metrics.cc b/ash/wm/wm_metrics.cc
index d0cfc98..4052a3b 100644
--- a/ash/wm/wm_metrics.cc
+++ b/ash/wm/wm_metrics.cc
@@ -42,8 +42,6 @@
       return out << "SnapGroupWindowUpdate";
     case WindowSnapActionSource::kTest:
       return out << "Test";
-    case WindowSnapActionSource::kLacrosSnapButtonOrWindowLayoutMenu:
-      return out << "LacrosSnapButtonOrWindowLayoutMenu";
     case WindowSnapActionSource::kSnapBySwapWindowsInSnapGroup:
       return out << "SnapBySwapWindowsInSnapGroup";
   }
diff --git a/ash/wm/wm_metrics.h b/ash/wm/wm_metrics.h
index d70d5001..c1a65b01 100644
--- a/ash/wm/wm_metrics.h
+++ b/ash/wm/wm_metrics.h
@@ -16,25 +16,25 @@
 // tools/metrics/histograms/metadata/ash/enums.xml.
 enum class WindowSnapActionSource {
   // Default value for any snap action actions that's not covered below.
-  kNotSpecified,
-  kDragWindowToEdgeToSnap,
-  kLongPressCaptionButtonToSnap,
-  kKeyboardShortcutToSnap,
-  kDragOrSelectOverviewWindowToSnap,
-  kLongPressOverviewButtonToSnap,
-  kDragUpFromShelfToSnap,
-  kDragDownFromTopToSnap,
-  kDragTabToSnap,
-  kAutoSnapInSplitView,
-  kSnapByWindowStateRestore,
-  kSnapByWindowLayoutMenu,
-  kSnapByFullRestoreOrDeskTemplateOrSavedDesk,
-  kSnapByClamshellTabletTransition,
-  kSnapByDeskOrSessionChange,
-  kSnapGroupWindowUpdate,
-  kTest,
-  kLacrosSnapButtonOrWindowLayoutMenu,
-  kSnapBySwapWindowsInSnapGroup,
+  kNotSpecified = 0,
+  kDragWindowToEdgeToSnap = 1,
+  kLongPressCaptionButtonToSnap = 2,
+  kKeyboardShortcutToSnap = 3,
+  kDragOrSelectOverviewWindowToSnap = 4,
+  kLongPressOverviewButtonToSnap = 5,
+  kDragUpFromShelfToSnap = 6,
+  kDragDownFromTopToSnap = 7,
+  kDragTabToSnap = 8,
+  kAutoSnapInSplitView = 9,
+  kSnapByWindowStateRestore = 10,
+  kSnapByWindowLayoutMenu = 11,
+  kSnapByFullRestoreOrDeskTemplateOrSavedDesk = 12,
+  kSnapByClamshellTabletTransition = 13,
+  kSnapByDeskOrSessionChange = 14,
+  kSnapGroupWindowUpdate = 15,
+  kTest = 16,
+  // 17 was removed.
+  kSnapBySwapWindowsInSnapGroup = 18,
   kMaxValue = kSnapBySwapWindowsInSnapGroup,
 };
 
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 1f6732d..6dc73bf 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -2965,7 +2965,16 @@
         # Disable putting the compiler command line into the debug info to
         # prevent some types of non-determinism.
         "-gno-codeview-command-line",
+
+        # Deterministically choose one source line number out of all merged
+        # source line numbers to avoid line 0 debug info when multiple
+        # instructions are merged.
+        # See https://crbug.com/415272777.
+        "-mllvm",
+        "-pick-merged-source-locations"
       ]
+
+      rustflags = [ "-Cllvm-args=-pick-merged-source-locations"]
     } else {
       cflags = [ "/Zi" ]  # Produce PDB file, no edit and continue.
     }
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 628dcbd..2b164a4 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -469,6 +469,7 @@
   public_deps = [
     "//cc/base",
     "//cc/mojom:layer_type",
+    "//cc/mojom:missing_tile_reason",
     "//cc/mojom:ui_resource_id",
     "//cc/paint",
     "//components/viz/common",
diff --git a/cc/layers/tile_display_layer_impl.cc b/cc/layers/tile_display_layer_impl.cc
index 931cabb1..b9ef659 100644
--- a/cc/layers/tile_display_layer_impl.cc
+++ b/cc/layers/tile_display_layer_impl.cc
@@ -50,9 +50,7 @@
 
 TileDisplayLayerImpl::Tile::Tile(TileDisplayLayerImpl& layer,
                                  const TileContents& contents)
-    : layer_(layer), contents_(contents) {
-  DCHECK(!std::holds_alternative<NoContents>(contents_));
-}
+    : layer_(layer), contents_(contents) {}
 
 TileDisplayLayerImpl::Tile::Tile(Tile&&) = default;
 
@@ -117,10 +115,12 @@
 
   std::unique_ptr<Tile> old_tile;
   if (std::holds_alternative<NoContents>(contents)) {
-    auto it = tiles_.find(key);
-    if (it != tiles_.end()) {
-      old_tile = std::move(it->second);
-      tiles_.erase(it);
+    const auto& no_contents = std::get<NoContents>(contents);
+    if (no_contents.reason == mojom::MissingTileReason::kTileDeleted) {
+      tiles_.erase(key);
+    } else {
+      old_tile =
+          std::exchange(tiles_[key], std::make_unique<Tile>(*layer_, contents));
     }
   } else {
     // If there is a valid TileResource, import it in order to track its usage.
diff --git a/cc/layers/tile_display_layer_impl.h b/cc/layers/tile_display_layer_impl.h
index 2fa5413..3a19bb75 100644
--- a/cc/layers/tile_display_layer_impl.h
+++ b/cc/layers/tile_display_layer_impl.h
@@ -15,6 +15,7 @@
 #include "cc/base/tiling_data.h"
 #include "cc/cc_export.h"
 #include "cc/layers/layer_impl.h"
+#include "cc/mojom/missing_tile_reason.mojom.h"
 #include "cc/tiles/tile_index.h"
 #include "cc/tiles/tile_priority.h"
 #include "cc/tiles/tiling_coverage_iterator.h"
@@ -31,7 +32,13 @@
 // layer down to Viz, and this layer uses that information to draw tile quads.
 class CC_EXPORT TileDisplayLayerImpl : public LayerImpl {
  public:
-  struct NoContents {};
+  struct NoContents {
+    mojom::MissingTileReason reason =
+        mojom::MissingTileReason::kResourceNotReady;
+
+    NoContents() = default;
+    explicit NoContents(mojom::MissingTileReason r) : reason(r) {}
+  };
 
   struct CC_EXPORT TileResource {
     TileResource(const viz::TransferableResource& resource,
diff --git a/cc/mojo_embedder/viz_layer_context.cc b/cc/mojo_embedder/viz_layer_context.cc
index f48a650..6cd4e32 100644
--- a/cc/mojo_embedder/viz_layer_context.cc
+++ b/cc/mojo_embedder/viz_layer_context.cc
@@ -474,10 +474,21 @@
   auto wire = viz::mojom::Tile::New();
   wire->column_index = tile.tiling_i_index();
   wire->row_index = tile.tiling_j_index();
+
+  // If a Tile is being deleted, mark the reason as deleted. This is essential
+  // to distinguish deleted tiles from OOMed OR RESOURCE_MODE tiles with no
+  // resources. OOMed tiles have no content but are still required in order to
+  // perform checkerboard.
+  if (tile.deleted()) {
+    wire->contents = viz::mojom::TileContents::NewMissingReason(
+        mojom::MissingTileReason::kTileDeleted);
+    return wire;
+  }
+
   switch (tile.draw_info().mode()) {
     case TileDrawInfo::OOM_MODE:
       wire->contents = viz::mojom::TileContents::NewMissingReason(
-          viz::mojom::MissingTileReason::kOutOfMemory);
+          mojom::MissingTileReason::kOutOfMemory);
       break;
 
     case TileDrawInfo::SOLID_COLOR_MODE:
@@ -492,7 +503,7 @@
             SerializeTileResource(tile, resource_provider, context_provider));
       } else {
         wire->contents = viz::mojom::TileContents::NewMissingReason(
-            viz::mojom::MissingTileReason::kResourceNotReady);
+            mojom::MissingTileReason::kResourceNotReady);
       }
       break;
   }
diff --git a/cc/mojom/BUILD.gn b/cc/mojom/BUILD.gn
index 1bed7543..6f003466c 100644
--- a/cc/mojom/BUILD.gn
+++ b/cc/mojom/BUILD.gn
@@ -119,6 +119,11 @@
   sources = [ "layer_type.mojom" ]
 }
 
+mojom("missing_tile_reason") {
+  generate_java = true
+  sources = [ "missing_tile_reason.mojom" ]
+}
+
 mojom("ui_resource_id") {
   generate_java = true
   sources = [ "ui_resource_id.mojom" ]
diff --git a/cc/mojom/missing_tile_reason.mojom b/cc/mojom/missing_tile_reason.mojom
new file mode 100644
index 0000000..777f6ba
--- /dev/null
+++ b/cc/mojom/missing_tile_reason.mojom
@@ -0,0 +1,17 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module cc.mojom;
+
+// For tiles that are missing or otherwise not ready to draw, this is the
+// reason why.
+// Note that this enum was part of
+// services/viz/public/mojom/compositing/tiling.mojom earlier but needed to
+// be moved here due to issue related to UBSAN bots.
+// crbug.com/418120288 for more info.
+enum MissingTileReason {
+  kOutOfMemory,
+  kResourceNotReady,
+  kTileDeleted,
+};
diff --git a/cc/tiles/tile.cc b/cc/tiles/tile.cc
index 5ee868a..96c892e 100644
--- a/cc/tiles/tile.cc
+++ b/cc/tiles/tile.cc
@@ -43,6 +43,7 @@
   TRACE_EVENT_OBJECT_DELETED_WITH_ID(
       TRACE_DISABLED_BY_DEFAULT("cc.debug"),
       "cc::Tile", this);
+  deleted_ = true;
   tile_manager_->Release(this);
 }
 
diff --git a/cc/tiles/tile.h b/cc/tiles/tile.h
index 241e20c..49df545 100644
--- a/cc/tiles/tile.h
+++ b/cc/tiles/tile.h
@@ -144,6 +144,7 @@
   void mark_used() { used_ = true; }
   void clear_used() { used_ = false; }
   bool used() const { return used_; }
+  bool deleted() const { return deleted_; }
 
  private:
   friend class TileManager;
@@ -191,6 +192,9 @@
   // rasterize a resource with checker images.
   bool raster_task_scheduled_with_checker_images_ : 1 = false;
 
+  // Set to true in destructor.
+  bool deleted_ : 1 = false;
+
   Id id_;
 
   // List of Rect-Transform pairs, representing unoccluded parts of the
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index 92bf4f7..d42871e 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -578,17 +578,10 @@
   if (tile->raster_task_scheduled_with_checker_images())
     num_of_tiles_with_checker_images_--;
   DCHECK_GE(num_of_tiles_with_checker_images_, 0);
+  CHECK(tile->deleted());
 
-  // Notify client that the tile state has changed only when a tile resource
-  // is released. Note that TileManager::Release() is only called when a Tile
-  // is being deleted. In this case we never update the damage. So make sure
-  // that NotifyTileStateChanged() does not update the damage for this tile.
-  // If a tile was a solid color, there is no resource associated with it.
-  // We do need to notify about tile deletion in that case.
-  if (FreeResourcesForTile(tile) ||
-      tile->draw_info().mode() == TileDrawInfo::SOLID_COLOR_MODE) {
-    client_->NotifyTileStateChanged(tile, /*update_damage=*/false);
-  }
+  FreeResourcesForTile(tile);
+  client_->NotifyTileStateChanged(tile, /*update_damage=*/false);
   tiles_.erase(tile->id());
 }
 
@@ -1129,8 +1122,8 @@
   std::unique_ptr<TilesWithResourceIterator> iterator =
       client_->CreateTilesWithResourceIterator();
   for (; !iterator->AtEnd(); iterator->Next()) {
-    if (iterator->IsCurrentTileOccluded() &&
-        FreeResourcesForTile(iterator->GetCurrent())) {
+    if (iterator->IsCurrentTileOccluded()) {
+      FreeResourcesForTile(iterator->GetCurrent());
       // We don't update the damage when Occluded tiles are released.
       client_->NotifyTileStateChanged(iterator->GetCurrent(),
                                       /*update_damage=*/false);
@@ -1138,7 +1131,7 @@
   }
 }
 
-bool TileManager::FreeResourcesForTile(Tile* tile) {
+void TileManager::FreeResourcesForTile(Tile* tile) {
   TileDrawInfo& draw_info = tile->draw_info();
 
   if (draw_info.is_checker_imaged()) {
@@ -1149,18 +1142,15 @@
   if (draw_info.has_resource()) {
     resource_pool_->ReleaseResource(draw_info.TakeResource());
     pending_gpu_work_tiles_.erase(tile);
-    return true;
   }
-  return false;
 }
 
 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
     Tile* tile) {
   TRACE_EVENT0("viz", __PRETTY_FUNCTION__);
   bool was_ready_to_draw = tile->draw_info().IsReadyToDraw();
-  if (FreeResourcesForTile(tile)) {
-    client_->NotifyTileStateChanged(tile, /*update_damage=*/was_ready_to_draw);
-  }
+  FreeResourcesForTile(tile);
+  client_->NotifyTileStateChanged(tile, /*update_damage=*/was_ready_to_draw);
 }
 
 void TileManager::PartitionImagesForCheckering(
diff --git a/cc/tiles/tile_manager.h b/cc/tiles/tile_manager.h
index 7ce47a01..8d1d066 100644
--- a/cc/tiles/tile_manager.h
+++ b/cc/tiles/tile_manager.h
@@ -302,7 +302,7 @@
   void TrimPrepaintTiles();
 
   // True if tile resources are present and freed.
-  bool FreeResourcesForTile(Tile* tile);
+  void FreeResourcesForTile(Tile* tile);
   void FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(Tile* tile);
   scoped_refptr<TileTask> CreateRasterTask(
       const PrioritizedTile& prioritized_tile,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 5fa95d6d..ca62197 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -1017,6 +1017,7 @@
                             browsingModeThemeColorProvider,
                             mActivityTabProvider,
                             mToolbarNavControlsEnabledSupplier,
+                            /* onNavigationPopupShown= */ () -> {},
                             historyDelegate);
         }
 
diff --git a/chrome/browser/ai/ai_data_keyed_service.cc b/chrome/browser/ai/ai_data_keyed_service.cc
index cffcae6..56610a83 100644
--- a/chrome/browser/ai/ai_data_keyed_service.cc
+++ b/chrome/browser/ai/ai_data_keyed_service.cc
@@ -74,9 +74,9 @@
 
 #if !BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "components/tabs/public/tab_group.h"
 #endif
 
 #if BUILDFLAG(ENABLE_PDF)
diff --git a/chrome/browser/ai/ai_data_keyed_service_browsertest.cc b/chrome/browser/ai/ai_data_keyed_service_browsertest.cc
index 36381ff8..dd3dadf 100644
--- a/chrome/browser/ai/ai_data_keyed_service_browsertest.cc
+++ b/chrome/browser/ai/ai_data_keyed_service_browsertest.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/tabs/public/tab_features.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
@@ -42,6 +41,7 @@
 #include "components/optimization_guide/proto/features/actions_data.pb.h"
 #include "components/optimization_guide/proto/features/common_quality_data.pb.h"
 #include "components/passage_embeddings/passage_embeddings_test_util.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
@@ -230,13 +230,15 @@
       browser()->GetTabStripModel()->AddToNewGroup({0}));
   auto vis_data1 = *tab_group1->visual_data();
   vis_data1.SetTitle(u"ok");
-  tab_group1->SetVisualData(vis_data1);
+  browser()->GetTabStripModel()->ChangeTabGroupVisuals(tab_group1->id(),
+                                                       vis_data1);
 
   auto* tab_group2 = browser()->GetTabStripModel()->group_model()->GetTabGroup(
       browser()->GetTabStripModel()->AddToNewGroup({1, 2}));
   auto vis_data2 = *tab_group1->visual_data();
   vis_data2.SetTitle(u"ok");
-  tab_group2->SetVisualData(vis_data2);
+  browser()->GetTabStripModel()->ChangeTabGroupVisuals(tab_group2->id(),
+                                                       vis_data2);
 
   AiData ai_data = LoadSimplePageAndData();
   ASSERT_TRUE(ai_data.has_value());
@@ -253,13 +255,15 @@
       browser()->GetTabStripModel()->AddToNewGroup({0}));
   auto vis_data1 = *tab_group1->visual_data();
   vis_data1.SetTitle(u"ok");
-  tab_group1->SetVisualData(vis_data1);
+  browser()->GetTabStripModel()->ChangeTabGroupVisuals(tab_group1->id(),
+                                                       vis_data1);
 
   auto* tab_group2 = browser()->GetTabStripModel()->group_model()->GetTabGroup(
       browser()->GetTabStripModel()->AddToNewGroup({1, 2}));
   auto vis_data2 = *tab_group1->visual_data();
   vis_data2.SetTitle(u"ok");
-  tab_group2->SetVisualData(vis_data2);
+  browser()->GetTabStripModel()->ChangeTabGroupVisuals(tab_group2->id(),
+                                                       vis_data2);
 
   AiData ai_data = LoadSimplePageAndData();
   ASSERT_TRUE(ai_data.has_value());
diff --git a/chrome/browser/android/BUILD.gn b/chrome/browser/android/BUILD.gn
index 8d5f069..2a18a71 100644
--- a/chrome/browser/android/BUILD.gn
+++ b/chrome/browser/android/BUILD.gn
@@ -16,6 +16,7 @@
   public_deps = [ "//chrome/browser:browser_public_dependencies" ]
   deps = [
     ":tabs_public",
+    "//chrome/browser/privacy_sandbox/incognito:tab_observer",
     "//chrome/browser/sync",
     "//components/external_intents/android",
     "//components/favicon/content",
diff --git a/chrome/browser/android/tab_features.cc b/chrome/browser/android/tab_features.cc
index 2f50379..7505c29 100644
--- a/chrome/browser/android/tab_features.cc
+++ b/chrome/browser/android/tab_features.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/android/tab_features.h"
 
+#include "chrome/browser/privacy_sandbox/incognito/privacy_sandbox_incognito_tab_observer.h"
 #include "chrome/browser/sync/sessions/sync_sessions_router_tab_helper.h"
 #include "chrome/browser/sync/sessions/sync_sessions_web_contents_router_factory.h"
 #include "chrome/browser/translate/chrome_translate_client.h"
@@ -23,6 +24,10 @@
 
   dwa_web_contents_observer_ =
       std::make_unique<metrics::DwaWebContentsObserver>(web_contents);
+
+  privacy_sandbox_incognito_tab_observer_ =
+      std::make_unique<privacy_sandbox::PrivacySandboxIncognitoTabObserver>(
+          web_contents);
 }
 
 TabFeatures::~TabFeatures() = default;
diff --git a/chrome/browser/android/tab_features.h b/chrome/browser/android/tab_features.h
index 94ca4a04..fc7ff9b 100644
--- a/chrome/browser/android/tab_features.h
+++ b/chrome/browser/android/tab_features.h
@@ -21,6 +21,10 @@
 class DwaWebContentsObserver;
 }  // namespace metrics
 
+namespace privacy_sandbox {
+class PrivacySandboxIncognitoTabObserver;
+}  // namespace privacy_sandbox
+
 namespace tabs {
 
 // This class holds state that is scoped to a tab in Android. It is constructed
@@ -34,6 +38,8 @@
   std::unique_ptr<sync_sessions::SyncSessionsRouterTabHelper>
       sync_sessions_router_;
   std::unique_ptr<metrics::DwaWebContentsObserver> dwa_web_contents_observer_;
+  std::unique_ptr<privacy_sandbox::PrivacySandboxIncognitoTabObserver>
+      privacy_sandbox_incognito_tab_observer_;
 };
 
 }  // namespace tabs
diff --git a/chrome/browser/ash/app_mode/kiosk_troubleshooting_tools_browsertest.cc b/chrome/browser/ash/app_mode/kiosk_troubleshooting_tools_browsertest.cc
index 873ac0c2..cb9e5d78 100644
--- a/chrome/browser/ash/app_mode/kiosk_troubleshooting_tools_browsertest.cc
+++ b/chrome/browser/ash/app_mode/kiosk_troubleshooting_tools_browsertest.cc
@@ -7,8 +7,10 @@
 #include "ash/shell.h"
 #include "base/run_loop.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "chrome/browser/ash/app_mode/kiosk_controller.h"
+#include "chrome/browser/ash/app_mode/kiosk_system_session.h"
+#include "chrome/browser/ash/app_mode/test/kiosk_mixin.h"
 #include "chrome/browser/ash/app_mode/test/kiosk_test_utils.h"
-#include "chrome/browser/ash/login/app_mode/test/web_kiosk_base_test.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_browser_window_handler.h"
 #include "chrome/browser/devtools/devtools_window_testing.h"
 #include "chrome/browser/policy/developer_tools_policy_handler.h"
@@ -17,6 +19,8 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/views/task_manager_view.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/mixin_based_in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
@@ -28,16 +32,27 @@
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
 
-using ash::kiosk::test::CreatePopupBrowser;
-using ash::kiosk::test::CreateRegularBrowser;
-using ash::kiosk::test::DidKioskCloseNewWindow;
 using policy::DeveloperToolsPolicyHandler::Availability::kAllowed;
 using policy::DeveloperToolsPolicyHandler::Availability::kDisallowed;
 
 namespace ash {
 
+using kiosk::test::CreatePopupBrowser;
+using kiosk::test::CreateRegularBrowser;
+using kiosk::test::CurrentProfile;
+using kiosk::test::DidKioskCloseNewWindow;
+using kiosk::test::WaitKioskLaunched;
+
+namespace {
+
+KioskSystemSession& GetKioskSystemSession() {
+  return CHECK_DEREF(KioskController::Get().GetKioskSystemSession());
+}
+
+}  // namespace
+
 // Test kiosk troubleshooting tools on web kiosk.
-class KioskTroubleshootingToolsTest : public WebKioskBaseTest {
+class KioskTroubleshootingToolsTest : public MixinBasedInProcessBrowserTest {
  public:
   KioskTroubleshootingToolsTest() = default;
 
@@ -46,19 +61,22 @@
       const KioskTroubleshootingToolsTest&) = delete;
 
   void SetUpOnMainThread() override {
-    WebKioskBaseTest::SetUpOnMainThread();
+    MixinBasedInProcessBrowserTest::SetUpOnMainThread();
     event_generator_ = std::make_unique<ui::test::EventGenerator>(
         ash::Shell::Get()->GetPrimaryRootWindow());
+    ASSERT_TRUE(WaitKioskLaunched());
+    SelectFirstBrowser();
+    ExpectOnlyKioskAppOpen();
   }
 
-  void UpdateTroubleshootingToolsPolicy(bool enable) {
-    profile()->GetPrefs()->SetBoolean(prefs::kKioskTroubleshootingToolsEnabled,
-                                      enable);
+  void UpdateTroubleshootingToolsPolicy(bool enable) const {
+    CurrentProfile().GetPrefs()->SetBoolean(
+        prefs::kKioskTroubleshootingToolsEnabled, enable);
   }
 
   void EnableDevTools() const {
-    profile()->GetPrefs()->SetInteger(prefs::kDevToolsAvailability,
-                                      static_cast<int>(kAllowed));
+    CurrentProfile().GetPrefs()->SetInteger(prefs::kDevToolsAvailability,
+                                            static_cast<int>(kAllowed));
   }
 
   void ExpectOpenBrowser(chromeos::KioskBrowserWindowType window_type) const {
@@ -79,7 +97,9 @@
     if (contents->IsLoading()) {
       content::WaitForLoadStop(contents);
     }
-    ASSERT_EQ(contents->GetLastCommittedURL(), app_install_url());
+    ASSERT_EQ(
+        contents->GetLastCommittedURL(),
+        kiosk_.GetDefaultServerUrl(KioskMixin::SimpleWebAppOption().url_path));
   }
 
   void EmulateOpenNewWindowShortcutPressed() const {
@@ -120,11 +140,12 @@
   }
 
   Browser& OpenForAppPopupBrowser() const {
-    profile()->GetPrefs()->SetBoolean(prefs::kNewWindowsInKioskAllowed, true);
-    Browser& browser =
-        CreatePopupBrowser(*profile(), kiosk_app_browser()->app_name());
+    CurrentProfile().GetPrefs()->SetBoolean(prefs::kNewWindowsInKioskAllowed,
+                                            true);
+    Browser& popup_browser =
+        CreatePopupBrowser(CurrentProfile(), browser()->app_name());
     EXPECT_FALSE(DidKioskCloseNewWindow());
-    return browser;
+    return popup_browser;
   }
 
   bool IsLactActiveBrowserResizable() {
@@ -142,33 +163,34 @@
  protected:
   std::unique_ptr<ui::test::EventGenerator> event_generator_;
   base::HistogramTester histogram;
+
+  KioskMixin kiosk_{
+      &mixin_host_,
+      KioskMixin::Config{/*name=*/{},
+                         KioskMixin::AutoLaunchAccount{
+                             KioskMixin::SimpleWebAppOption().account_id},
+                         {KioskMixin::SimpleWebAppOption()}}};
 };
 
 IN_PROC_BROWSER_TEST_F(KioskTroubleshootingToolsTest,
                        DevToolsBasicShowAndShutdown) {
-  InitializeRegularOnlineKiosk();
-  ExpectOnlyKioskAppOpen();
-
   UpdateTroubleshootingToolsPolicy(/*enable=*/true);
   EnableDevTools();
-  DevToolsWindowTesting::OpenDevToolsWindowSync(kiosk_app_browser(),
+  DevToolsWindowTesting::OpenDevToolsWindowSync(browser(),
                                                 /*is_docked=*/false);
   ExpectOpenBrowser(chromeos::KioskBrowserWindowType::kOpenedDevToolsBrowser);
 
   // Shut down the session when kiosk troubleshooting tools get disabled.
   UpdateTroubleshootingToolsPolicy(/*enable=*/false);
-  EXPECT_TRUE(kiosk_system_session()->is_shutting_down());
+  EXPECT_TRUE(GetKioskSystemSession().is_shutting_down());
 }
 
 IN_PROC_BROWSER_TEST_F(KioskTroubleshootingToolsTest,
                        DevToolsDisallowedNoShow) {
-  InitializeRegularOnlineKiosk();
-  ExpectOnlyKioskAppOpen();
-
   UpdateTroubleshootingToolsPolicy(/*enable=*/true);
 
   // Devtools are not enabled, but disabled by default.
-  DevToolsWindowTesting::OpenDevToolsWindowSync(kiosk_app_browser(),
+  DevToolsWindowTesting::OpenDevToolsWindowSync(browser(),
                                                 /*is_docked=*/false);
 
   ExpectOnlyKioskAppOpen();
@@ -177,13 +199,9 @@
 
 IN_PROC_BROWSER_TEST_F(KioskTroubleshootingToolsTest,
                        DevToolsTroubleshootingDisabled) {
-  InitializeRegularOnlineKiosk();
-  ExpectOnlyKioskAppOpen();
-
   EnableDevTools();
-  DevToolsWindowTesting::OpenDevToolsWindowSync(kiosk_app_browser(),
+  DevToolsWindowTesting::OpenDevToolsWindowSync(browser(),
                                                 /*is_docked=*/false);
-  ExpectOnlyKioskAppOpen();
 
   // Since the devtools are allowed, the devtools window is open, but
   // immediately gets closed, since the kiosk troubleshooting tools are
@@ -196,9 +214,7 @@
 
 IN_PROC_BROWSER_TEST_F(KioskTroubleshootingToolsTest,
                        NewWindowBasicShowAndShutdown) {
-  InitializeRegularOnlineKiosk();
   UpdateTroubleshootingToolsPolicy(/*enable=*/true);
-  ExpectOnlyKioskAppOpen();
 
   EmulateOpenNewWindowShortcutPressed();
   EXPECT_FALSE(DidKioskCloseNewWindow());
@@ -208,17 +224,15 @@
 
   // Shut down the session when kiosk troubleshooting tools get disabled.
   UpdateTroubleshootingToolsPolicy(/*enable=*/false);
-  EXPECT_TRUE(kiosk_system_session()->is_shutting_down());
+  EXPECT_TRUE(GetKioskSystemSession().is_shutting_down());
 }
 
 IN_PROC_BROWSER_TEST_F(KioskTroubleshootingToolsTest,
                        OpenAllTroubleshootingTools) {
-  InitializeRegularOnlineKiosk();
   UpdateTroubleshootingToolsPolicy(/*enable=*/true);
-  ExpectOnlyKioskAppOpen();
   EnableDevTools();
 
-  DevToolsWindowTesting::OpenDevToolsWindowSync(kiosk_app_browser(),
+  DevToolsWindowTesting::OpenDevToolsWindowSync(browser(),
                                                 /*is_docked=*/false);
 
   EmulateOpenNewWindowShortcutPressed();
@@ -236,15 +250,13 @@
 
 IN_PROC_BROWSER_TEST_F(KioskTroubleshootingToolsTest,
                        AllTroubleshootingToolsAreResizable) {
-  InitializeRegularOnlineKiosk();
   UpdateTroubleshootingToolsPolicy(/*enable=*/true);
-  ExpectOnlyKioskAppOpen();
   EnableDevTools();
 
   // The main browser should not be resizable.
   EXPECT_FALSE(IsLactActiveBrowserResizable());
 
-  DevToolsWindowTesting::OpenDevToolsWindowSync(kiosk_app_browser(),
+  DevToolsWindowTesting::OpenDevToolsWindowSync(browser(),
                                                 /*is_docked=*/false);
   EXPECT_TRUE(IsLactActiveBrowserResizable());
 
@@ -255,11 +267,8 @@
 
 IN_PROC_BROWSER_TEST_F(KioskTroubleshootingToolsTest,
                        NewWindowDisallowedNoShow) {
-  InitializeRegularOnlineKiosk();
-  ExpectOnlyKioskAppOpen();
-
   // Explicitly open a new window to make sure it will be closed.
-  CreateRegularBrowser(*profile());
+  CreateRegularBrowser(CurrentProfile());
   EXPECT_TRUE(DidKioskCloseNewWindow());
 
   histogram.ExpectBucketCount(
@@ -270,9 +279,6 @@
 
 IN_PROC_BROWSER_TEST_F(KioskTroubleshootingToolsTest,
                        NewWindowShortcutDisallowed) {
-  InitializeRegularOnlineKiosk();
-  ExpectOnlyKioskAppOpen();
-
   EmulateOpenNewWindowShortcutPressed();
   base::RunLoop().RunUntilIdle();
 
@@ -286,9 +292,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(KioskTroubleshootingToolsTest, NewWindowAddTab) {
-  InitializeRegularOnlineKiosk();
   UpdateTroubleshootingToolsPolicy(/*enable=*/true);
-  ExpectOnlyKioskAppOpen();
 
   Browser* newly_opened_browser =
       EmulateOpenNewWindowShortcutPressedAndReturnNewBrowser();
@@ -306,21 +310,20 @@
 }
 
 IN_PROC_BROWSER_TEST_F(KioskTroubleshootingToolsTest, SwitchWindowsForward) {
-  InitializeRegularOnlineKiosk();
   UpdateTroubleshootingToolsPolicy(/*enable=*/true);
-  Browser* main_browser = BrowserList::GetInstance()->get(0);
-  EXPECT_TRUE(main_browser->window()->IsActive());
+
+  EXPECT_TRUE(browser()->window()->IsActive());
   Browser* newly_opened_browser =
       EmulateOpenNewWindowShortcutPressedAndReturnNewBrowser();
 
   // When new window is opened, it becomes active.
   EXPECT_TRUE(newly_opened_browser->window()->IsActive());
-  EXPECT_FALSE(main_browser->window()->IsActive());
+  EXPECT_FALSE(browser()->window()->IsActive());
 
   EmulateSwitchWindowsForwardShortcutPressed();
 
   // The main window should be active again.
-  EXPECT_TRUE(main_browser->window()->IsActive());
+  EXPECT_TRUE(browser()->window()->IsActive());
   EXPECT_FALSE(newly_opened_browser->window()->IsActive());
 }
 
@@ -332,28 +335,24 @@
 #endif
 IN_PROC_BROWSER_TEST_F(KioskTroubleshootingToolsTest,
                        MAYBE_SwitchWindowsBackward) {
-  InitializeRegularOnlineKiosk();
   UpdateTroubleshootingToolsPolicy(/*enable=*/true);
-  Browser* main_browser = BrowserList::GetInstance()->get(0);
-  EXPECT_TRUE(main_browser->window()->IsActive());
+  EXPECT_TRUE(browser()->window()->IsActive());
   Browser* newly_opened_browser =
       EmulateOpenNewWindowShortcutPressedAndReturnNewBrowser();
 
   // When new window is opened, it becomes active.
   EXPECT_TRUE(newly_opened_browser->window()->IsActive());
-  EXPECT_FALSE(main_browser->window()->IsActive());
+  EXPECT_FALSE(browser()->window()->IsActive());
 
   EmulateSwitchWindowsBackwardShortcutPressed();
 
   // The main window should be active again.
-  EXPECT_TRUE(main_browser->window()->IsActive());
+  EXPECT_TRUE(browser()->window()->IsActive());
   EXPECT_FALSE(newly_opened_browser->window()->IsActive());
 }
 
 IN_PROC_BROWSER_TEST_F(KioskTroubleshootingToolsTest, SwitchWindowsDisallowed) {
-  InitializeRegularOnlineKiosk();
-  Browser* main_browser = BrowserList::GetInstance()->get(0);
-  EXPECT_TRUE(main_browser->window()->IsActive());
+  EXPECT_TRUE(browser()->window()->IsActive());
 
   // Enable another feature to allow opening two popup browsers to make sure
   // that switching between windows is still not available if the
@@ -362,48 +361,39 @@
 
   // When new window is opened, it becomes active.
   EXPECT_TRUE(new_browser.window()->IsActive());
-  EXPECT_FALSE(main_browser->window()->IsActive());
+  EXPECT_FALSE(browser()->window()->IsActive());
 
   EmulateSwitchWindowsForwardShortcutPressed();
 
   // Active window remains the same.
   EXPECT_TRUE(new_browser.window()->IsActive());
-  EXPECT_FALSE(main_browser->window()->IsActive());
+  EXPECT_FALSE(browser()->window()->IsActive());
 
   EmulateSwitchWindowsBackwardShortcutPressed();
 
   // Active window remains the same.
   EXPECT_TRUE(new_browser.window()->IsActive());
-  EXPECT_FALSE(main_browser->window()->IsActive());
+  EXPECT_FALSE(browser()->window()->IsActive());
 }
 
-class KioskTroubleshootingToolsParamTest
-    : public KioskTroubleshootingToolsTest,
-      public testing::WithParamInterface<
-          /*troubleshooting_policy_enabled=*/bool> {
- public:
-  bool IsTroubleshootingPolicyEnabledTest() const { return GetParam(); }
-};
+IN_PROC_BROWSER_TEST_F(
+    KioskTroubleshootingToolsTest,
+    TaskManagerShortcutShouldNotShowIfTroubleshootingIsDisabled) {
+  EmulateOpenTaskManagerShortcutPressed();
+  base::RunLoop().RunUntilIdle();
 
-IN_PROC_BROWSER_TEST_P(KioskTroubleshootingToolsParamTest,
-                       TaskManagerShortcutShow) {
-  InitializeRegularOnlineKiosk();
-  if (IsTroubleshootingPolicyEnabledTest()) {
-    UpdateTroubleshootingToolsPolicy(/*enable=*/true);
-  }
+  EXPECT_EQ(nullptr, GetTaskManagerView());
+}
+
+IN_PROC_BROWSER_TEST_F(
+    KioskTroubleshootingToolsTest,
+    TaskManagerShortcutShouldShowIfTroubleshootingIsEnabled) {
+  UpdateTroubleshootingToolsPolicy(/*enable=*/true);
 
   EmulateOpenTaskManagerShortcutPressed();
   base::RunLoop().RunUntilIdle();
 
-  if (IsTroubleshootingPolicyEnabledTest()) {
-    EXPECT_NE(nullptr, GetTaskManagerView());
-  } else {
-    EXPECT_EQ(nullptr, GetTaskManagerView());
-  }
+  EXPECT_NE(nullptr, GetTaskManagerView());
 }
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         KioskTroubleshootingToolsParamTest,
-                         testing::Bool());
-
 }  // namespace ash
diff --git a/chrome/browser/ash/boca/spotlight/spotlight_crd_manager_impl.cc b/chrome/browser/ash/boca/spotlight/spotlight_crd_manager_impl.cc
index 7a4fea19..254555d 100644
--- a/chrome/browser/ash/boca/spotlight/spotlight_crd_manager_impl.cc
+++ b/chrome/browser/ash/boca/spotlight/spotlight_crd_manager_impl.cc
@@ -53,36 +53,23 @@
 
 SpotlightCrdManagerImpl::~SpotlightCrdManagerImpl() = default;
 
-void SpotlightCrdManagerImpl::OnSessionStarted(
-    const std::string& teacher_email) {
-  if (!ash::features::IsBocaSpotlightEnabled()) {
-    return;
-  }
-  teacher_email_ = teacher_email;
-}
-
 void SpotlightCrdManagerImpl::OnSessionEnded() {
   if (!ash::features::IsBocaSpotlightEnabled()) {
     return;
   }
-  teacher_email_ = "";
   crd_session_->TerminateSession();
   persistent_bubble_controller_->OnSessionEnded();
 }
 
 void SpotlightCrdManagerImpl::InitiateSpotlightSession(
-    ConnectionCodeCallback callback) {
+    ConnectionCodeCallback callback,
+    const std::string& requester_email) {
   if (!ash::features::IsBocaSpotlightEnabled()) {
     return;
   }
-  if (teacher_email_.empty()) {
-    LOG(WARNING)
-        << "[Boca] Tried to initiate Spotlight without valid teacher email.";
-    return;
-  }
 
   SessionParameters parameters;
-  parameters.viewer_email = teacher_email_;
+  parameters.viewer_email = requester_email;
   parameters.allow_file_transfer = false;
   parameters.show_confirmation_dialog = false;
   parameters.terminate_upon_input = false;
diff --git a/chrome/browser/ash/boca/spotlight/spotlight_crd_manager_impl.h b/chrome/browser/ash/boca/spotlight/spotlight_crd_manager_impl.h
index 3412411..bccbc36c 100644
--- a/chrome/browser/ash/boca/spotlight/spotlight_crd_manager_impl.h
+++ b/chrome/browser/ash/boca/spotlight/spotlight_crd_manager_impl.h
@@ -31,15 +31,13 @@
   ~SpotlightCrdManagerImpl() override;
 
   // SpotlightCrdManager:
-  void OnSessionStarted(const std::string& teacher_email) override;
   void OnSessionEnded() override;
-  void InitiateSpotlightSession(ConnectionCodeCallback callback) override;
+  void InitiateSpotlightSession(ConnectionCodeCallback callback,
+                                const std::string& requester_email) override;
   void ShowPersistentNotification(const std::string& teacher_name) override;
   void HidePersistentNotification() override;
 
  private:
-  std::string teacher_email_;
-
   // Owns the `policy::CrdAdminSessionController` which provides a
   // `policy::StartCrdSessionJobDelegate`. The delegate is what actually
   // interacts with the CRD host and the `policy::SharedCrdSession` calls makes
diff --git a/chrome/browser/ash/boca/spotlight/spotlight_crd_manager_impl_browsertest.cc b/chrome/browser/ash/boca/spotlight/spotlight_crd_manager_impl_browsertest.cc
index d0e2c76..e3599a1 100644
--- a/chrome/browser/ash/boca/spotlight/spotlight_crd_manager_impl_browsertest.cc
+++ b/chrome/browser/ash/boca/spotlight/spotlight_crd_manager_impl_browsertest.cc
@@ -101,8 +101,7 @@
           Invoke([&](auto callback) { std::move(callback).Run("123"); })));
   TestFuture<const std::string&> success_future;
 
-  manager_->OnSessionStarted(kUserEmail);
-  manager_->InitiateSpotlightSession(success_future.GetCallback());
+  manager_->InitiateSpotlightSession(success_future.GetCallback(), kUserEmail);
   ::testing::Mock::VerifyAndClearExpectations(crd_session_);
 
   EXPECT_EQ(kSpotlightConnectionCode, success_future.Get());
@@ -122,11 +121,11 @@
         error_callback_future.SetValue();
       })));
 
-  manager_->OnSessionStarted(kUserEmail);
   manager_->InitiateSpotlightSession(
       base::BindOnce([](const std::string& result) {
         GTEST_FAIL() << "Unexpected call to success callback";
-      }));
+      }),
+      kUserEmail);
   ::testing::Mock::VerifyAndClearExpectations(crd_session_);
 
   EXPECT_TRUE(error_callback_future.Wait());
@@ -138,38 +137,15 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SpotlightCrdManagerImplTest,
-                       InitiateSpotlightSessionShouldFailIfNotInActiveSession) {
-  EXPECT_CALL(*crd_session_, StartCrdHost).Times(0);
-
-  manager_->InitiateSpotlightSession(
-      base::BindOnce([](const std::string& result) {
-        GTEST_FAIL() << "Unexpected call to success callback";
-      }));
-  ::testing::Mock::VerifyAndClearExpectations(crd_session_);
-}
-
-IN_PROC_BROWSER_TEST_F(
-    SpotlightCrdManagerImplTest,
-    OnSessionEndedShouldClearTeacherEmailAndTerminateSession) {
+                       OnSessionEndedShouldTerminateSession) {
   EXPECT_CALL(*crd_session_, StartCrdHost).Times(1);
   EXPECT_CALL(*crd_session_, TerminateSession()).Times(1);
   TestFuture<const std::string&> success_future;
 
-  manager_->OnSessionStarted(kUserEmail);
-  manager_->InitiateSpotlightSession(success_future.GetCallback());
+  manager_->InitiateSpotlightSession(success_future.GetCallback(), kUserEmail);
 
   manager_->OnSessionEnded();
   ::testing::Mock::VerifyAndClearExpectations(crd_session_);
-
-  // Starting another session should end before calling crd since the
-  // teacher_email_ is now be empty.
-
-  EXPECT_CALL(*crd_session_, StartCrdHost).Times(0);
-  manager_->InitiateSpotlightSession(
-      base::BindOnce([](const std::string& result) {
-        GTEST_FAIL() << "Unexpected call to success callback";
-      }));
-  ::testing::Mock::VerifyAndClearExpectations(crd_session_);
 }
 
 IN_PROC_BROWSER_TEST_F(SpotlightCrdManagerImplTest,
@@ -204,8 +180,7 @@
           [&]() { std::move(session_finished_future.GetCallback()).Run(); }));
 
   TestFuture<const std::string&> success_future;
-  manager_->OnSessionStarted(kUserEmail);
-  manager_->InitiateSpotlightSession(success_future.GetCallback());
+  manager_->InitiateSpotlightSession(success_future.GetCallback(), kUserEmail);
 
   manager_->OnSessionEnded();
   ::testing::Mock::VerifyAndClearExpectations(crd_session_);
diff --git a/chrome/browser/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc
index c1985a6..d99cb7e 100644
--- a/chrome/browser/autofill/autofill_browsertest.cc
+++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -377,7 +377,15 @@
 // country. The data file contains two profiles with valid phone numbers and two
 // profiles with invalid phone numbers from their respective country.
 // Profiles with an invalid number are imported, but their number is removed.
-IN_PROC_BROWSER_TEST_F(AutofillTest, ProfileSavedWithValidCountryPhone) {
+// TODO(https://crbug.com/418932421): Flaky on Mac 13 Tests.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_ProfileSavedWithValidCountryPhone \
+  DISABLED_ProfileSavedWithValidCountryPhone
+#else
+#define MAYBE_ProfileSavedWithValidCountryPhone \
+  ProfileSavedWithValidCountryPhone
+#endif
+IN_PROC_BROWSER_TEST_F(AutofillTest, MAYBE_ProfileSavedWithValidCountryPhone) {
   std::vector<FormMap> profiles = {
       {{"NAME_FIRST", "Bob"},
        {"NAME_LAST", "Smith"},
@@ -469,7 +477,15 @@
 //   The phone number does not have a leading '+'.
 //   The phone number has a leading international direct dialing (IDD) code.
 // This does not apply to US numbers. For US numbers, '+' is removed.
-IN_PROC_BROWSER_TEST_F(AutofillTest, UsePlusSignForInternationalNumber) {
+// TODO(https://crbug.com/418932421): Flaky on Mac 13 Tests.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_UsePlusSignForInternationalNumber \
+  DISABLED_UsePlusSignForInternationalNumber
+#else
+#define MAYBE_UsePlusSignForInternationalNumber \
+  UsePlusSignForInternationalNumber
+#endif
+IN_PROC_BROWSER_TEST_F(AutofillTest, MAYBE_UsePlusSignForInternationalNumber) {
   std::vector<FormMap> profiles;
 
   FormMap data1;
@@ -580,7 +596,16 @@
 // Minimum address values needed during aggregation are: address line 1, city,
 // state, and zip code.
 // Profiles are merged when data for address line 1 and city match.
-IN_PROC_BROWSER_TEST_F(AutofillTest, ProfilesNotMergedWhenNoMinAddressData) {
+// TODO(https://crbug.com/418932421): Flaky on Mac 13 Tests.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_ProfilesNotMergedWhenNoMinAddressData \
+  DISABLED_ProfilesNotMergedWhenNoMinAddressData
+#else
+#define MAYBE_ProfilesNotMergedWhenNoMinAddressData \
+  ProfilesNotMergedWhenNoMinAddressData
+#endif
+IN_PROC_BROWSER_TEST_F(AutofillTest,
+                       MAYBE_ProfilesNotMergedWhenNoMinAddressData) {
   AggregateProfilesIntoAutofillPrefs("dataset_no_address.txt");
 
   ASSERT_EQ(
diff --git a/chrome/browser/extensions/api/tab_groups/tab_groups_api.cc b/chrome/browser/extensions/api/tab_groups/tab_groups_api.cc
index 050e49ed..e0d533b 100644
--- a/chrome/browser/extensions/api/tab_groups/tab_groups_api.cc
+++ b/chrome/browser/extensions/api/tab_groups/tab_groups_api.cc
@@ -20,7 +20,6 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -32,6 +31,7 @@
 #include "components/tab_groups/tab_group_color.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "ui/gfx/range/range.h"
 
 using tabs::TabModel;
@@ -236,7 +236,7 @@
   TabGroup* tab_group = tab_strip_model->group_model()->GetTabGroup(id);
 
   tab_groups::TabGroupVisualData new_visual_data(title, color, collapsed);
-  tab_group->SetVisualData(std::move(new_visual_data));
+  tab_strip_model->ChangeTabGroupVisuals(id, std::move(new_visual_data));
 
   if (!has_callback())
     return RespondNow(NoArguments());
diff --git a/chrome/browser/extensions/api/tab_groups/tab_groups_api_apitest.cc b/chrome/browser/extensions/api/tab_groups/tab_groups_api_apitest.cc
index 16f9008..c358bb8 100644
--- a/chrome/browser/extensions/api/tab_groups/tab_groups_api_apitest.cc
+++ b/chrome/browser/extensions/api/tab_groups/tab_groups_api_apitest.cc
@@ -10,12 +10,12 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/extensions/api/tab_groups.h"
 #include "components/saved_tab_groups/public/tab_group_sync_service.h"
 #include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
diff --git a/chrome/browser/extensions/api/tab_groups/tab_groups_api_unittest.cc b/chrome/browser/extensions/api/tab_groups/tab_groups_api_unittest.cc
index b477b47e..bfd49dd 100644
--- a/chrome/browser/extensions/api/tab_groups/tab_groups_api_unittest.cc
+++ b/chrome/browser/extensions/api/tab_groups/tab_groups_api_unittest.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/ui_features.h"
@@ -38,6 +37,7 @@
 #include "components/tab_groups/tab_group_color.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/test/web_contents_tester.h"
 #include "extensions/browser/api_test_utils.h"
@@ -217,22 +217,20 @@
   TabStripModel* tab_strip_model = browser()->tab_strip_model();
   ASSERT_TRUE(tab_strip_model->SupportsTabGroups());
 
-  TabGroupModel* tab_group_model = tab_strip_model->group_model();
-
   // Create 3 groups with different titles.
   const tab_groups::TabGroupColorId color = tab_groups::TabGroupColorId::kGrey;
 
   tab_groups::TabGroupId group1 = tab_strip_model->AddToNewGroup({0});
   tab_groups::TabGroupVisualData visual_data1(u"Sample title", color);
-  tab_group_model->GetTabGroup(group1)->SetVisualData(visual_data1);
+  tab_strip_model->ChangeTabGroupVisuals(group1, visual_data1);
 
   tab_groups::TabGroupId group2 = tab_strip_model->AddToNewGroup({1});
   tab_groups::TabGroupVisualData visual_data2(u"Sample title suffixed", color);
-  tab_group_model->GetTabGroup(group2)->SetVisualData(visual_data2);
+  tab_strip_model->ChangeTabGroupVisuals(group2, visual_data2);
 
   tab_groups::TabGroupId group3 = tab_strip_model->AddToNewGroup({2});
   tab_groups::TabGroupVisualData visual_data3(u"Prefixed Sample title", color);
-  tab_group_model->GetTabGroup(group3)->SetVisualData(visual_data3);
+  tab_strip_model->ChangeTabGroupVisuals(group3, visual_data3);
 
   // Query by title and verify results.
   const char* kTitleQueryInfo = R"([{"title": "Sample title"}])";
@@ -253,23 +251,21 @@
   TabStripModel* tab_strip_model = browser()->tab_strip_model();
   ASSERT_TRUE(tab_strip_model->SupportsTabGroups());
 
-  TabGroupModel* tab_group_model = tab_strip_model->group_model();
-
   // Create 3 groups with different colors.
   tab_groups::TabGroupId group1 = tab_strip_model->AddToNewGroup({0});
   tab_groups::TabGroupVisualData visual_data1(
       std::u16string(), tab_groups::TabGroupColorId::kGrey);
-  tab_group_model->GetTabGroup(group1)->SetVisualData(visual_data1);
+  tab_strip_model->ChangeTabGroupVisuals(group1, visual_data1);
 
   tab_groups::TabGroupId group2 = tab_strip_model->AddToNewGroup({1});
   tab_groups::TabGroupVisualData visual_data2(
       std::u16string(), tab_groups::TabGroupColorId::kRed);
-  tab_group_model->GetTabGroup(group2)->SetVisualData(visual_data2);
+  tab_strip_model->ChangeTabGroupVisuals(group2, visual_data2);
 
   tab_groups::TabGroupId group3 = tab_strip_model->AddToNewGroup({2});
   tab_groups::TabGroupVisualData visual_data3(
       std::u16string(), tab_groups::TabGroupColorId::kBlue);
-  tab_group_model->GetTabGroup(group3)->SetVisualData(visual_data3);
+  tab_strip_model->ChangeTabGroupVisuals(group3, visual_data3);
 
   // Query by color and verify results.
   const char* kColorQueryInfo = R"([{"color": "blue"}])";
@@ -326,13 +322,11 @@
   TabStripModel* tab_strip_model = browser()->tab_strip_model();
   ASSERT_TRUE(tab_strip_model->SupportsTabGroups());
 
-  TabGroupModel* tab_group_model = tab_strip_model->group_model();
-
   // Create a group that is unshared.
   tab_groups::TabGroupId group1 = tab_strip_model->AddToNewGroup({0});
   tab_groups::TabGroupVisualData visual_data1(
       std::u16string(), tab_groups::TabGroupColorId::kGrey);
-  tab_group_model->GetTabGroup(group1)->SetVisualData(visual_data1);
+  tab_strip_model->ChangeTabGroupVisuals(group1, visual_data1);
 
   const char* not_shared_query = R"([{"shared": false}])";
   const char* shared_query = R"([{"shared": true}])";
@@ -386,13 +380,11 @@
   TabStripModel* tab_strip_model = browser()->tab_strip_model();
   ASSERT_TRUE(tab_strip_model->SupportsTabGroups());
 
-  TabGroupModel* tab_group_model = tab_strip_model->group_model();
-
   // Create a group.
   tab_groups::TabGroupId group = tab_strip_model->AddToNewGroup({0, 1, 2});
   tab_groups::TabGroupVisualData visual_data(
       u"Title", tab_groups::TabGroupColorId::kBlue);
-  tab_group_model->GetTabGroup(group)->SetVisualData(visual_data);
+  tab_strip_model->ChangeTabGroupVisuals(group, visual_data);
   int group_id = ExtensionTabUtil::GetGroupId(group);
 
   // Use the TabGroupsGetFunction to get the group object.
@@ -431,7 +423,7 @@
   tab_groups::TabGroupId group = tab_strip_model->AddToNewGroup({0, 1, 2});
   tab_groups::TabGroupVisualData visual_data(
       u"Initial title", tab_groups::TabGroupColorId::kBlue);
-  tab_group_model->GetTabGroup(group)->SetVisualData(visual_data);
+  tab_strip_model->ChangeTabGroupVisuals(group, visual_data);
   int group_id = ExtensionTabUtil::GetGroupId(group);
 
   // Use the TabGroupsUpdateFunction to update the title and color.
@@ -476,7 +468,7 @@
   tab_groups::TabGroupId group = tab_strip_model->AddToNewGroup({0, 1, 2});
   tab_groups::TabGroupVisualData visual_data(
       u"Initial title", tab_groups::TabGroupColorId::kBlue);
-  tab_group_model->GetTabGroup(group)->SetVisualData(visual_data);
+  tab_strip_model->ChangeTabGroupVisuals(group, visual_data);
 
   tab_groups::TabGroupSyncService* saved_service =
       tab_groups::SavedTabGroupUtils::GetServiceForProfile(
@@ -787,8 +779,7 @@
 
   tab_groups::TabGroupVisualData visual_data(u"Title",
                                              tab_groups::TabGroupColorId::kRed);
-  tab_strip_model->group_model()->GetTabGroup(group)->SetVisualData(
-      visual_data);
+  tab_strip_model->ChangeTabGroupVisuals(group, visual_data);
 
   EXPECT_EQ(1u, event_observer.events().size());
   EXPECT_TRUE(base::Contains(event_observer.events(),
diff --git a/chrome/browser/extensions/api/tab_groups/tab_groups_event_router.cc b/chrome/browser/extensions/api/tab_groups/tab_groups_event_router.cc
index f93c09c5..d128349 100644
--- a/chrome/browser/extensions/api/tab_groups/tab_groups_event_router.cc
+++ b/chrome/browser/extensions/api/tab_groups/tab_groups_event_router.cc
@@ -12,12 +12,12 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "components/tab_groups/tab_group_color.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 
 namespace extensions {
 
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index 10af690fd..ad1f4b4 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -65,7 +65,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/recently_audible_helper.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -89,6 +88,7 @@
 #include "components/tab_groups/tab_group_visual_data.h"
 #include "components/tabs/public/split_tab_data.h"
 #include "components/tabs/public/split_tab_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "components/translate/core/browser/language_state.h"
 #include "components/translate/core/common/language_detection_details.h"
 #include "components/webapps/common/web_app_id.h"
diff --git a/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc b/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
index 4fc79ca..7b19f07 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/ui_features.h"
@@ -39,6 +38,7 @@
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tabs/public/split_tab_collection.h"
 #include "components/tabs/public/split_tab_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/public/test/web_contents_tester.h"
@@ -574,11 +574,7 @@
       {GetTabStripModel()->GetIndexOfWebContents(raw_contents)});
   tab_groups::TabGroupVisualData visual_data(
       u"Initial title", tab_groups::TabGroupColorId::kBlue);
-  browser()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(group)
-      ->SetVisualData(visual_data);
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(group, visual_data);
 
   EXPECT_TRUE(
       ExtensionTabUtil::TabIsInSavedTabGroup(raw_contents, GetTabStripModel()));
@@ -954,11 +950,7 @@
   tab_groups::TabGroupId group = GetTabStripModel()->AddToNewGroup({0, 1, 2});
   tab_groups::TabGroupVisualData visual_data(
       u"Initial title", tab_groups::TabGroupColorId::kBlue);
-  browser()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(group)
-      ->SetVisualData(visual_data);
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(group, visual_data);
 
   // Use the TabsUpdateFunction to navigate to chromium.org
   int tab_extension_id = sessions::SessionTabHelper::IdForTab(
@@ -1312,11 +1304,7 @@
   tab_groups::TabGroupId group = GetTabStripModel()->AddToNewGroup({0});
   tab_groups::TabGroupVisualData visual_data(
       u"Initial title", tab_groups::TabGroupColorId::kBlue);
-  browser()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(group)
-      ->SetVisualData(visual_data);
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(group, visual_data);
 
   auto function = base::MakeRefCounted<TabsUngroupFunction>();
   function->set_extension(extension);
@@ -1478,11 +1466,7 @@
       {GetTabStripModel()->GetIndexOfWebContents(web_contents)});
   tab_groups::TabGroupVisualData visual_data(
       u"Initial title", tab_groups::TabGroupColorId::kBlue);
-  browser()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(group)
-      ->SetVisualData(visual_data);
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(group, visual_data);
 
   {
     auto goback_function = base::MakeRefCounted<TabsGoBackFunction>();
@@ -1774,11 +1758,7 @@
       {GetTabStripModel()->GetIndexOfWebContents(web_contents)});
   tab_groups::TabGroupVisualData visual_data(
       u"Initial title", tab_groups::TabGroupColorId::kBlue);
-  browser()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(group)
-      ->SetVisualData(visual_data);
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(group, visual_data);
 
   // The tab discard function should fail.
   auto function = base::MakeRefCounted<TabsDiscardFunction>();
@@ -1851,11 +1831,7 @@
       {GetTabStripModel()->GetIndexOfWebContents(web_contents)});
   tab_groups::TabGroupVisualData visual_data(
       u"Initial title", tab_groups::TabGroupColorId::kBlue);
-  browser()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(group)
-      ->SetVisualData(visual_data);
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(group, visual_data);
 
   // The tab discard function should not fail.
   auto function = base::MakeRefCounted<TabsDiscardFunction>();
diff --git a/chrome/browser/extensions/api/tabs/tabs_event_router.cc b/chrome/browser/extensions/api/tabs/tabs_event_router.cc
index 9e924f09..c791f432 100644
--- a/chrome/browser/extensions/api/tabs/tabs_event_router.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_event_router.cc
@@ -26,13 +26,13 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/recently_audible_helper.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "components/favicon/content/content_favicon_driver.h"
 #include "components/performance_manager/public/decorators/page_live_state_decorator.h"
 #include "components/performance_manager/public/graph/page_node.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/favicon_status.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/privacy_sandbox/incognito/privacy_sandbox_incognito_tab_observer.cc b/chrome/browser/privacy_sandbox/incognito/privacy_sandbox_incognito_tab_observer.cc
index 495c9357..ef76deb 100644
--- a/chrome/browser/privacy_sandbox/incognito/privacy_sandbox_incognito_tab_observer.cc
+++ b/chrome/browser/privacy_sandbox/incognito/privacy_sandbox_incognito_tab_observer.cc
@@ -37,6 +37,13 @@
 }
 
 bool PrivacySandboxIncognitoTabObserver::IsNewTabPage(const GURL& url) {
+#if BUILDFLAG(IS_ANDROID)
+  // On Android, the new tab page has a different URL.
+  if (url == chrome::kChromeUINativeNewTabURL) {
+    return true;
+  }
+#endif
+
   return url == chrome::kChromeUINewTabPageURL ||
          url == chrome::kChromeUINewTabURL;
 }
diff --git a/chrome/browser/resources/ash/settings/os_privacy_page/privacy_hub_geolocation_subpage.ts b/chrome/browser/resources/ash/settings/os_privacy_page/privacy_hub_geolocation_subpage.ts
index 4790b5f..dfa5d9c5 100644
--- a/chrome/browser/resources/ash/settings/os_privacy_page/privacy_hub_geolocation_subpage.ts
+++ b/chrome/browser/resources/ash/settings/os_privacy_page/privacy_hub_geolocation_subpage.ts
@@ -13,6 +13,7 @@
 import 'chrome://resources/ash/common/cr_elements/icons.html.js';
 import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
 import '../controls/controlled_button.js';
+import '../os_settings_icons.html.js';
 
 import {PrefsMixin} from '/shared/settings/prefs/prefs_mixin.js';
 import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js';
diff --git a/chrome/browser/search_engine_choice/BUILD.gn b/chrome/browser/search_engine_choice/BUILD.gn
index 7e0adb42..2780d47 100644
--- a/chrome/browser/search_engine_choice/BUILD.gn
+++ b/chrome/browser/search_engine_choice/BUILD.gn
@@ -45,6 +45,7 @@
     "//chrome/browser/profiles",
     "//chrome/browser/regional_capabilities",
     "//chrome/browser/search_engines",
+    "//components/metrics_services_manager",
     "//components/regional_capabilities",
     "//components/regional_capabilities:country_access_reason",
     "//components/search_engines",
@@ -81,7 +82,10 @@
 
       defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
 
-      sources = [ "search_engine_choice_dialog_browsertest.cc" ]
+      sources = [
+        "search_engine_choice_dialog_browsertest.cc",
+        "search_engine_choice_service_browsertest.cc",
+      ]
 
       deps = [
         ":search_engine_choice",
@@ -103,6 +107,8 @@
         "//components/keep_alive_registry",
         "//components/keyed_service/content",
         "//components/keyed_service/core",
+        "//components/metrics:test_support",
+        "//components/metrics_services_manager",
         "//components/search_engines",
         "//components/search_engines:test_support",
         "//components/version_info",
diff --git a/chrome/browser/search_engine_choice/search_engine_choice_service_browsertest.cc b/chrome/browser/search_engine_choice/search_engine_choice_service_browsertest.cc
new file mode 100644
index 0000000..f83104a
--- /dev/null
+++ b/chrome/browser/search_engine_choice/search_engine_choice_service_browsertest.cc
@@ -0,0 +1,233 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/search_engines/search_engine_choice/search_engine_choice_service.h"
+
+#include "base/check_deref.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engine_choice/search_engine_choice_service_factory.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "components/metrics/cloned_install_detector.h"
+#include "components/metrics/metrics_pref_names.h"
+#include "components/metrics/test/scoped_metrics_id_provider.h"
+#include "components/metrics_services_manager/metrics_services_manager.h"
+#include "components/regional_capabilities/regional_capabilities_switches.h"
+#include "components/regional_capabilities/regional_capabilities_utils.h"
+#include "components/search_engines/search_engine_choice/search_engine_choice_utils.h"
+#include "components/search_engines/search_engines_switches.h"
+#include "components/search_engines/template_url_service.h"
+#include "content/public/test/browser_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using search_engines::GetChoiceCompletionMetadata;
+using search_engines::SearchEngineChoiceScreenConditions;
+using search_engines::SearchEngineChoiceService;
+using search_engines::SearchEngineChoiceServiceFactory;
+
+class SearchEngineChoiceServiceBrowserTest : public InProcessBrowserTest {
+ public:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    InProcessBrowserTest::SetUpCommandLine(command_line);
+
+    command_line->AppendSwitchASCII(switches::kSearchEngineChoiceCountry,
+                                    switches::kDefaultListCountryOverride);
+  }
+
+  SearchEngineChoiceScreenConditions GetStaticConditions(
+      Profile* profile,
+      bool is_regular_profile = true) {
+    SearchEngineChoiceService* search_engine_choice_service =
+        SearchEngineChoiceServiceFactory::GetForProfile(profile);
+    TemplateURLService* template_url_service =
+        TemplateURLServiceFactory::GetForProfile(profile);
+
+    return search_engine_choice_service->GetStaticChoiceScreenConditions(
+        CHECK_DEREF(g_browser_process->policy_service()), is_regular_profile,
+        *template_url_service);
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(SearchEngineChoiceServiceBrowserTest,
+                       StaticCondition_IsEligible) {
+  EXPECT_EQ(GetStaticConditions(browser()->profile()),
+            SearchEngineChoiceScreenConditions::kEligible);
+}
+
+enum class FeatureState {
+  kDisabled,
+  kEnabledJustInTime,
+  kEnabledRetroactive,
+};
+
+struct RestoreTestParam {
+  std::string test_name;
+  FeatureState feature_state;
+  SearchEngineChoiceScreenConditions run_1_expected_condition;
+  SearchEngineChoiceScreenConditions run_2_expected_condition;
+};
+
+class SearchEngineChoiceServiceRestoreBrowserTest
+    : public SearchEngineChoiceServiceBrowserTest,
+      public testing::WithParamInterface<RestoreTestParam> {
+ public:
+  void SetUp() override {
+    scoped_machine_id_provider_.machine_id =
+        GetTestPreCount() == 2 ? "pre_restore_id" : "post_restore_id";
+
+    switch (GetParam().feature_state) {
+      case FeatureState::kDisabled:
+        feature_list_.InitAndDisableFeature(
+            switches::kInvalidateSearchEngineChoiceOnDeviceRestoreDetection);
+        break;
+      case FeatureState::kEnabledJustInTime:
+        feature_list_.InitAndEnableFeature(
+            switches::kInvalidateSearchEngineChoiceOnDeviceRestoreDetection);
+        break;
+      case FeatureState::kEnabledRetroactive:
+        feature_list_.InitAndEnableFeatureWithParameters(
+            switches::kInvalidateSearchEngineChoiceOnDeviceRestoreDetection,
+            {{"is_retroactive", "true"}});
+        break;
+    }
+
+    SearchEngineChoiceServiceBrowserTest::SetUp();
+  }
+
+  metrics::ScopedMachineIdProvider scoped_machine_id_provider_;
+  base::test::ScopedFeatureList feature_list_;
+};
+
+const RestoreTestParam kTestParams[] = {
+    {.test_name = "FeatureDisabled",
+     .feature_state = FeatureState::kDisabled,
+     .run_1_expected_condition =
+         SearchEngineChoiceScreenConditions::kAlreadyCompleted,
+     .run_2_expected_condition =
+         SearchEngineChoiceScreenConditions::kAlreadyCompleted},
+    {.test_name = "FeatureEnabledJustInTime",
+     .feature_state = FeatureState::kEnabledJustInTime,
+     // Ideally `kEligible`, but technically infeasible on Desktop platforms.
+     // The clone detection happens on a low-priority background task, and it
+     // completes after we are done checking the choice screen eligibility
+     // status.
+     .run_1_expected_condition =
+         SearchEngineChoiceScreenConditions::kAlreadyCompleted,
+     // Since the choice was not invalidated in the session where the clone was
+     // detected, for the "JustInTime" mode, we don't wipe it later either.
+     .run_2_expected_condition =
+         SearchEngineChoiceScreenConditions::kAlreadyCompleted},
+    {.test_name = "FeatureEnabledRetroactive",
+     .feature_state = FeatureState::kEnabledRetroactive,
+     // Ideally `kEligible`, but just like the JustInTime version, we detect
+     // the clone too late. The invalidation will be deferred to the next
+     // session.
+     .run_1_expected_condition =
+         SearchEngineChoiceScreenConditions::kAlreadyCompleted,
+     .run_2_expected_condition = SearchEngineChoiceScreenConditions::kEligible},
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    ,
+    SearchEngineChoiceServiceRestoreBrowserTest,
+    testing::ValuesIn(kTestParams),
+    [](const ::testing::TestParamInfo<RestoreTestParam>& info) {
+      return info.param.test_name;
+    });
+
+IN_PROC_BROWSER_TEST_P(SearchEngineChoiceServiceRestoreBrowserTest,
+                       PRE_PRE_StaticConditions) {
+  Profile* profile = browser()->profile();
+  SearchEngineChoiceService* search_engine_choice_service =
+      SearchEngineChoiceServiceFactory::GetForProfile(profile);
+
+  ASSERT_FALSE(GetChoiceCompletionMetadata(*profile->GetPrefs()).has_value());
+  ASSERT_FALSE(search_engine_choice_service->GetClientForTesting()
+                   .IsDeviceRestoreDetectedInCurrentSession());
+
+  ASSERT_EQ(GetStaticConditions(profile),
+            SearchEngineChoiceScreenConditions::kEligible);
+
+  search_engine_choice_service->RecordChoiceMade(
+      search_engines::ChoiceMadeLocation::kChoiceScreen,
+      TemplateURLServiceFactory::GetForProfile(profile));
+
+  ASSERT_EQ(GetStaticConditions(profile),
+            SearchEngineChoiceScreenConditions::kAlreadyCompleted);
+}
+
+IN_PROC_BROWSER_TEST_P(SearchEngineChoiceServiceRestoreBrowserTest,
+                       PRE_StaticConditions) {
+  auto* detector = g_browser_process->GetMetricsServicesManager()
+                       ->GetClonedInstallDetectorForTesting();
+  metrics::ClonedInstallInfo cloned_install_info =
+      metrics::ClonedInstallDetector::ReadClonedInstallInfo(
+          g_browser_process->local_state());
+
+  // The current session has the detection but not the ID reset.
+  ASSERT_TRUE(detector->ClonedInstallDetectedInCurrentSession());
+  EXPECT_EQ(cloned_install_info.reset_count, 0);
+
+  Profile* profile = browser()->profile();
+  SearchEngineChoiceService* search_engine_choice_service =
+      SearchEngineChoiceServiceFactory::GetForProfile(profile);
+
+  // The choice has not been wiped, but we know that it predates restore.
+  auto choice_completion_metata =
+      GetChoiceCompletionMetadata(*profile->GetPrefs());
+  EXPECT_TRUE(choice_completion_metata.has_value());
+  EXPECT_TRUE(
+      search_engine_choice_service->GetClientForTesting()
+          .DoesChoicePredateDeviceRestore(choice_completion_metata.value()));
+
+  EXPECT_EQ(GetStaticConditions(profile), GetParam().run_1_expected_condition);
+}
+
+IN_PROC_BROWSER_TEST_P(SearchEngineChoiceServiceRestoreBrowserTest,
+                       StaticConditions) {
+  auto* detector = g_browser_process->GetMetricsServicesManager()
+                       ->GetClonedInstallDetectorForTesting();
+  metrics::ClonedInstallInfo cloned_install_info =
+      metrics::ClonedInstallDetector::ReadClonedInstallInfo(
+          g_browser_process->local_state());
+
+  // The clone was detected in the previous session, but we reset the ID
+  // starting in this one.
+  ASSERT_FALSE(detector->ClonedInstallDetectedInCurrentSession());
+  ASSERT_EQ(cloned_install_info.reset_count, 1);
+
+  Profile* profile = browser()->profile();
+  SearchEngineChoiceService* search_engine_choice_service =
+      SearchEngineChoiceServiceFactory::GetForProfile(profile);
+
+  auto choice_completion_metata =
+      GetChoiceCompletionMetadata(*profile->GetPrefs());
+  if (GetParam().run_2_expected_condition ==
+      search_engines::SearchEngineChoiceScreenConditions::kAlreadyCompleted) {
+    // The choice has not been wiped, but we know that it predates restore.
+    EXPECT_TRUE(choice_completion_metata.has_value());
+    EXPECT_TRUE(
+        search_engine_choice_service->GetClientForTesting()
+            .DoesChoicePredateDeviceRestore(choice_completion_metata.value()));
+  } else {
+    // The choice should have been wiped when the service is created.
+    EXPECT_FALSE(choice_completion_metata.has_value());
+  }
+
+  // This is the second run after restore, it didn't happen in the current
+  // session.
+  EXPECT_FALSE(search_engine_choice_service->GetClientForTesting()
+                   .IsDeviceRestoreDetectedInCurrentSession());
+
+  EXPECT_EQ(GetStaticConditions(browser()->profile()),
+            GetParam().run_2_expected_condition);
+}
+
+}  // namespace
diff --git a/chrome/browser/search_engine_choice/search_engine_choice_service_client.cc b/chrome/browser/search_engine_choice/search_engine_choice_service_client.cc
index c8a0cf7..3eb9f97 100644
--- a/chrome/browser/search_engine_choice/search_engine_choice_service_client.cc
+++ b/chrome/browser/search_engine_choice/search_engine_choice_service_client.cc
@@ -4,8 +4,11 @@
 
 #include "chrome/browser/search_engine_choice/search_engine_choice_service_client.h"
 
+#include "base/check_is_test.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
+#include "components/metrics/cloned_install_detector.h"
+#include "components/metrics_services_manager/metrics_services_manager.h"
 #include "components/variations/service/variations_service.h"
 
 #if BUILDFLAG(IS_CHROMEOS)
@@ -39,12 +42,40 @@
 
 bool SearchEngineChoiceServiceClient::
     IsDeviceRestoreDetectedInCurrentSession() {
-  return false;
+  const metrics::ClonedInstallDetector* cloned_install_detector =
+      g_browser_process->GetMetricsServicesManager()
+          ? &g_browser_process->GetMetricsServicesManager()
+                 ->GetClonedInstallDetector()
+          : nullptr;
+  if (!cloned_install_detector) {
+    CHECK_IS_TEST();
+    return false;
+  }
+
+  return cloned_install_detector->ClonedInstallDetectedInCurrentSession();
 }
 
 bool SearchEngineChoiceServiceClient::DoesChoicePredateDeviceRestore(
     const ChoiceCompletionMetadata& choice_metadata) {
-  return false;
+  PrefService* local_state = g_browser_process->local_state();
+  if (!local_state) {
+    CHECK_IS_TEST();
+    return false;
+  }
+
+  metrics::ClonedInstallInfo cloned =
+      metrics::ClonedInstallDetector::ReadClonedInstallInfo(local_state);
+  if (!cloned.last_detection_timestamp) {
+    // When a user opts out of UMA, the metrics system clears the pref tracking
+    // when the clone detection happened. In this case we can't track the clone
+    // status and we then can't use it to invalidate DSE choices.
+    // If that has been used in the first session after the one that detected
+    // the clone, the search engine choice invalidation would have been done
+    // already, and the absence of this timestamp is not an issue.
+    return false;
+  }
+
+  return choice_metadata.timestamp.ToTimeT() < cloned.last_detection_timestamp;
 }
 
 }  // namespace search_engines
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc
index c6acd9c..93277b0b 100644
--- a/chrome/browser/sessions/session_restore.cc
+++ b/chrome/browser/sessions/session_restore.cc
@@ -64,7 +64,6 @@
 #include "chrome/browser/ui/startup/startup_tab.h"
 #include "chrome/browser/ui/startup/startup_types.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_user_gesture_details.h"
@@ -81,6 +80,7 @@
 #include "components/saved_tab_groups/public/types.h"
 #include "components/sessions/core/session_types.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "content/public/browser/dom_storage_context.h"
 #include "content/public/browser/navigation_controller.h"
@@ -1016,10 +1016,10 @@
       const tab_groups::TabGroupId& new_tab_group_id =
           new_group_ids.at(session_tab_group->id);
       if (session_tab_group->saved_guid) {
-        // We add this mapping to ensure the call to TabGroup::SetVisualData
-        // results in writing the saved guid to disk. This ensures we do not
-        // duplicate saved tab groups if there is a crash prior to or during
-        // model initialization.
+        // We add this mapping to ensure the call to
+        // TabStripModel::ChangeTabGroupVisuals results in writing the saved
+        // guid to disk. This ensures we do not duplicate saved tab groups if
+        // there is a crash prior to or during model initialization.
         session_service->AddSavedTabGroupsMapping(
             new_tab_group_id, session_tab_group->saved_guid.value());
       }
@@ -1028,7 +1028,8 @@
           browser->tab_strip_model()->group_model()->GetTabGroup(
               new_tab_group_id);
       CHECK(model_tab_group);
-      model_tab_group->SetVisualData(session_tab_group->visual_data);
+      browser->tab_strip_model()->ChangeTabGroupVisuals(
+          new_tab_group_id, session_tab_group->visual_data);
 
       ProcessSavedGroup(browser->profile(), new_tab_group_id,
                         session_tab_group->saved_guid);
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc
index 32bab5c5..315a9cd3 100644
--- a/chrome/browser/sessions/session_restore_browsertest.cc
+++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -71,7 +71,6 @@
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/ui_features.h"
@@ -111,6 +110,7 @@
 #include "components/tab_groups/tab_group_color.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_frame_host.h"
@@ -1137,7 +1137,7 @@
       *tsm->group_model()->GetTabGroup(group1)->visual_data();
   const tab_groups::TabGroupVisualData group2_data(
       u"Foo", tab_groups::TabGroupColorId::kBlue, true);
-  tsm->group_model()->GetTabGroup(group2)->SetVisualData(group2_data);
+  tsm->ChangeTabGroupVisuals(group2, group2_data);
 
   Browser* const new_browser = QuitBrowserAndRestore(browser());
   TabStripModel* const new_tsm = new_browser->tab_strip_model();
@@ -3003,12 +3003,9 @@
 
   // This ensures SessionService knows about the savedtabgroup. It shouldn't be
   // necessary.
-  browser()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(tab_group_id)
-      ->SetVisualData(tab_groups::TabGroupVisualData(
-          u"x", tab_groups::TabGroupColorId::kGrey));
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(
+      tab_group_id,
+      tab_groups::TabGroupVisualData(u"x", tab_groups::TabGroupColorId::kGrey));
 
   QuitBrowserAndRestore(
       browser(), GURL(), true, base::BindLambdaForTesting([&]() {
@@ -4604,21 +4601,17 @@
   EXPECT_EQ(2u, service->GetAllGroups().size());
 
   // Update the visual data of the new groups.
-  browser()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(group1)
-      ->SetVisualData(tab_groups::TabGroupVisualData(
-                          u"Group1", tab_groups::TabGroupColorId::kGrey),
-                      true);
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(
+      group1,
+      tab_groups::TabGroupVisualData(u"Group1",
+                                     tab_groups::TabGroupColorId::kGrey),
+      true);
 
-  browser()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(group2)
-      ->SetVisualData(tab_groups::TabGroupVisualData(
-                          u"Group2", tab_groups::TabGroupColorId::kBlue),
-                      true);
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(
+      group2,
+      tab_groups::TabGroupVisualData(u"Group2",
+                                     tab_groups::TabGroupColorId::kBlue),
+      true);
 
   // Close the browser and restore the last session
   Browser* restored = QuitBrowserAndRestore(browser());
diff --git a/chrome/browser/sessions/session_service_base.cc b/chrome/browser/sessions/session_service_base.cc
index d0e2032d..c731871 100644
--- a/chrome/browser/sessions/session_service_base.cc
+++ b/chrome/browser/sessions/session_service_base.cc
@@ -27,7 +27,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "components/sessions/content/content_serialized_navigation_builder.h"
@@ -37,6 +36,7 @@
 #include "components/sessions/core/session_constants.h"
 #include "components/sessions/core/session_id.h"
 #include "components/sessions/core/session_types.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/session_storage_namespace.h"
diff --git a/chrome/browser/sessions/tab_restore_browsertest.cc b/chrome/browser/sessions/tab_restore_browsertest.cc
index 322ce36..e576fac 100644
--- a/chrome/browser/sessions/tab_restore_browsertest.cc
+++ b/chrome/browser/sessions/tab_restore_browsertest.cc
@@ -37,7 +37,6 @@
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/tab_group_action_context_desktop.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/ui_features.h"
@@ -63,6 +62,7 @@
 #include "components/tab_groups/tab_group_color.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/render_view_host.h"
@@ -1384,13 +1384,10 @@
   // Add the tab to a group.
   tab_groups::TabGroupId group =
       browser()->tab_strip_model()->AddToNewGroup({0});
-  browser()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(group)
-      ->SetVisualData(tab_groups::TabGroupVisualData(
-          u"Group title", tab_groups::TabGroupColorId::kGreen,
-          /*is_collapsed=*/false));
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(
+      group, tab_groups::TabGroupVisualData(u"Group title",
+                                            tab_groups::TabGroupColorId::kGreen,
+                                            /*is_collapsed=*/false));
 }
 
 IN_PROC_BROWSER_TEST_F(TabRestoreTest, WindowMappingHasGroupDataAfterRestart) {
@@ -1601,7 +1598,7 @@
   TabGroup* group =
       browser()->tab_strip_model()->group_model()->GetTabGroup(group_id);
 
-  group->SetVisualData(visual_data);
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(group_id, visual_data);
   CloseTab(grouped_tab_index);
 
   ASSERT_NO_FATAL_FAILURE(RestoreTab(0, grouped_tab_index));
@@ -1635,7 +1632,7 @@
   TabGroup* group =
       browser()->tab_strip_model()->group_model()->GetTabGroup(group_id);
   ASSERT_TRUE(group);
-  group->SetVisualData(visual_data);
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(group_id, visual_data);
 
   CloseTab(grouped_tab_index);
 
@@ -1671,9 +1668,7 @@
       browser()->tab_strip_model()->AddToNewGroup({0, 1});
   const tab_groups::TabGroupVisualData visual_data(
       u"Foo", tab_groups::TabGroupColorId::kCyan, true);
-  TabGroup* group =
-      browser()->tab_strip_model()->group_model()->GetTabGroup(group_id);
-  group->SetVisualData(visual_data);
+  browser()->GetTabStripModel()->ChangeTabGroupVisuals(group_id, visual_data);
 
   CloseTab(closed_tab_index);
 
@@ -1714,9 +1709,11 @@
   TabGroup* group =
       browser()->tab_strip_model()->group_model()->GetTabGroup(group_id);
 
-  group->SetVisualData(visual_data_1);
+  browser()->GetTabStripModel()->ChangeTabGroupVisuals(group->id(),
+                                                       visual_data_1);
   CloseTab(closed_tab_index);
-  group->SetVisualData(visual_data_2);
+  browser()->GetTabStripModel()->ChangeTabGroupVisuals(group->id(),
+                                                       visual_data_2);
 
   ASSERT_NO_FATAL_FAILURE(RestoreTab(0, closed_tab_index));
   ASSERT_EQ(tab_count, browser()->tab_strip_model()->count());
@@ -1772,18 +1769,17 @@
   AddHTTPSSchemeTabs(browser(), 3);
   constexpr int tab_count = 4;
 
-  TabGroupModel* group_model = browser()->tab_strip_model()->group_model();
   tab_groups::TabGroupId group1 = browser()->tab_strip_model()->AddToNewGroup(
       {tab_count - 3, tab_count - 2});
   tab_groups::TabGroupVisualData group1_data(u"Foo",
                                              tab_groups::TabGroupColorId::kRed);
-  group_model->GetTabGroup(group1)->SetVisualData(group1_data);
+  browser()->GetTabStripModel()->ChangeTabGroupVisuals(group1, group1_data);
 
   tab_groups::TabGroupId group2 =
       browser()->tab_strip_model()->AddToNewGroup({tab_count - 1});
   tab_groups::TabGroupVisualData group2_data(
       u"Bar", tab_groups::TabGroupColorId::kBlue);
-  group_model->GetTabGroup(group2)->SetVisualData(group2_data);
+  browser()->GetTabStripModel()->ChangeTabGroupVisuals(group2, group2_data);
 
   CloseBrowserSynchronously(browser());
   ASSERT_EQ(1u, active_browser_list_->size());
@@ -2525,7 +2521,7 @@
   tab_groups::TabGroupColorId original_color =
       tab_groups::TabGroupColorId::kRed;
   tab_groups::TabGroupVisualData og_visual_data(original_title, original_color);
-  tab_group->SetVisualData(og_visual_data);
+  browser()->GetTabStripModel()->ChangeTabGroupVisuals(group, og_visual_data);
 
   std::optional<tab_groups::SavedTabGroup> saved_group =
       service->GetGroup(group);
@@ -2586,7 +2582,7 @@
   tab_groups::TabGroupColorId original_color =
       tab_groups::TabGroupColorId::kRed;
   tab_groups::TabGroupVisualData og_visual_data(original_title, original_color);
-  tab_group->SetVisualData(og_visual_data);
+  browser()->GetTabStripModel()->ChangeTabGroupVisuals(group, og_visual_data);
 
   const std::optional<tab_groups::SavedTabGroup> saved_group =
       service->GetGroup(group);
@@ -3083,11 +3079,8 @@
   // Set the visual data here.
   tab_groups::TabGroupVisualData original_visual_data(
       u"Title", tab_groups::TabGroupColorId::kYellow);
-  browser()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(group)
-      ->SetVisualData(original_visual_data, true);
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(
+      group, original_visual_data, true);
 
   ASSERT_TRUE(service->GetGroup(group));
   base::Uuid saved_group_id = service->GetGroup(group)->saved_guid();
@@ -3230,7 +3223,8 @@
   TabGroup* group =
       browser()->tab_strip_model()->group_model()->GetTabGroup(group_id);
   ASSERT_TRUE(group);
-  group->SetVisualData(visual_data);
+  browser()->GetTabStripModel()->ChangeTabGroupVisuals(group->id(),
+                                                       visual_data);
 
   CloseTab(grouped_tab_index);
 
diff --git a/chrome/browser/supervised_user/kids_profile_interactive_uitest.cc b/chrome/browser/supervised_user/kids_profile_interactive_uitest.cc
index f0a7b71..223480e3 100644
--- a/chrome/browser/supervised_user/kids_profile_interactive_uitest.cc
+++ b/chrome/browser/supervised_user/kids_profile_interactive_uitest.cc
@@ -9,6 +9,7 @@
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tab_ui_helper.h"
 #include "chrome/test/interaction/interactive_browser_test.h"
 #include "chrome/test/supervised_user/browser_user.h"
 #include "chrome/test/supervised_user/family_live_test.h"
@@ -45,7 +46,11 @@
                                             std::string_view iframe_name) {
   content::WebContents* web_contents = nullptr;
   for (int i = 0; i < browser.GetTabStripModel()->GetTabCount(); ++i) {
-    if (browser.GetTabStripModel()->GetTitleAt(i) == tab_title) {
+    std::u16string wc_title =
+        TabUIHelper::FromWebContents(
+            browser.GetTabStripModel()->GetWebContentsAt(i))
+            ->GetTitle();
+    if (wc_title == tab_title) {
       web_contents = browser.GetTabStripModel()->GetWebContentsAt(i);
       break;
     }
diff --git a/chrome/browser/sync/test/integration/sync_test_tab_utils.cc b/chrome/browser/sync/test/integration/sync_test_tab_utils.cc
index 1b94db0..d1773b7 100644
--- a/chrome/browser/sync/test/integration/sync_test_tab_utils.cc
+++ b/chrome/browser/sync/test/integration/sync_test_tab_utils.cc
@@ -20,9 +20,9 @@
 #else
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "components/tabs/public/tab_group.h"
 #endif  // BUILDFLAG(IS_ANDROID)
 
 using sync_datatype_helper::test;
@@ -125,7 +125,8 @@
   TabGroup* model_tab_group =
       tab_strip->group_model()->GetTabGroup(local_group_id);
   CHECK(model_tab_group);
-  model_tab_group->SetVisualData(
+  tab_strip->ChangeTabGroupVisuals(
+      local_group_id,
       tab_groups::TabGroupVisualData(base::UTF8ToUTF16(title), color),
       /*is_customized=*/true);
 #endif  // BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/touch_to_fill/common/android/java/src/org/chromium/chrome/browser/touch_to_fill/common/TouchToFillResourceProvider.java b/chrome/browser/touch_to_fill/common/android/java/src/org/chromium/chrome/browser/touch_to_fill/common/TouchToFillResourceProvider.java
index 3b908d369..59039e4f 100644
--- a/chrome/browser/touch_to_fill/common/android/java/src/org/chromium/chrome/browser/touch_to_fill/common/TouchToFillResourceProvider.java
+++ b/chrome/browser/touch_to_fill/common/android/java/src/org/chromium/chrome/browser/touch_to_fill/common/TouchToFillResourceProvider.java
@@ -30,7 +30,6 @@
      *
      * @return A {@link DrawableRes} that is never 0.
      */
-    default @DrawableRes int getLoyaltyCardHeaderDrawableId() {
-        return 0;
-    }
+    @DrawableRes
+    int getLoyaltyCardHeaderDrawableId();
 }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/back_button/BackButtonCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/back_button/BackButtonCoordinator.java
index 27deb56..ffda712d 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/back_button/BackButtonCoordinator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/back_button/BackButtonCoordinator.java
@@ -32,6 +32,7 @@
     private final BackButtonMediator mMediator;
     private final NavigationPopup.HistoryDelegate mHistoryDelegate;
     private final Supplier<@Nullable Tab> mTabSupplier;
+    private final Runnable mOnNavigationPopupShown;
     private final View mView;
 
     /**
@@ -52,10 +53,12 @@
             ThemeColorProvider themeColorProvider,
             ObservableSupplier<@Nullable Tab> tabSupplier,
             ObservableSupplier<Boolean> enabledSupplier,
+            Runnable onNavigationPopupShown,
             NavigationPopup.HistoryDelegate historyDelegate) {
         mView = view;
         mTabSupplier = tabSupplier;
         mHistoryDelegate = historyDelegate;
+        mOnNavigationPopupShown = onNavigationPopupShown;
 
         final ColorStateList iconColorList =
                 themeColorProvider.getActivityFocusTint() == null
@@ -92,6 +95,7 @@
                         mTabSupplier,
                         mHistoryDelegate);
         popup.show(mView);
+        mOnNavigationPopupShown.run();
     }
 
     /**
diff --git a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayout.java b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayout.java
index 0cd97cfa..8b763b8d 100644
--- a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayout.java
+++ b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayout.java
@@ -18,6 +18,7 @@
 public class WebAppHeaderLayout extends FrameLayout implements View.OnLayoutChangeListener {
 
     private @Nullable Callback<Integer> mOnWidthChanged;
+    private @Nullable Callback<Integer> mOnVisibilityChangedCallback;
 
     public WebAppHeaderLayout(Context context) {
         super(context);
@@ -60,6 +61,24 @@
         }
     }
 
+    /**
+     * Callback that will be notified about visibility changes
+     *
+     * @param onVisibilityChangedCallback a {@link Callback} that accepts new visibility.
+     */
+    public void setOnVisibilityChangedCallback(
+            @Nullable Callback<Integer> onVisibilityChangedCallback) {
+        mOnVisibilityChangedCallback = onVisibilityChangedCallback;
+    }
+
+    @Override
+    protected void onVisibilityChanged(View changedView, int visibility) {
+        // Make sure changedView == this, as any child view can trigger onvisibilityChanged.
+        if (changedView == this && mOnVisibilityChangedCallback != null) {
+            mOnVisibilityChangedCallback.onResult(visibility);
+        }
+    }
+
     /** Cleans up this view. */
     public void destroy() {
         removeOnLayoutChangeListener(this);
diff --git a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutCoordinator.java b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutCoordinator.java
index 5d626ae..ac94f84 100644
--- a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutCoordinator.java
+++ b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutCoordinator.java
@@ -156,7 +156,9 @@
         mReloadButtonCoordinator =
                 new ReloadButtonCoordinator(
                         reloadButton,
-                        this::refreshTab,
+                        (ignoreCache) -> {
+                            if (mMediator != null) mMediator.refreshTab(ignoreCache);
+                        },
                         mTabSupplier,
                         new ObservableSupplierImpl<>(),
                         mControlsEnabledSupplier,
@@ -172,6 +174,9 @@
                         mThemeColorProvider,
                         mTabSupplier,
                         mControlsEnabledSupplier,
+                        () -> {
+                            if (mMediator != null) mMediator.onNavigationPopupShown();
+                        },
                         mHistoryDelegate);
 
         mMediator.setOnButtonBottomInsetChanged(this::onButtonBottomInsetChanged);
@@ -220,21 +225,6 @@
         }
     }
 
-    // TODO(vkorotkevich): Move to the Mediator
-    @VisibleForTesting
-    void refreshTab(boolean ignoreCache) {
-        final var tab = mTabSupplier.get();
-        if (tab == null) return;
-
-        if (tab.isLoading()) {
-            tab.stopLoading();
-        } else if (ignoreCache) {
-            tab.reloadIgnoringCache();
-        } else {
-            tab.reload();
-        }
-    }
-
     @Override
     public int disableControlsAndClearOldToken(int token) {
         int newToken = mDisabledControlsHolder.acquireToken();
diff --git a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutCoordinatorTest.java b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutCoordinatorTest.java
index e46c204..d3b9e41 100644
--- a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutCoordinatorTest.java
+++ b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutCoordinatorTest.java
@@ -343,39 +343,6 @@
     }
 
     @Test
-    public void testReload_shouldReloadTab() {
-        setupDesktopWindowing(/* isInDesktopWindow= */ true);
-        setupDisplayMode(DisplayMode.MINIMAL_UI);
-        setupTab(/* isLoading= */ false, /* canGoBack= */ false);
-        createCoordinator();
-
-        mCoordinator.refreshTab(false);
-        verify(mTab).reload();
-    }
-
-    @Test
-    public void testReloadWhileReloading_shouldStopReloading() {
-        setupDesktopWindowing(/* isInDesktopWindow= */ true);
-        setupDisplayMode(DisplayMode.MINIMAL_UI);
-        setupTab(/* isLoading= */ true, /* canGoBack= */ false);
-        createCoordinator();
-
-        mCoordinator.refreshTab(false);
-        verify(mTab).stopLoading();
-    }
-
-    @Test
-    public void testReloadTabIgnoringCache_shouldReloadIgnoringCache() {
-        setupDesktopWindowing(/* isInDesktopWindow= */ true);
-        setupDisplayMode(DisplayMode.MINIMAL_UI);
-        setupTab(/* isLoading= */ false, /* canGoBack= */ false);
-        createCoordinator();
-
-        mCoordinator.refreshTab(true);
-        verify(mTab).reloadIgnoringCache();
-    }
-
-    @Test
     public void testDisableControls() {
         setupDesktopWindowing(/* isInDesktopWindow= */ true);
         setupDisplayMode(DisplayMode.MINIMAL_UI);
diff --git a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutMediator.java b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutMediator.java
index 6d7264508..3c7d6e2b 100644
--- a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutMediator.java
+++ b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutMediator.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.ui.web_app_header;
 
 import android.graphics.Rect;
+import android.view.View;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -17,6 +18,8 @@
 import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.theme.ThemeColorProvider;
+import org.chromium.chrome.browser.ui.web_app_header.WebAppHeaderUtils.BackEvent;
+import org.chromium.chrome.browser.ui.web_app_header.WebAppHeaderUtils.ReloadType;
 import org.chromium.components.browser_ui.desktop_windowing.AppHeaderState;
 import org.chromium.components.browser_ui.desktop_windowing.DesktopWindowStateManager;
 import org.chromium.components.browser_ui.widget.scrim.ScrimManager;
@@ -104,6 +107,9 @@
         mModel = model;
         // View should notify us about initial width.
         mModel.set(WebAppHeaderLayoutProperties.WIDTH_CHANGED_CALLBACK, this::onLayoutWidthUpdated);
+        mModel.set(
+                WebAppHeaderLayoutProperties.VISIBILITY_CHANGED_CALLBACK,
+                this::onVisibilityChanged);
 
         final var appHeaderState = desktopWindowStateManager.getAppHeaderState();
         if (appHeaderState != null) {
@@ -122,6 +128,13 @@
         updateNonDraggableAreas();
     }
 
+    private void onVisibilityChanged(int visibility) {
+        // If the web app header view is GONE, we should update the width to reflect this.
+        if (visibility == View.GONE) {
+            mWidthSupplier.set(0);
+        }
+    }
+
     @Override
     public void onThemeColorChanged(int color, boolean shouldAnimate) {
         mDesktopWindowStateManager.updateForegroundColor(color);
@@ -209,6 +222,38 @@
         final var tab = mTabSupplier.get();
         if (tab != null && tab.canGoBack()) {
             tab.goBack();
+            WebAppHeaderUtils.recordBackButtonEvent(BackEvent.BACK);
+        } else {
+            WebAppHeaderUtils.recordBackButtonEvent(BackEvent.INVALID);
+        }
+    }
+
+    /** Records histograms when navigation pop up is shown by long pressing back button */
+    public void onNavigationPopupShown() {
+        WebAppHeaderUtils.recordBackButtonEvent(BackEvent.NAVIGATION_MENU);
+    }
+
+    /**
+     * Reloads current visible tab or stops reloading.
+     *
+     * @param ignoreCache whether to force reload current tab.
+     */
+    public void refreshTab(boolean ignoreCache) {
+        final var tab = mTabSupplier.get();
+        if (tab == null) {
+            WebAppHeaderUtils.recordReloadButtonEvent(ReloadType.INVALID);
+            return;
+        }
+
+        if (tab.isLoading()) {
+            tab.stopLoading();
+            WebAppHeaderUtils.recordReloadButtonEvent(ReloadType.STOP_RELOAD);
+        } else if (ignoreCache) {
+            tab.reloadIgnoringCache();
+            WebAppHeaderUtils.recordReloadButtonEvent(ReloadType.RELOAD_IGNORE_CACHE);
+        } else {
+            tab.reload();
+            WebAppHeaderUtils.recordReloadButtonEvent(ReloadType.RELOAD_FROM_CACHE);
         }
     }
 
@@ -217,6 +262,10 @@
         return mWebAppMinHeaderHeight;
     }
 
+    public ObservableSupplierImpl<Integer> getWidthSupplierForTesting() {
+        return mWidthSupplier;
+    }
+
     static void setMinHeightForTesting(final int height) {
         sMinHeaderHeightForTesting = height;
         ResettersForTesting.register(() -> sMinHeaderHeightForTesting = null);
diff --git a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutMediatorTest.java b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutMediatorTest.java
index e41e0fe..1ab7f3b1 100644
--- a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutMediatorTest.java
+++ b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutMediatorTest.java
@@ -16,6 +16,7 @@
 import android.graphics.Rect;
 import android.os.Build;
 import android.os.Looper;
+import android.view.View;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -30,9 +31,12 @@
 
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.HistogramWatcher;
 import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.theme.ThemeColorProvider;
+import org.chromium.chrome.browser.ui.web_app_header.WebAppHeaderUtils.BackEvent;
+import org.chromium.chrome.browser.ui.web_app_header.WebAppHeaderUtils.ReloadType;
 import org.chromium.components.browser_ui.desktop_windowing.AppHeaderState;
 import org.chromium.components.browser_ui.desktop_windowing.DesktopWindowStateManager;
 import org.chromium.components.browser_ui.widget.scrim.ScrimManager;
@@ -258,6 +262,51 @@
     }
 
     @Test
+    public void testHeaderInitiallyHidden_WidthSupplierUpdatesOnVisibilityChange() {
+        setupDesktopWindowing(/* isInDesktopWindow= */ true, WIDEST_UNOCCLUDED_RECT);
+
+        mMediator =
+                new WebAppHeaderLayoutMediator(
+                        mModel,
+                        mHeaderDelegate,
+                        mDesktopWindowStateManager,
+                        mScrimManager,
+                        mTabSupplier,
+                        mNonDraggableAreasSupplier,
+                        mThemeColorProvider,
+                        SYS_APP_HEADER_HEIGHT,
+                        HEADER_BUTTON_HEIGHT);
+        mShadowLooper.idle();
+
+        mModel.get(WebAppHeaderLayoutProperties.WIDTH_CHANGED_CALLBACK).onResult(SCREEN_WIDTH);
+
+        // View starts off visible.
+        assertTrue(
+                "IS_VISIBLE property should be true.",
+                mModel.get(WebAppHeaderLayoutProperties.IS_VISIBLE));
+        assertEquals(
+                "Width supplier should report SCREEN_WIDTH.",
+                Integer.valueOf(SCREEN_WIDTH),
+                mMediator.getWidthSupplierForTesting().get());
+
+        // Change the app header state to have a View.GONE app header view.
+        AppHeaderState goneState =
+                new AppHeaderState(
+                        WIDEST_UNOCCLUDED_RECT,
+                        WIDEST_UNOCCLUDED_RECT,
+                        /* isInDesktopWindow= */ false);
+        mMediator.onAppHeaderStateChanged(goneState);
+        mModel.get(WebAppHeaderLayoutProperties.VISIBILITY_CHANGED_CALLBACK).onResult(View.GONE);
+        assertFalse(
+                "IS_VISIBLE property should be false.",
+                mModel.get(WebAppHeaderLayoutProperties.IS_VISIBLE));
+        assertEquals(
+                "Width supplier should be zero.",
+                Integer.valueOf(0),
+                mMediator.getWidthSupplierForTesting().get());
+    }
+
+    @Test
     public void testAppHeaderHeightIsLessThanMin_noTopPaddingsSet() {
         setupDesktopWindowing(/* isInDesktopWindow= */ true, WIDEST_UNOCCLUDED_RECT);
 
@@ -294,26 +343,78 @@
 
     @Test
     public void testGoBackWithHistory_shouldGoBack() {
+        var watcher =
+                HistogramWatcher.newSingleRecordWatcher(
+                        "CustomTabs.WebAppHeader.BackButtonEvent", BackEvent.BACK);
         mTabSupplier.set(mTab);
         when(mTab.canGoBack()).thenReturn(true);
 
         mMediator.goBack();
         verify(mTab).goBack();
+        watcher.assertExpected("Back event should be recorded.");
     }
 
     @Test
     public void testGoBackNoHistory_shouldNotGoBack() {
+        var watcher =
+                HistogramWatcher.newSingleRecordWatcher(
+                        "CustomTabs.WebAppHeader.BackButtonEvent", BackEvent.INVALID);
         mTabSupplier.set(mTab);
         when(mTab.canGoBack()).thenReturn(false);
 
         mMediator.goBack();
         verify(mTab, never()).goBack();
+        watcher.assertExpected("Invalid event should be recorded.");
     }
 
     @Test
     public void testGoBackNoTab_shouldNotGoBack() {
+        var watcher =
+                HistogramWatcher.newSingleRecordWatcher(
+                        "CustomTabs.WebAppHeader.BackButtonEvent", BackEvent.INVALID);
         mMediator.goBack();
         verify(mTab, never()).goBack();
+        watcher.assertExpected("Invalid event should be recorded.");
+    }
+
+    @Test
+    public void testReload_shouldReloadTab() {
+        var watcher =
+                HistogramWatcher.newSingleRecordWatcher(
+                        "CustomTabs.WebAppHeader.ReloadButtonEvent", ReloadType.RELOAD_FROM_CACHE);
+        when(mTab.isLoading()).thenReturn(false);
+        mTabSupplier.set(mTab);
+
+        mMediator.refreshTab(false);
+        verify(mTab).reload();
+        watcher.assertExpected("Reload from cache should be recorded.");
+    }
+
+    @Test
+    public void testReloadWhileReloading_shouldStopReloading() {
+        var watcher =
+                HistogramWatcher.newSingleRecordWatcher(
+                        "CustomTabs.WebAppHeader.ReloadButtonEvent", ReloadType.STOP_RELOAD);
+        when(mTab.isLoading()).thenReturn(true);
+        mTabSupplier.set(mTab);
+
+        mMediator.refreshTab(false);
+        verify(mTab).stopLoading();
+        watcher.assertExpected("Stop reloading should be recorded.");
+    }
+
+    @Test
+    public void testReloadTabIgnoringCache_shouldReloadIgnoringCache() {
+        var watcher =
+                HistogramWatcher.newSingleRecordWatcher(
+                        "CustomTabs.WebAppHeader.ReloadButtonEvent",
+                        ReloadType.RELOAD_IGNORE_CACHE);
+        when(mTab.isLoading()).thenReturn(false);
+        mTabSupplier.set(mTab);
+
+        mMediator.refreshTab(true);
+        verify(mTab).reloadIgnoringCache();
+        watcher.assertExpected("Reload ignoring cache should be recorded.");
     }
 
     @Test
diff --git a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutProperties.java b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutProperties.java
index 9a5be76..79c7992 100644
--- a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutProperties.java
+++ b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutProperties.java
@@ -35,6 +35,9 @@
     static final WritableObjectPropertyKey<Callback<Integer>> WIDTH_CHANGED_CALLBACK =
             new WritableObjectPropertyKey<>();
 
+    static final WritableObjectPropertyKey<Callback<Integer>> VISIBILITY_CHANGED_CALLBACK =
+            new WritableObjectPropertyKey<>();
+
     /** Background color of the header */
     static final WritableIntPropertyKey BACKGROUND_COLOR = new WritableIntPropertyKey();
 
@@ -47,6 +50,7 @@
                 NON_DRAGGABLE_AREAS,
                 WIDTH_CHANGED_CALLBACK,
                 BACKGROUND_COLOR,
+                VISIBILITY_CHANGED_CALLBACK,
             };
 
     private WebAppHeaderLayoutProperties() {}
diff --git a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutViewBinder.java b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutViewBinder.java
index e06ee2e..43ae11f 100644
--- a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutViewBinder.java
+++ b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutViewBinder.java
@@ -44,6 +44,9 @@
             view.setOnWidthChanged(model.get(WebAppHeaderLayoutProperties.WIDTH_CHANGED_CALLBACK));
         } else if (key == WebAppHeaderLayoutProperties.BACKGROUND_COLOR) {
             view.setBackgroundColor(model.get(WebAppHeaderLayoutProperties.BACKGROUND_COLOR));
+        } else if (key == WebAppHeaderLayoutProperties.VISIBILITY_CHANGED_CALLBACK) {
+            view.setOnVisibilityChangedCallback(
+                    model.get(WebAppHeaderLayoutProperties.VISIBILITY_CHANGED_CALLBACK));
         } else {
             assert false : String.format("Unsupported property key %s", key.toString());
         }
diff --git a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderUtils.java b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderUtils.java
index 77d58b79..4cf52c1 100644
--- a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderUtils.java
+++ b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderUtils.java
@@ -7,8 +7,10 @@
 import android.os.Build;
 
 import androidx.annotation.ChecksSdkIntAtLeast;
+import androidx.annotation.IntDef;
 import androidx.annotation.LayoutRes;
 
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.blink.mojom.DisplayMode;
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
@@ -17,9 +19,76 @@
 import org.chromium.chrome.browser.web_app_header.R;
 import org.chromium.components.browser_ui.desktop_windowing.DesktopWindowStateManager;
 
-/** Provides predicate utilities related to webapp header. */
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Provides predicate and histogram utilities related to webapp header. */
 @NullMarked
 public class WebAppHeaderUtils {
+
+    @IntDef({
+        ReloadType.INVALID,
+        ReloadType.STOP_RELOAD,
+        ReloadType.RELOAD_FROM_CACHE,
+        ReloadType.RELOAD_IGNORE_CACHE,
+        ReloadType.MAX_VALUE
+    })
+    @Target(ElementType.TYPE_USE)
+    @Retention(RetentionPolicy.SOURCE)
+    @interface ReloadType {
+        /**
+         * Indicates reload attempt when tab is null, e.g. navigating to tab switcher or during tab
+         * re-parenting.
+         */
+        int INVALID = 0;
+
+        /** Indicates stop reloading attempt on currently visible tab. */
+        int STOP_RELOAD = 1;
+
+        /**
+         * Indicates reload attempt from cache (left click or touch without meta keys) on currently
+         * visible tab.
+         */
+        int RELOAD_FROM_CACHE = 2;
+
+        /**
+         * Indicated reload attempt ignoring cache (left click with meta key) on currently visible
+         * tab
+         */
+        int RELOAD_IGNORE_CACHE = 3;
+
+        /**
+         * Maximum number of enum entries. This value should be updated when new entries are added.
+         * Do not decrement!
+         */
+        int MAX_VALUE = RELOAD_IGNORE_CACHE;
+    }
+
+    @IntDef({BackEvent.INVALID, BackEvent.BACK, BackEvent.NAVIGATION_MENU, BackEvent.MAX_VALUE})
+    @Target(ElementType.TYPE_USE)
+    @Retention(RetentionPolicy.SOURCE)
+    @interface BackEvent {
+        /**
+         * Indicates back press attempt when tab is null, e.g. navigating to tab switcher or during
+         * tab re-parenting.
+         */
+        int INVALID = 0;
+
+        /** Indicates single back press attempt on current active tab. */
+        int BACK = 1;
+
+        /** Indicated long back press that opens a navigation pop up on current active tab. */
+        int NAVIGATION_MENU = 2;
+
+        /**
+         * Maximum number of enum entries. This value should be updated when new entries are added.
+         * Do not decrement!
+         */
+        int MAX_VALUE = NAVIGATION_MENU;
+    }
+
     private WebAppHeaderUtils() {}
 
     /**
@@ -51,6 +120,15 @@
     }
 
     /**
+     * Provides layout id of the webapp header.
+     *
+     * @return webapp header layout resource id.
+     */
+    public static @LayoutRes int getWebAppHeaderLayoutId() {
+        return R.layout.web_app_main_layout;
+    }
+
+    /**
      * Checks whether minimal ui is visible based on the desktop window state and feature flag
      * state.
      *
@@ -66,11 +144,22 @@
     }
 
     /**
-     * Provides layout id of the webapp header.
+     * Records reload button events.
      *
-     * @return webapp header layout resource id.
+     * @param type event {@link ReloadType}.
      */
-    public static @LayoutRes int getWebAppHeaderLayoutId() {
-        return R.layout.web_app_main_layout;
+    static void recordReloadButtonEvent(@ReloadType int type) {
+        RecordHistogram.recordEnumeratedHistogram(
+                "CustomTabs.WebAppHeader.ReloadButtonEvent", type, ReloadType.MAX_VALUE);
+    }
+
+    /**
+     * Records back button events.
+     *
+     * @param type {@link BackEvent} type.
+     */
+    static void recordBackButtonEvent(@BackEvent int type) {
+        RecordHistogram.recordEnumeratedHistogram(
+                "CustomTabs.WebAppHeader.BackButtonEvent", type, ReloadType.MAX_VALUE);
     }
 }
diff --git a/chrome/browser/ui/ash/desks/chrome_desks_util.cc b/chrome/browser/ui/ash/desks/chrome_desks_util.cc
index 6eec804..902167f 100644
--- a/chrome/browser/ui/ash/desks/chrome_desks_util.cc
+++ b/chrome/browser/ui/ash/desks/chrome_desks_util.cc
@@ -4,11 +4,11 @@
 
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_info.h"
 #include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 
 namespace {
 
@@ -51,9 +51,7 @@
   for (const tab_groups::TabGroupInfo& tab_group : tab_groups) {
     tab_groups::TabGroupId new_group_id = tab_strip_model->AddToNewGroup(
         ConvertRangeToTabGroupIndices(tab_group.tab_range));
-    tab_strip_model->group_model()
-        ->GetTabGroup(new_group_id)
-        ->SetVisualData(tab_group.visual_data);
+    tab_strip_model->ChangeTabGroupVisuals(new_group_id, tab_group.visual_data);
   }
 }
 
diff --git a/chrome/browser/ui/bookmarks/bookmark_utils_desktop.cc b/chrome/browser/ui/bookmarks/bookmark_utils_desktop.cc
index bde58b88..bcb27b4 100644
--- a/chrome/browser/ui/bookmarks/bookmark_utils_desktop.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_utils_desktop.cc
@@ -27,7 +27,6 @@
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/simple_message_box.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/grit/branded_strings.h"
 #include "chrome/grit/generated_resources.h"
@@ -36,6 +35,7 @@
 #include "components/bookmarks/browser/bookmark_utils.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tabs/public/split_tab_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/web_contents.h"
@@ -327,7 +327,7 @@
           tab_groups::TabGroupVisualData new_visual_data(
               folder_title.value(), current_visual_data->color(),
               current_visual_data->is_collapsed());
-          group->SetVisualData(new_visual_data);
+          model->ChangeTabGroupVisuals(group->id(), new_visual_data);
 
           model->OpenTabGroupEditor(new_group_id.value());
         }
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 875c7a3..38850be 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -135,7 +135,6 @@
 #include "chrome/browser/ui/tab_modal_confirm_dialog.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_deletion_dialog_controller.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_menu_model.h"
@@ -201,6 +200,7 @@
 #include "components/tabs/public/split_tab_data.h"
 #include "components/tabs/public/split_tab_id.h"
 #include "components/tabs/public/split_tab_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "components/tabs/public/tab_interface.h"
 #include "components/user_manager/user_manager.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 6e5347d..e22d342 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -97,7 +97,6 @@
 #include "chrome/browser/ui/tabs/organization/tab_organization_session.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_user_gesture_details.h"
 #include "chrome/browser/ui/ui_features.h"
@@ -157,6 +156,7 @@
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
 #include "components/tabs/public/split_tab_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "components/tabs/public/tab_interface.h"
 #include "components/translate/core/browser/language_state.h"
 #include "components/translate/core/browser/translate_manager.h"
@@ -1375,13 +1375,13 @@
     std::optional<tab_groups::TabGroupId> new_group_id =
         tab_strip_model->GetTabGroupForTab(new_index);
     if (new_group_id && new_group_id != current_group_id) {
-      std::optional<int> first_tab_of_group =
+      tabs::TabInterface* first_tab_of_group =
           tab_strip_model->group_model()
               ->GetTabGroup(new_group_id.value())
               ->GetFirstTab();
       CHECK(first_tab_of_group);
       tab_strip_model->ActivateTabAt(
-          first_tab_of_group.value(),
+          tab_strip_model->GetIndexOfTab(first_tab_of_group),
           TabStripUserGestureDetails(
               TabStripUserGestureDetails::GestureType::kKeyboard));
       return;
diff --git a/chrome/browser/ui/browser_commands_browsertest.cc b/chrome/browser/ui/browser_commands_browsertest.cc
index 904d155..94e1e60 100644
--- a/chrome/browser/ui/browser_commands_browsertest.cc
+++ b/chrome/browser/ui/browser_commands_browsertest.cc
@@ -268,12 +268,9 @@
   std::vector<int> indices = {1, 2};
   tab_groups::TabGroupId group_id =
       browser()->tab_strip_model()->AddToNewGroup(indices);
-  browser()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(group_id)
-      ->SetVisualData(tab_groups::TabGroupVisualData(
-          u"Test Group", tab_groups::TabGroupColorId::kGrey));
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(
+      group_id, tab_groups::TabGroupVisualData(
+                    u"Test Group", tab_groups::TabGroupColorId::kGrey));
   ui_test_utils::BrowserChangeObserver new_browser_observer(
       nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
 
diff --git a/chrome/browser/ui/browser_live_tab_context.cc b/chrome/browser/ui/browser_live_tab_context.cc
index 7663ab9..ce187e6 100644
--- a/chrome/browser/ui/browser_live_tab_context.cc
+++ b/chrome/browser/ui/browser_live_tab_context.cc
@@ -28,7 +28,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/tab_group_action_context_desktop.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/ui_features.h"
@@ -44,6 +43,7 @@
 #include "components/sessions/core/tab_restore_service.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/session_storage_namespace.h"
 #include "content/public/browser/web_contents.h"
@@ -174,9 +174,8 @@
   CHECK(tab_strip_model);
   TabGroupModel* group_model = tab_strip_model->group_model();
   CHECK(group_model);
-  TabGroup* tab_group = group_model->GetTabGroup(group);
-  CHECK(tab_group);
-  tab_group->SetVisualData(std::move(visual_data));
+  CHECK(group_model->ContainsTabGroup(group));
+  tab_strip_model->ChangeTabGroupVisuals(group, std::move(visual_data));
 }
 
 const gfx::Rect BrowserLiveTabContext::GetRestoredBounds() const {
diff --git a/chrome/browser/ui/browser_tab_strip_model_delegate.cc b/chrome/browser/ui/browser_tab_strip_model_delegate.cc
index 24ccc51f..4d0074e 100644
--- a/chrome/browser/ui/browser_tab_strip_model_delegate.cc
+++ b/chrome/browser/ui/browser_tab_strip_model_delegate.cc
@@ -27,7 +27,6 @@
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_deletion_dialog_controller.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_menu_model_delegate.h"
@@ -46,6 +45,7 @@
 #include "components/sessions/core/tab_restore_service.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tabs/public/split_tab_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
diff --git a/chrome/browser/ui/browser_tabrestore.cc b/chrome/browser/ui/browser_tabrestore.cc
index 5b33e170..a1ca3719 100644
--- a/chrome/browser/ui/browser_tabrestore.cc
+++ b/chrome/browser/ui/browser_tabrestore.cc
@@ -19,11 +19,11 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tab_ui_helper.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "components/sessions/content/content_serialized_navigation_builder.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/restore_type.h"
diff --git a/chrome/browser/ui/hats/survey_config.cc b/chrome/browser/ui/hats/survey_config.cc
index 4ff70d06..970d883 100644
--- a/chrome/browser/ui/hats/survey_config.cc
+++ b/chrome/browser/ui/hats/survey_config.cc
@@ -233,7 +233,6 @@
       /*log_responses_to_uma=*/true,
       /*log_responses_to_ukm=*/true);
 
-#if !BUILDFLAG(IS_ANDROID)
   // Privacy sandbox ACT survey
   survey_configs.emplace_back(  //
       &privacy_sandbox::kPrivacySandboxActSurvey,
@@ -248,6 +247,7 @@
       /*requested_browser_type=*/
       hats::SurveyConfig::RequestedBrowserType::kIncognito);
 
+#if !BUILDFLAG(IS_ANDROID)
   // Dev tools surveys.
   survey_configs.emplace_back(&features::kHaTSDesktopDevToolsIssuesCOEP,
                               "devtools-issues-coep",
diff --git a/chrome/browser/ui/tabs/BUILD.gn b/chrome/browser/ui/tabs/BUILD.gn
index 5024f5ec..ef350c55 100644
--- a/chrome/browser/ui/tabs/BUILD.gn
+++ b/chrome/browser/ui/tabs/BUILD.gn
@@ -73,11 +73,8 @@
 
   source_set("tab_group") {
     sources = [
-      "tab_group.h",
-      "tab_group_controller.h",
       "tab_group_deletion_dialog_controller.h",
       "tab_group_model.h",
-      "tab_group_tab_collection.h",
       "tab_group_theme.h",
     ]
 
@@ -94,10 +91,8 @@
     public_deps = [ "//chrome/browser:browser_public_dependencies" ]
 
     sources = [
-      "tab_group.cc",
       "tab_group_deletion_dialog_controller.cc",
       "tab_group_model.cc",
-      "tab_group_tab_collection.cc",
       "tab_group_theme.cc",
     ]
 
@@ -188,7 +183,6 @@
 
   source_set("tab_strip") {
     sources = [
-      "tab_strip_collection.h",
       "tab_strip_model.h",
       "tab_strip_model_delegate.h",
       "tab_strip_model_stats_recorder.h",
@@ -213,7 +207,6 @@
     public_deps = [ "//chrome/browser:browser_public_dependencies" ]
 
     sources = [
-      "tab_strip_collection.cc",
       "tab_strip_model.cc",
       "tab_strip_model_delegate.cc",
       "tab_strip_model_stats_recorder.cc",
@@ -263,7 +256,6 @@
       "tab_style.h",
       "tab_types.h",
       "tab_utils.h",
-      "unpinned_tab_collection.h",
     ]
 
     if (is_win || is_mac || is_linux || is_chromeos) {
@@ -316,7 +308,6 @@
       "tab_renderer_data.cc",
       "tab_style.cc",
       "tab_utils.cc",
-      "unpinned_tab_collection.cc",
     ]
 
     if (is_win || is_mac || is_linux || is_chromeos) {
diff --git a/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.cc b/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.cc
index 49b4be1e..4e61f6b1 100644
--- a/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.cc
+++ b/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.cc
@@ -13,7 +13,7 @@
 #include "base/notreached.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
+#include "chrome/browser/ui/tab_ui_helper.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_group_theme.h"
 #include "chrome/browser/ui/tabs/tab_menu_model_delegate.h"
@@ -23,9 +23,11 @@
 #include "components/tab_groups/tab_group_color.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "components/tabs/public/tab_interface.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/accelerators/menu_label_accelerator_util.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/image_model.h"
 #include "ui/base/models/list_selection_model.h"
 #include "ui/color/color_provider.h"
@@ -33,9 +35,24 @@
 #include "ui/gfx/image/canvas_image_source.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/paint_vector_icon.h"
+#include "ui/gfx/text_elider.h"
 
 namespace {
 constexpr int kIconSize = 14;
+
+// TODO(crbug.com/418774949) Move to TabGroupFeatures for desktop.
+std::u16string GetContentString(const TabGroup& group) {
+  constexpr size_t kContextMenuTabTitleMaxLength = 30;
+  std::u16string format_string = l10n_util::GetPluralStringFUTF16(
+      IDS_TAB_CXMENU_PLACEHOLDER_GROUP_TITLE, group.tab_count() - 1);
+  std::u16string short_title;
+  gfx::ElideString(
+      TabUIHelper::FromWebContents(group.GetFirstTab()->GetContents())
+          ->GetTitle(),
+      kContextMenuTabTitleMaxLength, &short_title);
+  return base::ReplaceStringPlaceholders(format_string, short_title, nullptr);
+}
+
 }  // anonymous namespace
 
 ExistingTabGroupSubMenuModel::ExistingTabGroupSubMenuModel(
@@ -128,7 +145,7 @@
     // TODO(dljames): Add method to tab_group.cc to return displayed_title.
     // TODO(dljames): Add unit tests for all of tab_group.h
     const std::u16string displayed_title =
-        group_title.empty() ? tab_group->GetContentString() : group_title;
+        group_title.empty() ? GetContentString(*tab_group) : group_title;
     const int color_id =
         GetTabGroupContextMenuColorId(tab_group->visual_data()->color());
     const ui::ColorProvider& color_provider =
diff --git a/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model_browsertest.cc b/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model_browsertest.cc
index 49bb11b0..ea12903 100644
--- a/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model_browsertest.cc
+++ b/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model_browsertest.cc
@@ -10,11 +10,11 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_tab_menu_model_delegate.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/test/browser_test.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/ui/tabs/organization/tab_organization.cc b/chrome/browser/ui/tabs/organization/tab_organization.cc
index 4e6199e..6b65757 100644
--- a/chrome/browser/ui/tabs/organization/tab_organization.cc
+++ b/chrome/browser/ui/tabs/organization/tab_organization.cc
@@ -11,10 +11,10 @@
 
 #include "base/debug/dump_without_crashing.h"
 #include "chrome/browser/ui/tabs/organization/tab_data.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "components/tabs/public/tab_interface.h"
 
 namespace {
@@ -222,8 +222,8 @@
       tab_strip_model->group_model()->GetTabGroup(group_id_.value());
   tab_groups::TabGroupVisualData new_visual_data(
       GetDisplayName(), tab_group->visual_data()->color());
-  tab_group->SetVisualData(std::move(new_visual_data),
-                           tab_group->IsCustomized());
+  tab_strip_model->ChangeTabGroupVisuals(tab_group->id(), new_visual_data,
+                                         tab_group->IsCustomized());
 
   // If |this| has been destroyed, there is no need to notify the observers:
   // in practice, the only observer is the TabOrganizationSession which owns
diff --git a/chrome/browser/ui/tabs/organization/tab_organization_session.cc b/chrome/browser/ui/tabs/organization/tab_organization_session.cc
index 57412efd..bc6ebc0 100644
--- a/chrome/browser/ui/tabs/organization/tab_organization_session.cc
+++ b/chrome/browser/ui/tabs/organization/tab_organization_session.cc
@@ -13,9 +13,9 @@
 #include "chrome/browser/ui/tabs/organization/tab_data.h"
 #include "chrome/browser/ui/tabs/organization/tab_organization.h"
 #include "chrome/browser/ui/tabs/organization/tab_organization_request.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/web_contents.h"
 
 namespace {
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_observer.cc b/chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_observer.cc
index 625e60b6..9f666f4f 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_observer.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_observer.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_metrics.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/tab_group_action_context_desktop.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/data_sharing/collaboration_controller_delegate_desktop.h"
@@ -27,6 +26,7 @@
 #include "components/collaboration/public/collaboration_service.h"
 #include "components/saved_tab_groups/public/tab_group_sync_service.h"
 #include "components/saved_tab_groups/public/types.h"
+#include "components/tabs/public/tab_group.h"
 
 using collaboration::messaging::MessagingBackendServiceFactory;
 
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/instant_message_queue_processor.cc b/chrome/browser/ui/tabs/saved_tab_groups/instant_message_queue_processor.cc
index 086dc39..93da70f 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/instant_message_queue_processor.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/instant_message_queue_processor.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_tab_data.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/toasts/api/toast_id.h"
@@ -29,6 +28,7 @@
 #include "components/image_fetcher/core/image_fetcher_service.h"
 #include "components/saved_tab_groups/public/tab_group_sync_service.h"
 #include "components/signin/public/base/avatar_icon_util.h"
+#include "components/tabs/public/tab_group.h"
 
 namespace tab_groups {
 namespace {
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/local_tab_group_listener.cc b/chrome/browser/ui/tabs/saved_tab_groups/local_tab_group_listener.cc
index 7452f77..052d6f8 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/local_tab_group_listener.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/local_tab_group_listener.cc
@@ -16,12 +16,13 @@
 #include "chrome/browser/ui/tabs/saved_tab_groups/most_recent_shared_tab_update_store.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_web_contents_listener.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "components/saved_tab_groups/public/features.h"
 #include "components/saved_tab_groups/public/saved_tab_group_tab.h"
 #include "components/saved_tab_groups/public/utils.h"
+#include "components/tabs/public/tab_group.h"
 #include "components/tabs/public/tab_interface.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
@@ -105,13 +106,16 @@
   CHECK(service_->GetGroup(saved_guid_).has_value());
   CHECK(tab_strip_model->group_model()->ContainsTabGroup(local_id_));
 
-  const std::optional<int> tabstrip_index_of_first_tab_in_group =
+  tabs::TabInterface* first_tab_in_group =
       tab_strip_model->group_model()->GetTabGroup(local_id_)->GetFirstTab();
-  CHECK(tabstrip_index_of_first_tab_in_group.has_value());
+  CHECK(first_tab_in_group);
+  int tabstrip_index_of_first_tab_in_group =
+      tab_strip_model->GetIndexOfTab(first_tab_in_group);
+  CHECK_NE(tabstrip_index_of_first_tab_in_group, TabStripModel::kNoTab);
 
   const int relative_index_of_tab_in_group =
       tab_strip_model->GetIndexOfTab(local_tab) -
-      tabstrip_index_of_first_tab_in_group.value();
+      tabstrip_index_of_first_tab_in_group;
 
   LocalTabID local_tab_id = local_tab->GetHandle().raw_value();
 
@@ -168,16 +172,19 @@
   // at index 2. For the tab group, C is at index 0.
   // Moving C to index 4 in the tabstrip means it will now have an index of 2 in
   // the tab group and SavedTabGroupModel.
-  const std::optional<int> tabstrip_index_of_first_tab_in_group =
+  tabs::TabInterface* first_tab_in_group =
       tab_strip_model->group_model()->GetTabGroup(local_id_)->GetFirstTab();
-  CHECK(tabstrip_index_of_first_tab_in_group.has_value());
+  CHECK(first_tab_in_group);
+  int tabstrip_index_of_first_tab_in_group =
+      tab_strip_model->GetIndexOfTab(first_tab_in_group);
+  CHECK_NE(tabstrip_index_of_first_tab_in_group, TabStripModel::kNoTab);
 
   // Count the number of tabs that are actually in the group between
   // `tabstrip_index_of_first_tab_in_group` and `tabstrip_index_of_moved_tab`.
   // We must do this because a tab group may not be contiguous in intermediate
   // states such as when dragging a group by its header.
   int index_in_group = 0;
-  for (int i = tabstrip_index_of_first_tab_in_group.value();
+  for (int i = tabstrip_index_of_first_tab_in_group;
        i < tabstrip_index_of_moved_tab; i++) {
     if (tab_strip_model->GetTabGroupForTab(i) == local_id_) {
       index_in_group++;
@@ -268,7 +275,8 @@
       tab_strip_model->group_model()->GetTabGroup(local_id_);
   CHECK(local_tab_group);
   const bool is_collapsed = local_tab_group->visual_data()->is_collapsed();
-  local_tab_group->SetVisualData(
+  tab_strip_model->ChangeTabGroupVisuals(
+      local_id_,
       tab_groups::TabGroupVisualData(saved_group->title(), saved_group->color(),
                                      is_collapsed),
       /*is_customized=*/true);
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc
index feebf72..80bb1f6 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc
@@ -31,7 +31,6 @@
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_pref_names.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_service_proxy.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/common/channel_info.h"
 #include "components/data_sharing/public/features.h"
@@ -59,6 +58,7 @@
 #include "components/sync_device_info/device_info_tracker.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "components/tabs/public/tab_interface.h"
 #include "content/public/browser/web_contents.h"
 
@@ -335,9 +335,10 @@
       tab_strip_model_for_creation->group_model()->GetTabGroup(tab_group_id);
 
   // Activate the first tab in the tab group.
-  std::optional<int> first_tab = tab_group->GetFirstTab();
-  DCHECK(first_tab.has_value());
-  tab_strip_model_for_creation->ActivateTabAt(first_tab.value());
+  tabs::TabInterface* first_tab = tab_group->GetFirstTab();
+  DCHECK(first_tab);
+  tab_strip_model_for_creation->ActivateTabAt(
+      tab_strip_model_for_creation->GetIndexOfTab(first_tab));
 
   // Set the group's visual data after the tab strip is in its final state. This
   // ensures the tab group's bounds are correctly set. crbug/1408814.
@@ -608,8 +609,9 @@
 
   // Remove tabs from the end of the tab group to even out the number of tabs in
   // the local and saved group.
-  while (tab_group->tab_count() > int(num_tabs_in_saved_group)) {
-    const int last_tab = tab_group->GetLastTab().value();
+  while (tab_group->tab_count() > static_cast<int>(num_tabs_in_saved_group)) {
+    const int last_tab =
+        tab_strip_model->GetIndexOfTab(tab_group->GetLastTab());
     tab_strip_model->CloseWebContentsAt(
         last_tab, TabCloseTypes::CLOSE_CREATE_HISTORICAL_TAB);
   }
@@ -699,6 +701,9 @@
 void SavedTabGroupKeyedService::UpdateGroupVisualData(
     const base::Uuid saved_group_guid,
     const TabGroupId group_id) {
+  const Browser* const browser =
+      SavedTabGroupUtils::GetBrowserWithTabGroupId(group_id);
+  CHECK(browser);
   TabGroup* const tab_group = SavedTabGroupUtils::GetTabGroupWithId(group_id);
   CHECK(tab_group);
   const SavedTabGroup* const saved_group = model_->Get(saved_group_guid);
@@ -708,7 +713,7 @@
   TabGroupVisualData visual_data(
       saved_group->title(), saved_group->color(),
       /*is_collapsed=*/tab_group->visual_data()->is_collapsed());
-  tab_group->SetVisualData(visual_data, /*is_customized=*/true);
+  browser->tab_strip_model()->ChangeTabGroupVisuals(group_id, visual_data);
 }
 
 bool SavedTabGroupKeyedService::IsRemoteDevice(
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service_unittest.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service_unittest.cc
index 5344b37..40a160a 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service_unittest.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service_unittest.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_web_contents_listener.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_service_proxy.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -29,6 +28,7 @@
 #include "components/tab_groups/tab_group_color.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "components/tabs/public/tab_interface.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.cc
index b67279f..fb30492 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.cc
@@ -13,13 +13,13 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/local_tab_group_listener.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "components/saved_tab_groups/internal/saved_tab_group_model.h"
 #include "components/saved_tab_groups/public/features.h"
 #include "components/saved_tab_groups/public/tab_group_sync_service.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "components/tabs/public/tab_interface.h"
 
 namespace content {
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.cc
index dba0cc0..5b1dbf9 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.cc
@@ -58,6 +58,7 @@
 #include "components/sync/service/sync_user_settings.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "content/public/browser/web_contents.h"
+#include "ui/gfx/range/range.h"
 #include "url/gurl.h"
 
 namespace tab_groups {
@@ -568,21 +569,20 @@
       browser_for_activation->tab_strip_model()->group_model()->GetTabGroup(
           local_group_id);
 
-  std::optional<int> first_tab = tab_group->GetFirstTab();
-  std::optional<int> last_tab = tab_group->GetLastTab();
+  gfx::Range tab_group_index_range = tab_group->ListTabs();
+  CHECK(!tab_group_index_range.is_empty());
+
   int active_index = browser_for_activation->tab_strip_model()->active_index();
-  CHECK(first_tab.has_value());
-  CHECK(last_tab.has_value());
   CHECK_GE(active_index, 0);
 
-  if (active_index >= first_tab.value() && active_index <= last_tab) {
+  if (active_index >= static_cast<int>(tab_group_index_range.GetMin()) &&
+      active_index < static_cast<int>(tab_group_index_range.GetMax())) {
     browser_for_activation->window()->Activate();
     return;
   }
 
   browser_for_activation->ActivateContents(
-      browser_for_activation->tab_strip_model()->GetWebContentsAt(
-          first_tab.value()));
+      tab_group->GetFirstTab()->GetContents());
 
   base::RecordAction(
       base::UserMetricsAction("TabGroups_SavedTabGroups_Focused"));
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h
index 6048765..dd395a5 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h
+++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h
@@ -9,12 +9,12 @@
 
 #include "base/uuid.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_deletion_dialog_controller.h"
 #include "chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view.h"
 #include "components/data_sharing/public/group_data.h"
 #include "components/saved_tab_groups/public/saved_tab_group.h"
 #include "components/saved_tab_groups/public/types.h"
+#include "components/tabs/public/tab_group.h"
 #include "ui/base/interaction/element_tracker.h"
 #include "ui/base/window_open_disposition.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/session_service_tab_group_sync_observer.cc b/chrome/browser/ui/tabs/saved_tab_groups/session_service_tab_group_sync_observer.cc
index 8a2b56b..1b830bb 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/session_service_tab_group_sync_observer.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/session_service_tab_group_sync_observer.cc
@@ -10,13 +10,13 @@
 #include "chrome/browser/sessions/session_service.h"
 #include "chrome/browser/sessions/session_service_factory.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "components/saved_tab_groups/public/saved_tab_group.h"
 #include "components/saved_tab_groups/public/tab_group_sync_service.h"
 #include "components/saved_tab_groups/public/types.h"
 #include "components/sessions/core/session_id.h"
+#include "components/tabs/public/tab_group.h"
 
 namespace tab_groups {
 
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_delegate_browsertest.cc b/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_delegate_browsertest.cc
index 8811976..01f54f1 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_delegate_browsertest.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_delegate_browsertest.cc
@@ -23,7 +23,6 @@
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_web_contents_listener.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/tab_group_action_context_desktop.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_delegate_desktop.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.h"
 #include "chrome/common/channel_info.h"
@@ -46,6 +45,7 @@
 #include "components/sync_device_info/device_info_sync_service.h"
 #include "components/sync_device_info/device_info_tracker.h"
 #include "components/tab_groups/tab_group_color.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
@@ -878,7 +878,8 @@
   TabGroup* local_group =
       browser()->tab_strip_model()->group_model()->GetTabGroup(local_id);
   ASSERT_THAT(local_group, NotNull());
-  local_group->SetVisualData(
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(
+      local_id,
       TabGroupVisualData(u"Title", TabGroupColorId::kBlue,
                          /*is_collapsed=*/true),
       /*is_customized=*/true);
@@ -920,7 +921,8 @@
       browser()->tab_strip_model()->group_model()->GetTabGroup(local_id);
   ASSERT_THAT(local_group, NotNull());
   ASSERT_EQ(1, local_group->tab_count());
-  local_group->SetVisualData(
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(
+      local_id,
       TabGroupVisualData(u"Title", TabGroupColorId::kBlue,
                          /*is_collapsed=*/true),
       /*is_customized=*/true);
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_delegate_desktop.cc b/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_delegate_desktop.cc
index b001a7e..0199fb37 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_delegate_desktop.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_delegate_desktop.cc
@@ -23,6 +23,7 @@
 #include "components/saved_tab_groups/internal/tab_group_sync_service_impl.h"
 #include "components/saved_tab_groups/public/tab_group_sync_service.h"
 #include "components/saved_tab_groups/public/types.h"
+#include "components/tabs/public/tab_interface.h"
 #include "ui/gfx/range/range.h"
 
 namespace tab_groups {
@@ -376,14 +377,14 @@
       tab_strip_model->group_model()->GetTabGroup(tab_group_id);
 
   // Activate the first tab in the group.
-  std::optional<int> first_tab = tab_group->GetFirstTab();
-  DCHECK(first_tab.has_value());
-  tab_strip_model->ActivateTabAt(first_tab.value());
+  tabs::TabInterface* first_tab = tab_group->GetFirstTab();
+  DCHECK(first_tab);
+  tab_strip_model->ActivateTabAt(tab_strip_model->GetIndexOfTab(first_tab));
 
   // Update the group to use the saved title and color.
   TabGroupVisualData visual_data(saved_group.title(), saved_group.color(),
                                  /*is_collapsed=*/false);
-  tab_group->SetVisualData(visual_data, /*is_customized=*/true);
+  tab_strip_model->ChangeTabGroupVisuals(tab_group_id, visual_data);
 
   const std::optional<SavedTabGroup> saved_group2 =
       service_->GetGroup(saved_group.saved_guid());
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_navigation_browser_test.cc b/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_navigation_browser_test.cc
index 9181811..d0558e1 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_navigation_browser_test.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_navigation_browser_test.cc
@@ -13,7 +13,6 @@
 #include "chrome/browser/ui/tabs/public/tab_features.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_web_contents_listener.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/tab_group_action_context_desktop.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/saved_tab_groups/internal/tab_group_sync_service_impl.h"
@@ -21,6 +20,7 @@
 #include "components/saved_tab_groups/public/tab_group_sync_service.h"
 #include "components/saved_tab_groups/public/types.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "components/tabs/public/tab_interface.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/reload_type.h"
diff --git a/chrome/browser/ui/tabs/tab_collection_storage_unittest.cc b/chrome/browser/ui/tabs/tab_collection_storage_unittest.cc
index abf6337..fb555618 100644
--- a/chrome/browser/ui/tabs/tab_collection_storage_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_collection_storage_unittest.cc
@@ -8,17 +8,17 @@
 
 #include "base/test/gtest_util.h"
 #include "chrome/browser/ui/tabs/features.h"
-#include "chrome/browser/ui/tabs/tab_group_tab_collection.h"
 #include "chrome/browser/ui/tabs/tab_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
 #include "chrome/browser/ui/tabs/test_util.h"
-#include "chrome/browser/ui/tabs/unpinned_tab_collection.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/tabs/public/pinned_tab_collection.h"
 #include "components/tabs/public/tab_collection.h"
+#include "components/tabs/public/tab_group_tab_collection.h"
+#include "components/tabs/public/unpinned_tab_collection.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_renderer_host.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/tabs/tab_collection_unittest.cc b/chrome/browser/ui/tabs/tab_collection_unittest.cc
index 9b74a1a4..96426228 100644
--- a/chrome/browser/ui/tabs/tab_collection_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_collection_unittest.cc
@@ -9,13 +9,10 @@
 #include <optional>
 
 #include "chrome/browser/ui/tabs/features.h"
-#include "chrome/browser/ui/tabs/tab_group_tab_collection.h"
 #include "chrome/browser/ui/tabs/tab_model.h"
-#include "chrome/browser/ui/tabs/tab_strip_collection.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
 #include "chrome/browser/ui/tabs/test_util.h"
-#include "chrome/browser/ui/tabs/unpinned_tab_collection.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/tab_groups/tab_group_visual_data.h"
@@ -25,6 +22,9 @@
 #include "components/tabs/public/split_tab_id.h"
 #include "components/tabs/public/split_tab_visual_data.h"
 #include "components/tabs/public/tab_collection_storage.h"
+#include "components/tabs/public/tab_group_tab_collection.h"
+#include "components/tabs/public/tab_strip_collection.h"
+#include "components/tabs/public/unpinned_tab_collection.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_renderer_host.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -250,8 +250,8 @@
  public:
   TabGroupTabCollectionTest() {
     grouped_collection_ = std::make_unique<tabs::TabGroupTabCollection>(
-        tab_groups::TabGroupId::GenerateNew(), tab_groups::TabGroupVisualData(),
-        GetTabStripModel());
+        tab_groups::TabGroupId::GenerateNew(),
+        tab_groups::TabGroupVisualData());
   }
   TabGroupTabCollectionTest(const TabGroupTabCollectionTest&) = delete;
   TabGroupTabCollectionTest& operator=(const TabGroupTabCollectionTest&) =
@@ -437,7 +437,7 @@
     AddTabsToUnpinnedContainer(GetCollection(), GetTabStripModel(), 2);
     tab_groups::TabGroupId group_id = tab_groups::TabGroupId::GenerateNew();
     auto tab_group_one = std::make_unique<tabs::TabGroupTabCollection>(
-        group_id, tab_groups::TabGroupVisualData(), GetTabStripModel());
+        group_id, tab_groups::TabGroupVisualData());
     AddTabsToGroupContainer(tab_group_one.get(), GetTabStripModel(), 2);
     GetCollection()->AddCollection(std::move(tab_group_one), 2);
     AddTabsToUnpinnedContainer(GetCollection(), GetTabStripModel(), 2);
@@ -464,7 +464,7 @@
       std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
   tab_groups::TabGroupId group_id = tab_groups::TabGroupId::GenerateNew();
   auto tab_group_one = std::make_unique<tabs::TabGroupTabCollection>(
-      group_id, tab_groups::TabGroupVisualData(), GetTabStripModel());
+      group_id, tab_groups::TabGroupVisualData());
 
   tabs::TabModel* tab_model_one_ptr = tab_model_one.get();
   tabs::TabGroupTabCollection* tab_group_one_ptr = tab_group_one.get();
@@ -511,7 +511,7 @@
       std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
   tab_groups::TabGroupId group_id = tab_groups::TabGroupId::GenerateNew();
   auto tab_group_one = std::make_unique<tabs::TabGroupTabCollection>(
-      group_id, tab_groups::TabGroupVisualData(), GetTabStripModel());
+      group_id, tab_groups::TabGroupVisualData());
 
   tabs::TabModel* tab_model_one_ptr = tab_model_one.get();
   tabs::TabGroupTabCollection* tab_group_one_ptr = tab_group_one.get();
@@ -573,7 +573,7 @@
     std::unique_ptr<tabs::TabGroupTabCollection> group_one =
         std::make_unique<tabs::TabGroupTabCollection>(
             tab_groups::TabGroupId::GenerateNew(),
-            tab_groups::TabGroupVisualData(), GetTabStripModel());
+            tab_groups::TabGroupVisualData());
     tabs::TabGroupTabCollection* group_one_ptr = group_one.get();
     AddTabsToGroupContainer(group_one_ptr, GetTabStripModel(), 2);
     tab_strip_collection->AddTabGroup(std::move(group_one), 6);
@@ -661,7 +661,7 @@
   tab_groups::TabGroupId group_two_id = tab_groups::TabGroupId::GenerateNew();
   std::unique_ptr<tabs::TabGroupTabCollection> group_two =
       std::make_unique<tabs::TabGroupTabCollection>(
-          group_two_id, tab_groups::TabGroupVisualData(), GetTabStripModel());
+          group_two_id, tab_groups::TabGroupVisualData());
   tabs::TabGroupTabCollection* group_two_ptr = group_two.get();
 
   EXPECT_EQ(nullptr, tab_strip_collection->GetTabGroupCollection(group_two_id));
@@ -878,7 +878,7 @@
   std::unique_ptr<tabs::TabGroupTabCollection> group_one =
       std::make_unique<tabs::TabGroupTabCollection>(
           tab_groups::TabGroupId::GenerateNew(),
-          tab_groups::TabGroupVisualData(), GetTabStripModel());
+          tab_groups::TabGroupVisualData());
   tabs::TabGroupTabCollection* group_one_ptr = group_one.get();
   AddTabsToGroupContainer(group_one_ptr, GetTabStripModel(), 2);
 
@@ -1179,7 +1179,7 @@
   tab_groups::TabGroupId group_two_id = tab_groups::TabGroupId::GenerateNew();
   tab_strip_collection->CreateTabGroup(
       std::make_unique<tabs::TabGroupTabCollection>(
-          group_two_id, tab_groups::TabGroupVisualData(), GetTabStripModel()));
+          group_two_id, tab_groups::TabGroupVisualData()));
   // TODO(crbug.com/332586827): Re-enable death testing.
   // EXPECT_DEATH_IF_SUPPORTED(tab_strip_collection->ValidateData(), "");
 
diff --git a/chrome/browser/ui/tabs/tab_group.cc b/chrome/browser/ui/tabs/tab_group.cc
deleted file mode 100644
index 161670f..0000000
--- a/chrome/browser/ui/tabs/tab_group.cc
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/tabs/tab_group.h"
-
-#include <map>
-#include <memory>
-#include <optional>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/feature_list.h"
-#include "chrome/browser/favicon/favicon_utils.h"
-#include "chrome/browser/ui/tabs/tab_group_controller.h"
-#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
-#include "chrome/browser/ui/ui_features.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/tab_groups/tab_group_id.h"
-#include "components/tab_groups/tab_group_visual_data.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/text_elider.h"
-#include "url/gurl.h"
-
-TabGroup::TabGroup(TabGroupController* controller,
-                   const tab_groups::TabGroupId& id,
-                   const tab_groups::TabGroupVisualData& visual_data)
-    : controller_(controller), id_(id) {
-  visual_data_ = std::make_unique<tab_groups::TabGroupVisualData>(visual_data);
-}
-
-TabGroup::~TabGroup() = default;
-
-void TabGroup::SetVisualData(tab_groups::TabGroupVisualData visual_data,
-                             bool is_customized) {
-  // Move current visuals to old_visuals before updating
-  std::unique_ptr<tab_groups::TabGroupVisualData> old_visuals =
-      std::move(visual_data_);
-  TabGroupChange::VisualsChange visuals;
-  visuals.old_visuals = old_visuals.get();
-  visuals.new_visuals = &visual_data;
-
-  visual_data_ = std::make_unique<tab_groups::TabGroupVisualData>(visual_data);
-
-  // Once the visual data is customized, it should stay customized.
-  is_customized_ |= is_customized;
-
-  // Notify the controller of the visual change
-  controller_->OnTabGroupVisualsChanged(id_, visuals);
-}
-
-void TabGroup::SetGroupIsClosing(bool is_closing) {
-  is_closing_ = is_closing;
-}
-
-std::u16string TabGroup::GetContentString() const {
-  gfx::Range tabs_in_group = ListTabs();
-  DCHECK_GT(tabs_in_group.length(), 0u);
-
-  constexpr size_t kContextMenuTabTitleMaxLength = 30;
-  std::u16string format_string = l10n_util::GetPluralStringFUTF16(
-      IDS_TAB_CXMENU_PLACEHOLDER_GROUP_TITLE, tabs_in_group.length() - 1);
-  std::u16string short_title;
-  gfx::ElideString(controller_->GetTitleAt(tabs_in_group.start()),
-                   kContextMenuTabTitleMaxLength, &short_title);
-  return base::ReplaceStringPlaceholders(format_string, short_title, nullptr);
-}
-
-void TabGroup::AddTab() {
-  ++tab_count_;
-}
-
-void TabGroup::RemoveTab() {
-  DCHECK_GT(tab_count_, 0);
-  --tab_count_;
-}
-
-bool TabGroup::IsEmpty() const {
-  return tab_count_ == 0;
-}
-
-bool TabGroup::IsCustomized() const {
-  return is_customized_;
-}
-
-std::optional<int> TabGroup::GetFirstTab() const {
-  for (int i = 0; i < controller_->GetTabCount(); ++i) {
-    if (controller_->GetTabGroupForTab(i) == id_) {
-      return i;
-    }
-  }
-
-  return std::nullopt;
-}
-
-std::optional<int> TabGroup::GetLastTab() const {
-  for (int i = controller_->GetTabCount() - 1; i >= 0; --i) {
-    if (controller_->GetTabGroupForTab(i) == id_) {
-      return i;
-    }
-  }
-
-  return std::nullopt;
-}
-
-gfx::Range TabGroup::ListTabs() const {
-  std::optional<int> maybe_first_tab = GetFirstTab();
-  if (!maybe_first_tab) {
-    return gfx::Range();
-  }
-
-  int first_tab = maybe_first_tab.value();
-  // Safe to assume GetLastTab() is not nullopt.
-  int last_tab = GetLastTab().value();
-
-  // If DCHECKs are enabled, check for group contiguity. The result
-  // doesn't really make sense if the group is discontiguous.
-  if (DCHECK_IS_ON()) {
-    for (int i = first_tab; i <= last_tab; ++i) {
-      DCHECK(controller_->GetTabGroupForTab(i) == id_);
-    }
-  }
-
-  return gfx::Range(first_tab, last_tab + 1);
-}
diff --git a/chrome/browser/ui/tabs/tab_group_controller.h b/chrome/browser/ui/tabs/tab_group_controller.h
deleted file mode 100644
index cafe538..0000000
--- a/chrome/browser/ui/tabs/tab_group_controller.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_TABS_TAB_GROUP_CONTROLLER_H_
-#define CHROME_BROWSER_UI_TABS_TAB_GROUP_CONTROLLER_H_
-
-#include <optional>
-#include <string>
-
-#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
-
-namespace tab_groups {
-class TabGroupId;
-}
-
-class TabGroupController {
- public:
-  virtual void OpenTabGroupEditor(const tab_groups::TabGroupId& group) = 0;
-
-  // Called whenever a tab group's visuals are updated by the tab group object.
-  virtual void OnTabGroupVisualsChanged(
-      const tab_groups::TabGroupId& group,
-      const TabGroupChange::VisualsChange& visuals) = 0;
-  virtual std::u16string GetTitleAt(int index) const = 0;
-
-  // Methods from TabStripModel that are exposed to TabGroup.
-  virtual std::optional<tab_groups::TabGroupId> GetTabGroupForTab(
-      int index) const = 0;
-  virtual int GetTabCount() const = 0;
-
- protected:
-  virtual ~TabGroupController() = default;
-};
-
-#endif  // CHROME_BROWSER_UI_TABS_TAB_GROUP_CONTROLLER_H_
diff --git a/chrome/browser/ui/tabs/tab_group_model.cc b/chrome/browser/ui/tabs/tab_group_model.cc
index 5ddf6f8..238e4076 100644
--- a/chrome/browser/ui/tabs/tab_group_model.cc
+++ b/chrome/browser/ui/tabs/tab_group_model.cc
@@ -12,14 +12,12 @@
 
 #include "base/containers/contains.h"
 #include "base/types/pass_key.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
-#include "chrome/browser/ui/tabs/tab_group_controller.h"
 #include "components/tab_groups/tab_group_color.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 
-TabGroupModel::TabGroupModel(TabGroupController* controller)
-    : controller_(controller) {}
+TabGroupModel::TabGroupModel() = default;
 
 TabGroupModel::~TabGroupModel() = default;
 
@@ -30,7 +28,6 @@
   CHECK(!ContainsTabGroup(group->id()));
   group_ids_.emplace_back(group->id());
   groups_[group->id()] = group;
-  group->set_controller(controller_, base::PassKey<TabGroupModel>());
 }
 
 bool TabGroupModel::ContainsTabGroup(const tab_groups::TabGroupId& id) const {
@@ -45,9 +42,6 @@
 void TabGroupModel::RemoveTabGroup(const tab_groups::TabGroupId& id,
                                    base::PassKey<TabStripModel>) {
   CHECK(ContainsTabGroup(id));
-  // TODO(397754004): Set the controller for the group to nullptr. This might
-  // break callers that try to query any group related information of remove
-  // notification from tabstripmodel.
   std::erase(group_ids_, id);
   groups_.erase(id);
 }
diff --git a/chrome/browser/ui/tabs/tab_group_model.h b/chrome/browser/ui/tabs/tab_group_model.h
index ee82a4a..0cbeb9e 100644
--- a/chrome/browser/ui/tabs/tab_group_model.h
+++ b/chrome/browser/ui/tabs/tab_group_model.h
@@ -17,7 +17,6 @@
 #include "base/types/pass_key.h"
 
 class TabGroup;
-class TabGroupController;
 class TabStripModel;
 namespace tab_groups {
 enum class TabGroupColorId;
@@ -32,7 +31,7 @@
 // need to be reflected in the view.
 class TabGroupModel {
  public:
-  explicit TabGroupModel(TabGroupController* controller);
+  TabGroupModel();
   ~TabGroupModel();
 
   // Returns whether a tab group with the given |id| exists.
@@ -64,8 +63,6 @@
   // Used to maintain insertion order of TabGroupsIds added to the
   // TabGroupModel.
   std::vector<tab_groups::TabGroupId> group_ids_;
-
-  raw_ptr<TabGroupController> controller_;
 };
 
 #endif  // CHROME_BROWSER_UI_TABS_TAB_GROUP_MODEL_H_
diff --git a/chrome/browser/ui/tabs/tab_iterator_unittest.cc b/chrome/browser/ui/tabs/tab_iterator_unittest.cc
index cee8d577..a2ad15c 100644
--- a/chrome/browser/ui/tabs/tab_iterator_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_iterator_unittest.cc
@@ -5,16 +5,16 @@
 #include <memory>
 #include <utility>
 
-#include "chrome/browser/ui/tabs/tab_group_tab_collection.h"
 #include "chrome/browser/ui/tabs/tab_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
 #include "chrome/browser/ui/tabs/test_util.h"
-#include "chrome/browser/ui/tabs/unpinned_tab_collection.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/tabs/public/split_tab_collection.h"
 #include "components/tabs/public/split_tab_visual_data.h"
 #include "components/tabs/public/tab_collection.h"
+#include "components/tabs/public/tab_group_tab_collection.h"
+#include "components/tabs/public/unpinned_tab_collection.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_renderer_host.h"
@@ -64,16 +64,14 @@
 }
 
 TEST_F(TabCollectionIteratorTest, IteratorWithOnlyCollection) {
-  collection()->AddCollection(
-      std::make_unique<tabs::TabGroupTabCollection>(
-          tab_groups::TabGroupId::GenerateNew(),
-          tab_groups::TabGroupVisualData(), GetTabStripModel()),
-      0);
-  collection()->AddCollection(
-      std::make_unique<tabs::TabGroupTabCollection>(
-          tab_groups::TabGroupId::GenerateNew(),
-          tab_groups::TabGroupVisualData(), GetTabStripModel()),
-      0);
+  collection()->AddCollection(std::make_unique<tabs::TabGroupTabCollection>(
+                                  tab_groups::TabGroupId::GenerateNew(),
+                                  tab_groups::TabGroupVisualData()),
+                              0);
+  collection()->AddCollection(std::make_unique<tabs::TabGroupTabCollection>(
+                                  tab_groups::TabGroupId::GenerateNew(),
+                                  tab_groups::TabGroupVisualData()),
+                              0);
 
   EXPECT_EQ(*collection()->begin(), nullptr);
   EXPECT_EQ(*collection()->end(), nullptr);
@@ -97,7 +95,7 @@
   std::unique_ptr<tabs::TabGroupTabCollection> group_one =
       std::make_unique<tabs::TabGroupTabCollection>(
           tab_groups::TabGroupId::GenerateNew(),
-          tab_groups::TabGroupVisualData(), GetTabStripModel());
+          tab_groups::TabGroupVisualData());
 
   group_one->AddTab(
       std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel()),
@@ -118,7 +116,7 @@
   std::unique_ptr<tabs::TabGroupTabCollection> group_two =
       std::make_unique<tabs::TabGroupTabCollection>(
           tab_groups::TabGroupId::GenerateNew(),
-          tab_groups::TabGroupVisualData(), GetTabStripModel());
+          tab_groups::TabGroupVisualData());
 
   group_two->AddTab(
       std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel()),
diff --git a/chrome/browser/ui/tabs/tab_model.cc b/chrome/browser/ui/tabs/tab_model.cc
index ee4df4f..51ae935 100644
--- a/chrome/browser/ui/tabs/tab_model.cc
+++ b/chrome/browser/ui/tabs/tab_model.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/ui/tabs/public/tab_dialog_manager.h"
 #include "chrome/browser/ui/tabs/public/tab_features.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
-#include "chrome/browser/ui/tabs/tab_group_tab_collection.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
 #include "chrome/browser/ui/ui_features.h"
@@ -24,6 +23,7 @@
 #include "components/tabs/public/split_tab_collection.h"
 #include "components/tabs/public/split_tab_id.h"
 #include "components/tabs/public/tab_collection.h"
+#include "components/tabs/public/tab_group_tab_collection.h"
 #include "components/web_modal/modal_dialog_host.h"
 #include "components/web_modal/web_contents_modal_dialog_host.h"
 #include "content/public/browser/visibility.h"
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 4bb02f2..b9a78aba 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -56,7 +56,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/commerce/ui_utils.h"
 #include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble.h"
-#include "chrome/browser/ui/tab_ui_helper.h"
 #include "chrome/browser/ui/tabs/features.h"
 #include "chrome/browser/ui/tabs/organization/metrics.h"
 #include "chrome/browser/ui/tabs/organization/tab_organization_service.h"
@@ -64,11 +63,8 @@
 #include "chrome/browser/ui/tabs/organization/tab_organization_session.h"
 #include "chrome/browser/ui/tabs/tab_change_type.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
-#include "chrome/browser/ui/tabs/tab_group_tab_collection.h"
 #include "chrome/browser/ui/tabs/tab_model.h"
-#include "chrome/browser/ui/tabs/tab_strip_collection.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/tabs/tab_strip_user_gesture_details.h"
@@ -95,8 +91,10 @@
 #include "components/tabs/public/split_tab_data.h"
 #include "components/tabs/public/split_tab_id.h"
 #include "components/tabs/public/split_tab_visual_data.h"
-#include "components/tabs/public/tab_collection.h"
+#include "components/tabs/public/tab_group.h"
+#include "components/tabs/public/tab_group_tab_collection.h"
 #include "components/tabs/public/tab_interface.h"
+#include "components/tabs/public/tab_strip_collection.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "components/webapps/common/web_app_id.h"
 #include "content/public/browser/browser_thread.h"
@@ -168,9 +166,8 @@
   return factory_instance;
 }
 
-std::unique_ptr<TabGroupModel> TabGroupModelFactory::Create(
-    TabGroupController* controller) {
-  return std::make_unique<TabGroupModel>(controller);
+std::unique_ptr<TabGroupModel> TabGroupModelFactory::Create() {
+  return std::make_unique<TabGroupModel>();
 }
 
 DetachedTabCollection::DetachedTabCollection(
@@ -242,7 +239,7 @@
   contents_data_ = std::make_unique<tabs::TabStripCollection>();
 
   if (group_model_factory) {
-    group_model_ = group_model_factory->Create(this);
+    group_model_ = group_model_factory->Create();
   }
   scrubbing_metrics_.Init();
 }
@@ -1801,8 +1798,7 @@
   ReentrancyCheck reentrancy_check(&reentrancy_guard_);
   CHECK(SupportsTabGroups());
   std::unique_ptr<tabs::TabGroupTabCollection> group_collection =
-      std::make_unique<tabs::TabGroupTabCollection>(group_id, visual_data,
-                                                    this);
+      std::make_unique<tabs::TabGroupTabCollection>(group_id, visual_data);
   group_model_->AddTabGroup(group_collection->GetTabGroup(),
                             base::PassKey<TabStripModel>());
   contents_data_->CreateTabGroup(std::move(group_collection));
@@ -1887,14 +1883,20 @@
 
   for (const auto& kv : indices_per_tab_group) {
     const TabGroup* group = group_model_->GetTabGroup(kv.first);
-    const int first_tab_in_group = group->GetFirstTab().value();
-    const int last_tab_in_group = group->GetLastTab().value();
+    CHECK(group);
+    gfx::Range group_index_range = group->ListTabs();
+    tabs::TabInterface* first_tab_in_group = group->GetFirstTab();
+    CHECK(first_tab_in_group);
+    int first_tab_index = GetIndexOfTab(first_tab_in_group);
+
+    tabs::TabInterface* last_tab_in_group = group->GetLastTab();
+    int last_tab_index = GetIndexOfTab(last_tab_in_group);
 
     // This is an estimate. If the group is non-contiguous it will be
     // larger than the true size. This can happen while dragging tabs in
     // or out of a group.
-    const int num_tabs_in_group = last_tab_in_group - first_tab_in_group + 1;
-    const int group_midpoint = first_tab_in_group + num_tabs_in_group / 2;
+    const int group_midpoint =
+        first_tab_index + (group_index_range.length() / 2);
 
     // Split group into |left_of_group| and |right_of_group| depending on
     // whether the index is closest to the left or right edge.
@@ -1907,9 +1909,9 @@
         right_of_group.push_back(index);
       }
     }
-    MoveTabsAndSetPropertiesImpl(left_of_group, first_tab_in_group,
-                                 std::nullopt, false);
-    MoveTabsAndSetPropertiesImpl(right_of_group, last_tab_in_group + 1,
+    MoveTabsAndSetPropertiesImpl(left_of_group, first_tab_index, std::nullopt,
+                                 false);
+    MoveTabsAndSetPropertiesImpl(right_of_group, last_tab_index + 1,
                                  std::nullopt, false);
   }
 }
@@ -1953,10 +1955,27 @@
   }
 }
 
-void TabStripModel::OnTabGroupVisualsChanged(
-    const tab_groups::TabGroupId& group,
-    const TabGroupChange::VisualsChange& visuals) {
-  TabGroupChange change(this, group, visuals);
+void TabStripModel::ChangeTabGroupVisuals(
+    const tab_groups::TabGroupId& group_id,
+    tab_groups::TabGroupVisualData visual_data,
+    bool is_customized) {
+  TabGroup* tab_group = group_model_->GetTabGroup(group_id);
+
+  // Move current visuals to old_visuals before updating
+  tab_groups::TabGroupVisualData old_visuals = *tab_group->visual_data();
+  TabGroupChange::VisualsChange visuals;
+  visuals.old_visuals = &old_visuals;
+  visuals.new_visuals = &visual_data;
+
+  tab_group->SetVisualData(visual_data, is_customized);
+  NotifyTabGroupVisualsChanged(group_id, visuals);
+}
+
+void TabStripModel::NotifyTabGroupVisualsChanged(
+    const tab_groups::TabGroupId& group_id,
+    TabGroupChange::VisualsChange visuals) {
+  // Notify the controller of the visual change
+  TabGroupChange change(this, group_id, visuals);
   for (auto& observer : observers_) {
     observer.OnTabGroupChanged(change);
   }
@@ -2128,10 +2147,6 @@
       *GetSplitData(split_id)->visual_data());
 }
 
-std::u16string TabStripModel::GetTitleAt(int index) const {
-  return TabUIHelper::FromWebContents(GetWebContentsAt(index))->GetTitle();
-}
-
 int TabStripModel::GetTabCount() const {
   return contents_data_->TabCountRecursive();
 }
@@ -3578,8 +3593,7 @@
           new_group,
           tab_groups::TabGroupVisualData(
               std::u16string(),
-              group_model_->GetNextColor(base::PassKey<TabStripModel>())),
-          this);
+              group_model_->GetNextColor(base::PassKey<TabStripModel>())));
   group_model_->AddTabGroup(group_collection->GetTabGroup(),
                             base::PassKey<TabStripModel>());
   contents_data_->CreateTabGroup(std::move(group_collection));
@@ -3645,8 +3659,13 @@
   }
 
   const TabGroup* group_object = group_model_->GetTabGroup(group);
-  int first_tab_in_group = group_object->GetFirstTab().value();
-  int last_tab_in_group = group_object->GetLastTab().value();
+
+  tabs::TabInterface* first_tab_in_group = group_object->GetFirstTab();
+  CHECK(first_tab_in_group);
+  int first_tab_index = GetIndexOfTab(first_tab_in_group);
+
+  tabs::TabInterface* last_tab_in_group = group_object->GetLastTab();
+  int last_tab_index = GetIndexOfTab(last_tab_in_group);
 
   // Split |new_indices| into |tabs_left_of_group| and |tabs_right_of_group| to
   // be moved to proper destination index. Directly set the group for indices
@@ -3654,9 +3673,9 @@
   std::vector<int> tabs_left_of_group;
   std::vector<int> tabs_right_of_group;
   for (int index : indices) {
-    if (index < first_tab_in_group) {
+    if (index < first_tab_index) {
       tabs_left_of_group.push_back(index);
-    } else if (index > last_tab_in_group) {
+    } else if (index > last_tab_index) {
       tabs_right_of_group.push_back(index);
     }
   }
@@ -3665,12 +3684,12 @@
     std::vector<int> all_tabs = tabs_left_of_group;
     all_tabs.insert(all_tabs.end(), tabs_right_of_group.begin(),
                     tabs_right_of_group.end());
-    MoveTabsAndSetPropertiesImpl(all_tabs, last_tab_in_group + 1, group, false);
+    MoveTabsAndSetPropertiesImpl(all_tabs, last_tab_index + 1, group, false);
   } else {
-    MoveTabsAndSetPropertiesImpl(tabs_left_of_group, first_tab_in_group, group,
+    MoveTabsAndSetPropertiesImpl(tabs_left_of_group, first_tab_index, group,
                                  false);
-    MoveTabsAndSetPropertiesImpl(tabs_right_of_group, last_tab_in_group + 1,
-                                 group, false);
+    MoveTabsAndSetPropertiesImpl(tabs_right_of_group, last_tab_index + 1, group,
+                                 false);
   }
 }
 
@@ -3972,7 +3991,7 @@
     // TabGroupChange::kCreated.
     if (is_group_empty) {
       TabGroupChange::VisualsChange visuals;
-      OnTabGroupVisualsChanged(new_group.value(), visuals);
+      NotifyTabGroupVisualsChanged(new_group.value(), visuals);
     }
   }
 }
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index e192270..80c73ae 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -23,7 +23,6 @@
 #include "base/scoped_multi_source_observation.h"
 #include "base/scoped_observation.h"
 #include "build/build_config.h"
-#include "chrome/browser/ui/tabs/tab_group_controller.h"
 #include "chrome/browser/ui/tabs/tab_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_scrubbing_metrics.h"
 #include "chrome/browser/ui/tabs/tab_strip_user_gesture_details.h"
@@ -70,7 +69,7 @@
   TabGroupModelFactory& operator=(const TabGroupModelFactory&) = delete;
 
   static TabGroupModelFactory* GetInstance();
-  std::unique_ptr<TabGroupModel> Create(TabGroupController* controller);
+  std::unique_ptr<TabGroupModel> Create();
 };
 
 // Have DetachedTabCollection object as a container of the `collection_` so
@@ -174,7 +173,7 @@
 // accessed on the UI thread.
 //
 ////////////////////////////////////////////////////////////////////////////////
-class TabStripModel : public TabGroupController {
+class TabStripModel {
  public:
   using TabIterator = tabs::TabCollection::Iterator;
 
@@ -196,7 +195,7 @@
   TabStripModel(const TabStripModel&) = delete;
   TabStripModel& operator=(const TabStripModel&) = delete;
 
-  ~TabStripModel() override;
+  ~TabStripModel();
 
   // Retrieves the TabStripModelDelegate associated with this TabStripModel.
   TabStripModelDelegate* delegate() const { return delegate_; }
@@ -211,6 +210,11 @@
 
   // Retrieve the number of WebContentses/emptiness of the TabStripModel.
   int count() const;
+
+  // TODO(crbug.com/417291958) remove this function since its the same as
+  // count().
+  int GetTabCount() const;
+
   bool empty() const;
 
   // Retrieve the Profile associated with this TabStripModel.
@@ -267,8 +271,8 @@
 
   // Creates a group object so that group_model can link it with once group
   // collection owns it.
-  // TODO(392952244): Remove this after replacing callers with detaching and
-  // attaching groups.
+  // TODO(crbug.com/392952244): Remove this after replacing callers with
+  // detaching and attaching groups.
   void AddTabGroup(const tab_groups::TabGroupId group_id,
                    tab_groups::TabGroupVisualData visual_data);
 
@@ -492,8 +496,7 @@
 
   // Returns the group that contains the tab at |index|, or nullopt if the tab
   // index is invalid or not grouped.
-  std::optional<tab_groups::TabGroupId> GetTabGroupForTab(
-      int index) const override;
+  std::optional<tab_groups::TabGroupId> GetTabGroupForTab(int index) const;
 
   // If a tab inserted at |index| would be within a tab group, return that
   // group's ID. Otherwise, return nullopt. If |index| points to the first tab
@@ -647,14 +650,15 @@
   // Saves tabs with url supported by Read Later.
   void AddToReadLater(const std::vector<int>& indices);
 
-  // TabGroupController:
-  void OpenTabGroupEditor(const tab_groups::TabGroupId& group) override;
-  void OnTabGroupVisualsChanged(
-      const tab_groups::TabGroupId& group,
-      const TabGroupChange::VisualsChange& visuals) override;
-  std::u16string GetTitleAt(int index) const override;
-  // The same as count(), but overridden for TabGroup to access.
-  int GetTabCount() const override;
+  // Notifies all group observers that the TabGroupEditor is opening. This is
+  // used by Views that want to force the editor to open without having to find
+  // the group's header view in the Tab Strip.
+  void OpenTabGroupEditor(const tab_groups::TabGroupId& group);
+
+  // Updates the group visuals and notifies observers.
+  void ChangeTabGroupVisuals(const tab_groups::TabGroupId& group,
+                             tab_groups::TabGroupVisualData visual_data,
+                             bool is_customized = false);
 
   // Returns iterators for traversing through all the tabs in the tabstrip.
   TabIterator begin() const;
@@ -834,6 +838,10 @@
                 const TabStripSelectionChange& selection);
 
   // Notify observers that a `group` was created.
+  void NotifyTabGroupVisualsChanged(const tab_groups::TabGroupId& group_id,
+                                    TabGroupChange::VisualsChange visuals);
+
+  // Notify observers that a `group` was created.
   void NotifyTabGroupCreated(const tab_groups::TabGroupId& group);
 
   // Notify observers that a `group` was closed.
diff --git a/chrome/browser/ui/tabs/tab_strip_model_observer.cc b/chrome/browser/ui/tabs/tab_strip_model_observer.cc
index 406ac3f..a037362a 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_observer.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_observer.cc
@@ -9,10 +9,10 @@
 
 #include "base/check_op.h"
 #include "base/trace_event/trace_event.h"
-#include "chrome/browser/ui/tabs/tab_group_tab_collection.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "components/tabs/public/split_tab_collection.h"
 #include "components/tabs/public/split_tab_visual_data.h"
+#include "components/tabs/public/tab_group_tab_collection.h"
 #include "components/tabs/public/tab_interface.h"
 #include "content/public/browser/web_contents.h"
 #include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
diff --git a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
index 4863e5b..9f8c03d 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
@@ -33,9 +33,7 @@
 #include "chrome/browser/ui/browser_window/test/mock_browser_window_interface.h"
 #include "chrome/browser/ui/tabs/features.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
-#include "chrome/browser/ui/tabs/tab_group_tab_collection.h"
 #include "chrome/browser/ui/tabs/tab_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/tabs/tab_strip_user_gesture_details.h"
@@ -51,6 +49,8 @@
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tabs/public/split_tab_data.h"
 #include "components/tabs/public/split_tab_visual_data.h"
+#include "components/tabs/public/tab_group.h"
+#include "components/tabs/public/tab_group_tab_collection.h"
 #include "components/tabs/public/tab_interface.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
@@ -4716,7 +4716,7 @@
 
   const tab_groups::TabGroupVisualData new_data(
       u"Foo", tab_groups::TabGroupColorId::kCyan);
-  tabstrip()->group_model()->GetTabGroup(group)->SetVisualData(new_data);
+  tabstrip()->ChangeTabGroupVisuals(group, new_data);
   const tab_groups::TabGroupVisualData* data =
       tabstrip()->group_model()->GetTabGroup(group)->visual_data();
   EXPECT_EQ(data->title(), new_data.title());
@@ -4736,7 +4736,7 @@
 
   const tab_groups::TabGroupVisualData new_data(
       u"Foo", tab_groups::TabGroupColorId::kBlue);
-  tabstrip()->group_model()->GetTabGroup(group)->SetVisualData(new_data);
+  tabstrip()->ChangeTabGroupVisuals(group, new_data);
 
   // Now check that we are notified when we change it, once at creation
   // and once from the explicit update.
diff --git a/chrome/browser/ui/uma_browsing_activity_observer.cc b/chrome/browser/ui/uma_browsing_activity_observer.cc
index bf44f55..6ba6107 100644
--- a/chrome/browser/ui/uma_browsing_activity_observer.cc
+++ b/chrome/browser/ui/uma_browsing_activity_observer.cc
@@ -18,12 +18,12 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/upgrade_detector/upgrade_detector.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/unload_controller.cc b/chrome/browser/ui/unload_controller.cc
index b98d7d3..b11c1ca 100644
--- a/chrome/browser/ui/unload_controller.cc
+++ b/chrome/browser/ui/unload_controller.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/lifetime/application_lifetime_desktop.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
@@ -23,6 +22,7 @@
 #include "chrome/browser/web_applications/policy/web_app_policy_manager.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "components/webapps/common/web_app_id.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_interactive_uitest.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_interactive_uitest.cc
index d5b68ae5..8dea7d6 100644
--- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_interactive_uitest.cc
+++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_interactive_uitest.cc
@@ -21,7 +21,6 @@
 #include "chrome/browser/ui/tabs/features.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_service_proxy.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_menu_model.h"
 #include "chrome/browser/ui/tabs/test/tab_strip_interactive_test_mixin.h"
@@ -53,6 +52,7 @@
 #include "components/saved_tab_groups/public/tab_group_sync_service.h"
 #include "components/tab_groups/tab_group_color.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/favicon_status.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/test/browser_test.h"
@@ -924,7 +924,8 @@
                         old_visual_data->color()),
       // Update the text and color.
       Do([&]() {
-        group->SetVisualData(/*visual_data=*/{new_title, new_color});
+        browser()->tab_strip_model()->ChangeTabGroupVisuals(
+            group_id, {new_title, new_color});
       }),
       // Verify the button has the same color and title as the tab group.
       CheckViewProperty(kSavedTabGroupButtonElementId,
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/shared_tab_group_interactive_uitest.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/shared_tab_group_interactive_uitest.cc
index 5621960..d293c76 100644
--- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/shared_tab_group_interactive_uitest.cc
+++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/shared_tab_group_interactive_uitest.cc
@@ -10,7 +10,6 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_element_identifiers.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_metrics.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/test/tab_strip_interactive_test_mixin.h"
@@ -34,6 +33,7 @@
 #include "components/signin/public/identity_manager/identity_test_utils.h"
 #include "components/tab_groups/tab_group_color.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/test/browser_test.h"
 #include "google_apis/gaia/core_account_id.h"
 #include "google_apis/gaia/gaia_id.h"
@@ -259,7 +259,8 @@
   // know when the entity tracker is initialized.
   TabGroup* tab_group =
       browser()->tab_strip_model()->group_model()->GetTabGroup(group_id);
-  tab_group->SetVisualData(*tab_group->visual_data());
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(
+      group_id, *tab_group->visual_data());
 
   RunTestSequence(WaitForShow(kTabGroupHeaderElementId),
                   FinishTabstripAnimations(),
diff --git a/chrome/browser/ui/views/data_sharing/data_sharing_chrome_native_interactive_uitest.cc b/chrome/browser/ui/views/data_sharing/data_sharing_chrome_native_interactive_uitest.cc
index f0049b0..0e85664 100644
--- a/chrome/browser/ui/views/data_sharing/data_sharing_chrome_native_interactive_uitest.cc
+++ b/chrome/browser/ui/views/data_sharing/data_sharing_chrome_native_interactive_uitest.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/ui/browser_element_identifiers.h"
 #include "chrome/browser/ui/browser_window/public/browser_window_features.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/test/tab_strip_interactive_test_mixin.h"
 #include "chrome/browser/ui/toolbar/app_menu_model.h"
@@ -38,6 +37,7 @@
 #include "components/saved_tab_groups/public/tab_group_sync_service.h"
 #include "components/saved_tab_groups/public/types.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/test/browser_test.h"
 #include "ui/base/interaction/element_identifier.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
diff --git a/chrome/browser/ui/views/data_sharing/data_sharing_live_browsertest.cc b/chrome/browser/ui/views/data_sharing/data_sharing_live_browsertest.cc
index 7fa63ab..680803e 100644
--- a/chrome/browser/ui/views/data_sharing/data_sharing_live_browsertest.cc
+++ b/chrome/browser/ui/views/data_sharing/data_sharing_live_browsertest.cc
@@ -9,7 +9,6 @@
 #include "chrome/browser/signin/e2e_tests/signin_util.h"
 #include "chrome/browser/tab_group_sync/tab_group_sync_service_factory.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/tab_group_action_context_desktop.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/ui_features.h"
@@ -22,6 +21,7 @@
 #include "components/signin/public/identity_manager/test_accounts.h"
 #include "components/sync/service/sync_service.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
diff --git a/chrome/browser/ui/views/page_action/collaboration_messaging_page_action_icon_view_interactive_uitest.cc b/chrome/browser/ui/views/page_action/collaboration_messaging_page_action_icon_view_interactive_uitest.cc
index 6020a4b..6651f60 100644
--- a/chrome/browser/ui/views/page_action/collaboration_messaging_page_action_icon_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/page_action/collaboration_messaging_page_action_icon_view_interactive_uitest.cc
@@ -10,13 +10,13 @@
 #include "chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_observer.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_observer_factory.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_tab_data.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/views/page_action/collaboration_messaging_page_action_icon_view.h"
 #include "chrome/test/interaction/interactive_browser_test.h"
 #include "components/collaboration/public/messaging/message.h"
 #include "components/data_sharing/public/features.h"
 #include "components/saved_tab_groups/public/features.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/test/browser_test.h"
 
 using collaboration::messaging::CollaborationEvent;
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index 856786d..2760b7a 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -34,7 +34,6 @@
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
 #include "chrome/browser/ui/tabs/split_tab_util.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_deletion_dialog_controller.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_menu_model.h"
@@ -69,6 +68,7 @@
 #include "components/tabs/public/split_tab_data.h"
 #include "components/tabs/public/split_tab_id.h"
 #include "components/tabs/public/split_tab_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "components/tabs/public/tab_interface.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
@@ -77,6 +77,7 @@
 #include "content/public/browser/web_contents.h"
 #include "ipc/ipc_message.h"
 #include "third_party/metrics_proto/omnibox_event.pb.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/list_selection_model.h"
 #include "ui/base/models/menu_model.h"
 #include "ui/base/mojom/menu_source_type.mojom-forward.h"
@@ -84,6 +85,7 @@
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/range/range.h"
+#include "ui/gfx/text_elider.h"
 #include "ui/views/controls/menu/menu_runner.h"
 #include "ui/views/widget/widget.h"
 #include "url/origin.h"
@@ -559,7 +561,8 @@
   if (origin != ToggleTabGroupCollapsedStateOrigin::kMenuAction ||
       should_toggle_group) {
     tabstrip_->ToggleTabGroup(group, !is_currently_collapsed, origin);
-    model_->group_model()->GetTabGroup(group)->SetVisualData(
+    model_->ChangeTabGroupVisuals(
+        group,
         tab_groups::TabGroupVisualData(GetGroupTitle(group),
                                        GetGroupColorId(group),
                                        !is_currently_collapsed),
@@ -685,9 +688,24 @@
   return model_->group_model()->GetTabGroup(group)->visual_data()->title();
 }
 
+// TODO(crbug.com/418774949) Combine with ExistingTabGroupSubMenuModel and move
+// To TabGroupFeatures.
 std::u16string BrowserTabStripController::GetGroupContentString(
     const tab_groups::TabGroupId& group) const {
-  return model_->group_model()->GetTabGroup(group)->GetContentString();
+  CHECK(model_->SupportsTabGroups());
+
+  const TabGroup* tab_group = model_->group_model()->GetTabGroup(group);
+  CHECK(tab_group);
+
+  constexpr size_t kContextMenuTabTitleMaxLength = 30;
+  std::u16string format_string = l10n_util::GetPluralStringFUTF16(
+      IDS_TAB_CXMENU_PLACEHOLDER_GROUP_TITLE, tab_group->tab_count() - 1);
+  std::u16string short_title;
+  gfx::ElideString(
+      TabUIHelper::FromWebContents(tab_group->GetFirstTab()->GetContents())
+          ->GetTitle(),
+      kContextMenuTabTitleMaxLength, &short_title);
+  return base::ReplaceStringPlaceholders(format_string, short_title, nullptr);
 }
 
 tab_groups::TabGroupColorId BrowserTabStripController::GetGroupColorId(
@@ -712,12 +730,17 @@
 void BrowserTabStripController::SetVisualDataForGroup(
     const tab_groups::TabGroupId& group,
     const tab_groups::TabGroupVisualData& visual_data) {
-  model_->group_model()->GetTabGroup(group)->SetVisualData(visual_data);
+  model_->ChangeTabGroupVisuals(group, visual_data);
 }
 
 std::optional<int> BrowserTabStripController::GetFirstTabInGroup(
     const tab_groups::TabGroupId& group) const {
-  return model_->group_model()->GetTabGroup(group)->GetFirstTab();
+  tabs::TabInterface* tab =
+      model_->group_model()->GetTabGroup(group)->GetFirstTab();
+  if (!tab) {
+    return std::nullopt;
+  }
+  return model_->GetIndexOfTab(tab);
 }
 
 gfx::Range BrowserTabStripController::ListTabsInGroup(
diff --git a/chrome/browser/ui/views/tabs/dragging/drag_session_data.cc b/chrome/browser/ui/views/tabs/dragging/drag_session_data.cc
index 324e07e..07b0442 100644
--- a/chrome/browser/ui/views/tabs/dragging/drag_session_data.cc
+++ b/chrome/browser/ui/views/tabs/dragging/drag_session_data.cc
@@ -6,13 +6,13 @@
 
 #include "base/memory/raw_ptr.h"
 #include "base/trace_event/trace_event.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/tabs/dragging/tab_drag_context.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
 #include "chrome/browser/ui/views/tabs/tab_slot_view.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
+#include "components/tabs/public/tab_group.h"
 
 TabDragData::TabDragData(TabDragContext* source_context, TabSlotView* view)
     : source_model_index(source_context->GetIndexOf(view)),
diff --git a/chrome/browser/ui/views/tabs/dragging/dragging_tabs_session.cc b/chrome/browser/ui/views/tabs/dragging/dragging_tabs_session.cc
index 47a736c..45e4c4db 100644
--- a/chrome/browser/ui/views/tabs/dragging/dragging_tabs_session.cc
+++ b/chrome/browser/ui/views/tabs/dragging/dragging_tabs_session.cc
@@ -124,8 +124,6 @@
 
   const gfx::Point dragged_view_point = GetAttachedDragPoint(point_in_screen);
 
-  const int threshold = attached_context_->GetHorizontalDragThreshold();
-
   std::vector<TabSlotView*> views(drag_data_.tab_drag_data_.size());
   for (size_t i = 0; i < drag_data_.tab_drag_data_.size(); ++i) {
     views[i] = drag_data_.tab_drag_data_[i].attached_view.get();
@@ -136,6 +134,17 @@
   const gfx::Point point_in_attached_context =
       views::View::ConvertPointFromScreen(attached_context_, point_in_screen);
 
+  const int to_index = attached_context_->GetInsertionIndexForDraggedBounds(
+      GetDraggedViewTabStripBounds(dragged_view_point),
+      drag_data_.attached_views(), drag_data_.num_dragging_tabs());
+
+  constexpr int kHorizontalMoveThreshold = 16;  // DIPs.
+  const int threshold = base::ClampRound(
+      static_cast<double>(
+          attached_context_->GetTabAt(to_index)->bounds().width()) /
+      TabStyle::Get()->GetStandardWidth(/*is_split=*/false) *
+      kHorizontalMoveThreshold);
+
   // Update the model, moving the WebContents from one index to another. Do this
   // only if we have moved a minimum distance since the last reorder (to prevent
   // jitter), or if this the first move and the tabs are not consecutive, or if
@@ -146,9 +155,6 @@
        threshold) ||
       (initial_move_ && !AreTabsConsecutive())) {
     TabStripModel* attached_model = attached_context_->GetTabStripModel();
-    const int to_index = attached_context_->GetInsertionIndexForDraggedBounds(
-        GetDraggedViewTabStripBounds(dragged_view_point),
-        drag_data_.attached_views(), drag_data_.num_dragging_tabs());
 
     content::WebContents* last_contents =
         drag_data_.tab_drag_data_.back().contents;
diff --git a/chrome/browser/ui/views/tabs/dragging/tab_drag_context.h b/chrome/browser/ui/views/tabs/dragging/tab_drag_context.h
index 8c4bc803..2c8a6c5a 100644
--- a/chrome/browser/ui/views/tabs/dragging/tab_drag_context.h
+++ b/chrome/browser/ui/views/tabs/dragging/tab_drag_context.h
@@ -104,11 +104,6 @@
   virtual int TabDragAreaEndX() const = 0;
   virtual int TabDragAreaBeginX() const = 0;
 
-  // Returns the horizontal drag threshold - the amount a tab drag must move to
-  // trigger a reorder. This is dependent on the width of tabs. The smaller the
-  // tabs compared to the standard size, the smaller the threshold.
-  virtual int GetHorizontalDragThreshold() const = 0;
-
   // Returns the index where the dragged WebContents should be inserted into
   // this tabstrip given the DraggedTabView's bounds `dragged_bounds` in
   // coordinates relative to `attached_tabstrip_` and has had the mirroring
diff --git a/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.cc
index bac0984d..a1e6a2c 100644
--- a/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.cc
@@ -37,7 +37,6 @@
 #include "chrome/browser/ui/tabs/organization/metrics.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -62,6 +61,7 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "components/tabs/public/tab_interface.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
@@ -77,6 +77,7 @@
 #include "ui/gfx/geometry/point_conversions.h"
 #include "ui/gfx/geometry/vector2d.h"
 #include "ui/gfx/image/image_skia_operations.h"
+#include "ui/gfx/range/range.h"
 #include "ui/views/controls/scroll_view.h"
 #include "ui/views/drag_utils.h"
 #include "ui/views/event_monitor.h"
@@ -437,12 +438,12 @@
     const tab_groups::TabGroupId group_id = source_view->group().value();
     const std::optional<tab_groups::TabGroupId> active_group_id =
         tab_strip_model->GetActiveTab()->GetGroup();
-    const std::optional<int> group_starting_index =
-        tab_strip_model->group_model()->GetTabGroup(group_id)->GetFirstTab();
+    gfx::Range group_range =
+        tab_strip_model->group_model()->GetTabGroup(group_id)->ListTabs();
     const int active_tab_index_within_group =
         (active_group_id.has_value() && active_group_id.value() == group_id &&
-         group_starting_index.has_value())
-            ? tab_strip_model->active_index() - group_starting_index.value()
+         !group_range.is_empty())
+            ? tab_strip_model->active_index() - group_range.GetMin()
             : 0;
     ref->drag_data_.group_drag_data_ = std::make_optional<GroupDragData>(
         group_id, active_tab_index_within_group);
@@ -1839,10 +1840,8 @@
         attached_context_->GetTabStripModel()->DetachTabGroupForInsertion(
             group_id),
         target_index);
-    source_context_->GetTabStripModel()
-        ->group_model()
-        ->GetTabGroup(group_id)
-        ->SetVisualData(first_tab_in_group.tab_group_data->group_visual_data);
+    source_context_->GetTabStripModel()->ChangeTabGroupVisuals(
+        group_id, first_tab_in_group.tab_group_data->group_visual_data);
     return;
   }
 
diff --git a/chrome/browser/ui/views/tabs/dragging/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/dragging/tab_drag_controller_interactive_uitest.cc
index b873145..4e2a4bd 100644
--- a/chrome/browser/ui/views/tabs/dragging/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/dragging/tab_drag_controller_interactive_uitest.cc
@@ -43,7 +43,6 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/tabs/features.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
@@ -72,6 +71,7 @@
 #include "components/tab_groups/tab_group_visual_data.h"
 #include "components/tabs/public/split_tab_data.h"
 #include "components/tabs/public/split_tab_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
@@ -1383,7 +1383,7 @@
   tab_groups::TabGroupId group2 = model->AddToNewGroup({1});
   const tab_groups::TabGroupVisualData new_data(
       u"Foo", tab_groups::TabGroupColorId::kCyan);
-  group_model->GetTabGroup(group2)->SetVisualData(new_data);
+  model->ChangeTabGroupVisuals(group2, new_data);
   StopAnimating(tab_strip);
 
   // Dragging the tab in the first index to the tab in the second index switches
diff --git a/chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view_interactive_uitest.cc b/chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view_interactive_uitest.cc
index 907016a..e23d2a4 100644
--- a/chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view_interactive_uitest.cc
@@ -6,7 +6,6 @@
 #include "chrome/browser/data_sharing/data_sharing_service_factory.h"
 #include "chrome/browser/tab_group_sync/tab_group_sync_service_factory.h"
 #include "chrome/browser/ui/browser_element_identifiers.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/test/tab_strip_interactive_test_mixin.h"
@@ -21,6 +20,7 @@
 #include "components/saved_tab_groups/public/tab_group_sync_service.h"
 #include "components/signin/public/base/avatar_icon_util.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/test/browser_test.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/http_connection.h"
diff --git a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc
index 05a1247..392e46b0 100644
--- a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc
+++ b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc
@@ -41,7 +41,6 @@
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_metrics.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_pref_names.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_deletion_dialog_controller.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -75,6 +74,7 @@
 #include "components/tab_groups/tab_group_color.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "tab_group_editor_bubble_view.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/accelerators/accelerator.h"
@@ -681,7 +681,8 @@
   tab_groups::TabGroupVisualData new_data(
       std::u16string(title_field_->GetText()), updated_color,
       current_visual_data->is_collapsed());
-  tab_group->SetVisualData(new_data, tab_group->IsCustomized());
+  browser_->tab_strip_model()->ChangeTabGroupVisuals(group_, new_data,
+                                                     tab_group->IsCustomized());
 }
 
 const std::u16string TabGroupEditorBubbleView::GetTextForCloseButton() const {
diff --git a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view_browsertest.cc b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view_browsertest.cc
index d61333d..ceedb4a 100644
--- a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view_browsertest.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_deletion_dialog_controller.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
@@ -24,6 +23,7 @@
 #include "components/data_sharing/public/features.h"
 #include "components/saved_tab_groups/public/features.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/test/browser_test.h"
 #include "ui/events/event.h"
 #include "ui/gfx/geometry/point_f.h"
diff --git a/chrome/browser/ui/views/tabs/tab_group_header_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_group_header_interactive_uitest.cc
index 4089ac5..9fb2ccf 100644
--- a/chrome/browser/ui/views/tabs/tab_group_header_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_group_header_interactive_uitest.cc
@@ -7,7 +7,6 @@
 #include "chrome/browser/data_sharing/data_sharing_service_factory.h"
 #include "chrome/browser/tab_group_sync/tab_group_sync_service_factory.h"
 #include "chrome/browser/ui/browser_element_identifiers.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/test/tab_strip_interactive_test_mixin.h"
@@ -22,6 +21,7 @@
 #include "components/saved_tab_groups/public/tab_group_sync_service.h"
 #include "components/signin/public/base/avatar_icon_util.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/test/browser_test.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/http_connection.h"
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 713beef..561724d 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -506,14 +506,6 @@
     return TabDragAreaBeginX() + GetTabDragAreaWidth();
   }
 
-  int GetHorizontalDragThreshold() const override {
-    constexpr int kHorizontalMoveThreshold = 16;  // DIPs.
-
-    double ratio = static_cast<double>(tab_strip_->GetInactiveTabWidth()) /
-                   TabStyle::Get()->GetStandardWidth(/*is_split=*/false);
-    return base::ClampRound(ratio * kHorizontalMoveThreshold);
-  }
-
   int GetInsertionIndexForDraggedBounds(const gfx::Rect& dragged_bounds,
                                         std::vector<TabSlotView*> dragged_views,
                                         int num_dragged_tabs) const override {
@@ -1173,8 +1165,6 @@
         base::TimeTicks::Now() - new_tab_button_pressed_start_time_.value());
     new_tab_button_pressed_start_time_.reset();
   }
-
-  LogTabWidthsForTabScrolling();
 }
 
 void TabStrip::MoveTab(int from_model_index,
@@ -2453,19 +2443,6 @@
   controller_->MoveGroup(group, target_index);
 }
 
-void TabStrip::LogTabWidthsForTabScrolling() {
-  int active_tab_width = GetActiveTabWidth();
-  int inactive_tab_width = GetInactiveTabWidth();
-
-  if (active_tab_width > 1) {
-    UMA_HISTOGRAM_EXACT_LINEAR("Tabs.ActiveTabWidth", active_tab_width, 257);
-  }
-  if (inactive_tab_width > 1) {
-    UMA_HISTOGRAM_EXACT_LINEAR("Tabs.InactiveTabWidth", inactive_tab_width,
-                               257);
-  }
-}
-
 // TabStrip:TabContextMenuController:
 // ----------------------------------------------------------
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index eddce1f..66f457e 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -447,10 +447,6 @@
   void AnnounceTabAddedToGroup(tab_groups::TabGroupId group_id);
   void AnnounceTabRemovedFromGroup(tab_groups::TabGroupId group_id);
 
-  // For metrics on the best size for tab scrolling, log if the different
-  // sizes would trigger tab scrolling
-  void LogTabWidthsForTabScrolling();
-
   // -- Member Variables ------------------------------------------------------
 
   raw_ptr<TabStripObserver> observer_;
diff --git a/chrome/browser/ui/views/tabs/tab_strip_browsertest.cc b/chrome/browser/ui/views/tabs/tab_strip_browsertest.cc
index 58dcc8a7a..f15e2bc6 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_browsertest.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_browsertest.cc
@@ -17,7 +17,6 @@
 #include "chrome/browser/ui/performance_controls/tab_resource_usage_tab_helper.h"
 #include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_renderer_data.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -28,6 +27,7 @@
 #include "components/data_sharing/public/features.h"
 #include "components/saved_tab_groups/public/features.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/test/browser_test.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/text/bytes_formatting.h"
@@ -1036,9 +1036,9 @@
 
   tab_groups::TabGroupId group = AddTabToNewGroup(1);
   tab_strip()->tab_at(1)->SetGroup(group);
-  tab_strip_model()->group_model()->GetTabGroup(group)->SetVisualData(
-      tab_groups::TabGroupVisualData(u"Test title",
-                                     tab_groups::TabGroupColorId::kBlue));
+  tab_strip_model()->ChangeTabGroupVisuals(
+      group, tab_groups::TabGroupVisualData(
+                 u"Test title", tab_groups::TabGroupColorId::kBlue));
 
   auto* group_header = tab_strip()->group_header(group);
   std::u16string group_title = tab_strip_model()
@@ -1059,7 +1059,8 @@
 
   // Validating tab_group name update & collapsed state change should update the
   // accessible name.
-  tab_strip_model()->group_model()->GetTabGroup(group)->SetVisualData(
+  tab_strip_model()->ChangeTabGroupVisuals(
+      group,
       tab_groups::TabGroupVisualData(u"", tab_groups::TabGroupColorId::kBlue));
   group_title = tab_strip_model()
                     ->group_model()
@@ -1076,9 +1077,9 @@
             l10n_util::GetStringFUTF16(IDS_GROUP_AX_LABEL_UNNAMED_GROUP_FORMAT,
                                        u"\"New Tab\"", collapsed_state));
 
-  tab_strip_model()->group_model()->GetTabGroup(group)->SetVisualData(
-      tab_groups::TabGroupVisualData(u"New test title",
-                                     tab_groups::TabGroupColorId::kBlue));
+  tab_strip_model()->ChangeTabGroupVisuals(
+      group, tab_groups::TabGroupVisualData(
+                 u"New test title", tab_groups::TabGroupColorId::kBlue));
   collapsed_state = GetCollapsedState(group);
   EXPECT_FALSE(tab_strip()->IsGroupCollapsed(group));
   group_title = tab_strip_model()
@@ -1238,9 +1239,9 @@
 
   tab_groups::TabGroupId group = AddTabToNewGroup(1);
   tab_strip()->tab_at(1)->SetGroup(group);
-  tab_strip_model()->group_model()->GetTabGroup(group)->SetVisualData(
-      tab_groups::TabGroupVisualData(u"Non empty title text",
-                                     tab_groups::TabGroupColorId::kBlue));
+  tab_strip_model()->ChangeTabGroupVisuals(
+      group, tab_groups::TabGroupVisualData(
+                 u"Non empty title text", tab_groups::TabGroupColorId::kBlue));
 
   auto* group_header = tab_strip()->group_header(group);
   std::u16string group_title = tab_strip_model()
@@ -1257,9 +1258,9 @@
           std::u16string(group_header->GetTitleTextForTesting()),
           tab_strip()->GetGroupContentString(group_header->group().value())));
 
-  tab_strip_model()->group_model()->GetTabGroup(group)->SetVisualData(
-      tab_groups::TabGroupVisualData(std::u16string(),
-                                     tab_groups::TabGroupColorId::kBlue));
+  tab_strip_model()->ChangeTabGroupVisuals(
+      group, tab_groups::TabGroupVisualData(
+                 std::u16string(), tab_groups::TabGroupColorId::kBlue));
 
   EXPECT_EQ(group_header->GetRenderedTooltipText(gfx::Point()),
             l10n_util::GetStringFUTF16(IDS_TAB_GROUPS_UNNAMED_GROUP_TOOLTIP,
@@ -1276,9 +1277,9 @@
 
   tab_groups::TabGroupId group = AddTabToNewGroup(1);
   tab_strip()->tab_at(1)->SetGroup(group);
-  tab_strip_model()->group_model()->GetTabGroup(group)->SetVisualData(
-      tab_groups::TabGroupVisualData(u"Non empty title text",
-                                     tab_groups::TabGroupColorId::kBlue));
+  tab_strip_model()->ChangeTabGroupVisuals(
+      group, tab_groups::TabGroupVisualData(
+                 u"Non empty title text", tab_groups::TabGroupColorId::kBlue));
 
   auto* group_header = tab_strip()->group_header(group);
   std::u16string group_title = tab_strip_model()
diff --git a/chrome/browser/ui/views/tabs/tab_strip_unittest.cc b/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
index 8d2baa09..caa2c82 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
@@ -501,7 +501,8 @@
 
   // Create a lot of tabs in order to make inactive tabs tiny.
   const int min_inactive_width = TabStyle::Get()->GetMinimumInactiveWidth();
-  while (GetInactiveTabWidth() != min_inactive_width) {
+  while (tab_strip_->GetTabCount() == 0 ||
+         tab_strip_->tab_at(0)->width() != min_inactive_width) {
     controller_->CreateNewTab();
     CompleteAnimationAndLayout();
   }
@@ -536,7 +537,9 @@
   const int min_inactive_width = TabStyle::Get()->GetMinimumInactiveWidth();
   const int min_active_width =
       TabStyle::Get()->GetMinimumActiveWidth(/*is_split*/ false);
-  while (GetInactiveTabWidth() >= (min_inactive_width + min_active_width) / 2) {
+  while (tab_strip_->GetTabCount() == 0 ||
+         tab_strip_->tab_at(0)->width() >=
+             (min_inactive_width + min_active_width) / 2) {
     controller_->CreateNewTab();
     CompleteAnimationAndLayout();
   }
@@ -548,12 +551,12 @@
   // remaining one will be active and there will be no inactive tabs,
   // so we stop at 2.
   while (tab_strip_->GetTabCount() > 2) {
-    const int last_inactive_width = GetInactiveTabWidth();
+    const int last_inactive_width = tab_strip_->tab_at(0)->width();
     tab_strip_->CloseTab(
         tab_strip_->tab_at(tab_strip_->GetActiveIndex().value()),
         CloseTabSource::kFromMouse);
     CompleteAnimationAndLayout();
-    EXPECT_GE(GetInactiveTabWidth(), last_inactive_width);
+    EXPECT_GE(tab_strip_->tab_at(0)->width(), last_inactive_width);
   }
 }
 
@@ -564,7 +567,8 @@
 
   // Create a lot of tabs in order to make inactive tabs tiny.
   const int min_inactive_width = TabStyle::Get()->GetMinimumInactiveWidth();
-  while (GetInactiveTabWidth() != min_inactive_width) {
+  while (tab_strip_->GetTabCount() == 0 ||
+         tab_strip_->tab_at(0)->width() != min_inactive_width) {
     controller_->CreateNewTab();
     CompleteAnimationAndLayout();
   }
diff --git a/chrome/browser/ui/webui/history_clusters/history_clusters_handler.cc b/chrome/browser/ui/webui/history_clusters/history_clusters_handler.cc
index 260ed629..e001f51a 100644
--- a/chrome/browser/ui/webui/history_clusters/history_clusters_handler.cc
+++ b/chrome/browser/ui/webui/history_clusters/history_clusters_handler.cc
@@ -30,7 +30,6 @@
 #include "chrome/browser/ui/browser_window/public/browser_window_features.h"
 #include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
 #include "chrome/browser/ui/profiles/profile_view_utils.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
@@ -50,6 +49,7 @@
 #include "components/search_engines/template_url.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/strings/grit/components_strings.h"
+#include "components/tabs/public/tab_group.h"
 #include "components/tabs/public/tab_interface.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
@@ -477,7 +477,7 @@
       // Copy and modify the existing visual data with a new title.
       tab_groups::TabGroupVisualData visual_data = *tab_group->visual_data();
       visual_data.SetTitle(base::UTF8ToUTF16(*tab_group_name));
-      tab_group->SetVisualData(visual_data);
+      model->ChangeTabGroupVisuals(new_group_id, visual_data);
     }
   }
 }
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.h b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.h
index 4c2e03b4f..6dcce9b 100644
--- a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.h
+++ b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.h
@@ -18,7 +18,6 @@
 #include "chrome/browser/ui/tabs/organization/tab_organization.h"
 #include "chrome/browser/ui/tabs/organization/tab_organization_observer.h"
 #include "chrome/browser/ui/tabs/organization/tab_organization_session.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_group_theme.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -28,6 +27,7 @@
 #include "components/optimization_guide/core/model_execution/settings_enabled_observer.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/sessions/core/tab_restore_service.h"
+#include "components/tabs/public/tab_group.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc b/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc
index 2f37aae..3b9a78d 100644
--- a/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc
+++ b/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc
@@ -369,7 +369,6 @@
   AddTabWithTitle(browser1(), GURL(kTabUrl2), kTabName2);
 
   TabStripModel* tab_strip_model = browser1()->tab_strip_model();
-  TabGroupModel* tab_group_model = tab_strip_model->group_model();
 
   // Associate a tab to a given tab group.
   tab_groups::TabGroupId group1 = tab_strip_model->AddToNewGroup({0});
@@ -378,7 +377,7 @@
   const tab_groups::TabGroupColorId sample_color =
       tab_groups::TabGroupColorId::kGrey;
   tab_groups::TabGroupVisualData visual_data1(sample_title, sample_color);
-  tab_group_model->GetTabGroup(group1)->SetVisualData(visual_data1);
+  tab_strip_model->ChangeTabGroupVisuals(group1, visual_data1);
 
   // Get Tabs and Tab Group details.
   tab_search::mojom::PageHandler::GetProfileDataCallback callback1 =
@@ -465,7 +464,6 @@
   AddTabWithTitle(browser1(), GURL(kTabUrl2), kTabName2);
 
   TabStripModel* tab_strip_model = browser1()->tab_strip_model();
-  TabGroupModel* tab_group_model = tab_strip_model->group_model();
 
   // Associate a tab to a given tab group.
   tab_groups::TabGroupId group1 = tab_strip_model->AddToNewGroup({0});
@@ -474,7 +472,7 @@
   const tab_groups::TabGroupColorId sample_color =
       tab_groups::TabGroupColorId::kGrey;
   tab_groups::TabGroupVisualData visual_data1(sample_title, sample_color);
-  tab_group_model->GetTabGroup(group1)->SetVisualData(visual_data1);
+  tab_strip_model->ChangeTabGroupVisuals(group1, visual_data1);
 
   // Close a group and its tabs.
   tab_strip_model->CloseAllTabsInGroup(group1);
@@ -533,8 +531,7 @@
   const tab_groups::TabGroupColorId sample_color =
       tab_groups::TabGroupColorId::kGrey;
   tab_groups::TabGroupVisualData visual_data1(sample_title, sample_color);
-  TabGroupModel* tab_group_model = tab_strip_model->group_model();
-  tab_group_model->GetTabGroup(group1)->SetVisualData(visual_data1);
+  tab_strip_model->ChangeTabGroupVisuals(group1, visual_data1);
 
   // Close the tabs associated with a browser.
   browser1()->tab_strip_model()->CloseAllTabs();
@@ -784,8 +781,7 @@
   const tab_groups::TabGroupColorId sample_color =
       tab_groups::TabGroupColorId::kGrey;
   tab_groups::TabGroupVisualData visual_data1(sample_title, sample_color);
-  TabGroupModel* tab_group_model = tab_strip_model->group_model();
-  tab_group_model->GetTabGroup(group1)->SetVisualData(visual_data1);
+  tab_strip_model->ChangeTabGroupVisuals(group1, visual_data1);
 
   browser1()->tab_strip_model()->CloseAllTabs();
   browser2()->tab_strip_model()->CloseAllTabs();
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc
index 62789fe4..d055dbc 100644
--- a/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc
+++ b/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc
@@ -26,7 +26,6 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/color/chrome_color_id.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_group_theme.h"
 #include "chrome/browser/ui/tabs/tab_menu_model.h"
@@ -45,6 +44,7 @@
 #include "components/tab_groups/tab_group_color.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/common/drop_data.h"
 #include "third_party/blink/public/common/input/web_gesture_event.h"
 #include "ui/aura/window_delegate.h"
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.h b/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.h
index d670c2eb..99be7c9 100644
--- a/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.h
+++ b/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.h
@@ -11,12 +11,12 @@
 #include "base/timer/timer.h"
 #include "chrome/browser/themes/theme_service_observer.h"
 #include "chrome/browser/ui/tabs/tab_change_type.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/webui/tab_strip/tab_before_unload_tracker.h"
 #include "chrome/browser/ui/webui/tab_strip/tab_strip.mojom.h"
 #include "chrome/browser/ui/webui/tab_strip/thumbnail_tracker.h"
 #include "components/saved_tab_groups/public/tab_group_sync_service.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "mojo/public/cpp/bindings/receiver.h"
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler_unittest.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler_unittest.cc
index de12ff3..c0f201e 100644
--- a/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler_unittest.cc
+++ b/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler_unittest.cc
@@ -214,20 +214,12 @@
       browser()->tab_strip_model()->AddToNewGroup({0});
   const tab_groups::TabGroupVisualData group1_visuals(
       u"Group 1", tab_groups::TabGroupColorId::kGreen);
-  browser()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(group1)
-      ->SetVisualData(group1_visuals);
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(group1, group1_visuals);
   tab_groups::TabGroupId group2 =
       browser()->tab_strip_model()->AddToNewGroup({1});
   const tab_groups::TabGroupVisualData group2_visuals(
       u"Group 2", tab_groups::TabGroupColorId::kCyan);
-  browser()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(group2)
-      ->SetVisualData(group2_visuals);
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(group2, group2_visuals);
 
   tab_strip::mojom::PageHandler::GetGroupVisualDataCallback callback =
       base::BindLambdaForTesting(
@@ -248,11 +240,8 @@
       browser()->tab_strip_model()->AddToNewGroup({0});
   const tab_groups::TabGroupVisualData new_visual_data(
       u"My new title", tab_groups::TabGroupColorId::kGreen);
-  browser()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(expected_group_id)
-      ->SetVisualData(new_visual_data);
+  browser()->tab_strip_model()->ChangeTabGroupVisuals(expected_group_id,
+                                                      new_visual_data);
 
   EXPECT_CALL(
       page_,
@@ -400,11 +389,8 @@
   // Create some visual data to make sure it gets transferred.
   const tab_groups::TabGroupVisualData visual_data(
       u"My group", tab_groups::TabGroupColorId::kGreen);
-  new_browser.get()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(group_id)
-      ->SetVisualData(visual_data);
+  new_browser.get()->tab_strip_model()->ChangeTabGroupVisuals(group_id,
+                                                              visual_data);
 
   content::WebContents* moved_contents1 =
       new_browser.get()->tab_strip_model()->GetWebContentsAt(0);
@@ -456,11 +442,8 @@
   // Create some visual data to make sure it gets transferred.
   const tab_groups::TabGroupVisualData visual_data(
       u"My group", tab_groups::TabGroupColorId::kGreen);
-  new_browser.get()
-      ->tab_strip_model()
-      ->group_model()
-      ->GetTabGroup(group_id)
-      ->SetVisualData(visual_data);
+  new_browser.get()->tab_strip_model()->ChangeTabGroupVisuals(group_id,
+                                                              visual_data);
 
   web_ui()->ClearTrackedCalls();
 
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_ui_util.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_ui_util.cc
index 3298a7a..cb5606f 100644
--- a/chrome/browser/ui/webui/tab_strip/tab_strip_ui_util.cc
+++ b/chrome/browser/ui/webui/tab_strip/tab_strip_ui_util.cc
@@ -15,11 +15,11 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_model.h"
 #include "chrome/browser/ui/webui/tab_strip/tab_strip_ui.h"
 #include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_group.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/clipboard/clipboard_format_type.h"
 #include "ui/base/clipboard/custom_data_helper.h"
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index 7f47ef1..1b901115 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -8,6 +8,7 @@
 import("//testing/test.gni")
 
 assert(!is_fuchsia, "Fuchsia shouldn't use anything in //chrome")
+assert(!is_android, "Android shouldn't use anything in //chrome/web_applications")
 
 source_set("web_applications") {
   sources = [
diff --git a/chrome/browser/web_applications/isolated_web_apps/OWNERS b/chrome/browser/web_applications/isolated_web_apps/OWNERS
index 9f446666..87595b4 100644
--- a/chrome/browser/web_applications/isolated_web_apps/OWNERS
+++ b/chrome/browser/web_applications/isolated_web_apps/OWNERS
@@ -4,4 +4,3 @@
 simonha@google.com
 
 # Backup OWNERS
-cmfcmf@chromium.org #{LAST_RESORT_SUGGESTION}
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index d0bc8ac..27a3a03a 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1747331992-514ecb535abd7911b7eada5f7d4aa75e92c510eb-6e0befebc90f982694346073119820ff61e213b5.profdata
+chrome-android32-main-1747719893-3c9e34321deb95365f5f982a1cc15519666f3fed-2f97115fc991c1e755b76c32e12c2c3f10e7bd7b.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 5e52722..e884169 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1747342978-05f42cae514e2a68e573402ca30224c66cc4850d-b8983f3a0ee438c844a535171c7e4a03e26529fd.profdata
+chrome-android64-main-1747722462-e121152d79ac9f1f8f15a1edeb57a0307f7182d0-b1d85aba3c3f074e0d8841b91b06b3201226dbe8.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 818049b..71b95f57 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1747706336-342ae52532b82d226477a67df84ce31c38795e1f-d29271b3bd04f264ba092e5dcc2e2579f7712701.profdata
+chrome-mac-arm-main-1747727718-c6eb8c61fdf85404da40972742aa626134cd06d7-021bccde4594335053979771d08aa0d2f39459f3.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 0d04649..02c02c2 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1747698011-62d683e15a9a8383d02a76dc83fd4f3d900d0918-3b9180ccbc5c7a525a46ae4f81f7209025954583.profdata
+chrome-mac-main-1747719893-b4f31881e5d3d34c258e3b93820d818aaaff3819-2f97115fc991c1e755b76c32e12c2c3f10e7bd7b.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index 0fd3cac..4d42776 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1747698011-43268f6a546662e2c8a657382f4023b0d0b29aed-3b9180ccbc5c7a525a46ae4f81f7209025954583.profdata
+chrome-win-arm64-main-1747719893-7c57d3f2cc12388843b361656cd2689de1c161a1-2f97115fc991c1e755b76c32e12c2c3f10e7bd7b.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 69c1bf7..d0ac04f 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1747677396-f26d0858b187abcb1c2eab628d4942713919a140-55031cf373b345a10a079f07cca33880566e8303.profdata
+chrome-win32-main-1747688297-3a4799fa1be0ce98605003500aafacac93cc2ff4-dc74cb818a84657e88260c06762b463b265b070e.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index f3800a1..c91d4c2 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -12059,6 +12059,7 @@
     "//components/sync",
     "//components/sync:test_support",
     "//components/tab_groups:tab_groups",
+    "//components/tabs:public",
     "//components/webapps/common",
     "//content/public/browser",
     "//content/test:test_support",
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/onboarding_landing_page_test.ts b/chrome/test/data/webui/chromeos/shimless_rma/onboarding_landing_page_test.ts
index 1cc2124..0d49bc7 100644
--- a/chrome/test/data/webui/chromeos/shimless_rma/onboarding_landing_page_test.ts
+++ b/chrome/test/data/webui/chromeos/shimless_rma/onboarding_landing_page_test.ts
@@ -29,6 +29,7 @@
   const verificationIconSelector = '#verificationIcon';
   const unqualifiedComponentsLinkSelector = '#unqualifiedComponentsLink';
   const verificationSkipMessageSelector = '#verificationSkipMessage';
+  const exitButtonSelector = '#landingExit';
 
   setup(() => {
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
@@ -187,6 +188,17 @@
             .textContent!.trim());
   });
 
+  // Hides Exit button when canExit is false.
+  test('ExitButtonHidesWhenCannotExit', async () => {
+    await initializeLandingPage();
+    assert(component);
+    component.canExit = false;
+
+    assertTrue(
+        strictQuery(exitButtonSelector, component.shadowRoot, HTMLElement)
+            .hidden);
+  });
+
   // Verify clicking the landing page's exit button sends the correct event.
   test('ExitButtonDispatchesExitEvent', async () => {
     await initializeLandingPage();
diff --git a/chromeos/ash/components/boca/spotlight/spotlight_crd_manager.h b/chromeos/ash/components/boca/spotlight/spotlight_crd_manager.h
index 17a604b..8e893a6 100644
--- a/chromeos/ash/components/boca/spotlight/spotlight_crd_manager.h
+++ b/chromeos/ash/components/boca/spotlight/spotlight_crd_manager.h
@@ -17,7 +17,6 @@
   SpotlightCrdManager& operator=(const SpotlightCrdManager&) = delete;
   virtual ~SpotlightCrdManager() = default;
 
-  virtual void OnSessionStarted(const std::string& teacher_email) = 0;
   virtual void OnSessionEnded() = 0;
 
   // TODO: dorianbrandon - Move to more appropriate class.
@@ -28,7 +27,8 @@
 
   // Starts the CRD session and returns the connection code for the request.
   virtual void InitiateSpotlightSession(
-      base::OnceCallback<void(const std::string&)> callback) = 0;
+      base::OnceCallback<void(const std::string&)> callback,
+      const std::string& requester_email) = 0;
 
  protected:
   SpotlightCrdManager() = default;
diff --git a/chromeos/ash/components/boca/spotlight/spotlight_session_manager.cc b/chromeos/ash/components/boca/spotlight/spotlight_session_manager.cc
index 49057a6..aa97cf3 100644
--- a/chromeos/ash/components/boca/spotlight/spotlight_session_manager.cc
+++ b/chromeos/ash/components/boca/spotlight/spotlight_session_manager.cc
@@ -43,7 +43,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   in_session_ = true;
-  spotlight_crd_manager_->OnSessionStarted(producer.email());
+  teacher_email_ = producer.email();
   teacher_name_ = producer.full_name();
 }
 
@@ -53,6 +53,7 @@
   in_session_ = false;
   request_in_progress_ = false;
   spotlight_crd_manager_->OnSessionEnded();
+  teacher_email_ = "";
   teacher_name_ = "";
   notification_handler_->StopSpotlightCountdown();
 }
@@ -80,15 +81,27 @@
 
   if (device->second.has_view_screen_config()) {
     switch (device->second.view_screen_config().view_screen_state()) {
-      case ::boca::ViewScreenConfig::REQUESTED:
+      case ::boca::ViewScreenConfig::REQUESTED: {
         if (request_in_progress_) {
           return;
         }
         request_in_progress_ = true;
+        std::string requester_email = teacher_email_;
+        // ignore the experiment, the correct experiment is not a part of this
+        // chain
+        if (ash::features::IsBocaSpotlightRobotRequesterEnabled() &&
+            device->second.view_screen_config().has_view_screen_requester()) {
+          requester_email = device->second.view_screen_config()
+                                .view_screen_requester()
+                                .service_account()
+                                .email();
+        }
         spotlight_crd_manager_->InitiateSpotlightSession(
             base::BindOnce(&SpotlightSessionManager::OnConnectionCodeReceived,
-                           weak_ptr_factory_.GetWeakPtr()));
+                           weak_ptr_factory_.GetWeakPtr()),
+            requester_email);
         break;
+      }
       case ::boca::ViewScreenConfig::INACTIVE:
         request_in_progress_ = false;
         notification_handler_->StopSpotlightCountdown();
diff --git a/chromeos/ash/components/boca/spotlight/spotlight_session_manager.h b/chromeos/ash/components/boca/spotlight/spotlight_session_manager.h
index 8a3dbf1..53093d0 100644
--- a/chromeos/ash/components/boca/spotlight/spotlight_session_manager.h
+++ b/chromeos/ash/components/boca/spotlight/spotlight_session_manager.h
@@ -53,6 +53,7 @@
   bool in_session_ = false;
   bool request_in_progress_ = false;
   std::string teacher_name_;
+  std::string teacher_email_;
   const std::unique_ptr<SpotlightNotificationHandler> notification_handler_;
   const std::unique_ptr<SpotlightService> spotlight_service_;
   const std::unique_ptr<SpotlightCrdManager> spotlight_crd_manager_;
diff --git a/chromeos/ash/components/boca/spotlight/spotlight_session_manager_unittest.cc b/chromeos/ash/components/boca/spotlight/spotlight_session_manager_unittest.cc
index 30389a5..dc3e1bf 100644
--- a/chromeos/ash/components/boca/spotlight/spotlight_session_manager_unittest.cc
+++ b/chromeos/ash/components/boca/spotlight/spotlight_session_manager_unittest.cc
@@ -40,6 +40,7 @@
 
 constexpr char kDeviceId[] = "device-id";
 constexpr char kGaiaId[] = "123";
+constexpr char kRobotEmail[] = "robot@gmail.com";
 constexpr char kSessionId[] = "session-id";
 constexpr char kSpotlightConnectionCode[] = "456";
 constexpr char kUserEmail[] = "cat@gmail.com";
@@ -97,14 +98,11 @@
 
 class MockSpotlightCrdManager : public SpotlightCrdManager {
  public:
-  MOCK_METHOD(void,
-              OnSessionStarted,
-              (const std::string& teacher_email),
-              (override));
   MOCK_METHOD(void, OnSessionEnded, (), (override));
   MOCK_METHOD(void,
               InitiateSpotlightSession,
-              (InitiateSpotlightSessionCallback callback),
+              (InitiateSpotlightSessionCallback callback,
+               const std::string& requester_email),
               (override));
   MOCK_METHOD(void,
               ShowPersistentNotification,
@@ -129,8 +127,10 @@
  public:
   SpotlightSessionManagerTest() = default;
   void SetUp() override {
-    scoped_feature_list_.InitWithFeatures({ash::features::kBocaSpotlight},
-                                          /*disabled_features=*/{});
+    scoped_feature_list_.InitWithFeatures(
+        {ash::features::kBocaSpotlight,
+         ash::features::kBocaSpotlightRobotRequester},
+        /*disabled_features=*/{});
 
     // Set up global BocaAppClient's mock.
     boca_app_client_ = std::make_unique<NiceMock<MockBocaAppClient>>();
@@ -164,6 +164,9 @@
  protected:
   base::test::SingleThreadTaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+  base::test::ScopedFeatureList& scoped_feature_list() {
+    return scoped_feature_list_;
+  }
   MockSessionManager* session_manager() { return session_manager_.get(); }
   MockSpotlightService* spotlight_service() { return spotlight_service_; }
   MockSpotlightCrdManager* spotlight_crd_manager() {
@@ -183,7 +186,6 @@
 TEST_F(SpotlightSessionManagerTest, OnSessionStarted) {
   ::boca::UserIdentity producer;
   producer.set_email(kUserEmail);
-  EXPECT_CALL(*spotlight_crd_manager(), OnSessionStarted).Times(1);
   spotlight_session_manager_->OnSessionStarted(kSessionId, producer);
 }
 
@@ -192,7 +194,13 @@
   spotlight_session_manager_->OnSessionEnded(kSessionId);
 }
 
-TEST_F(SpotlightSessionManagerTest, IniatesSpotlightSessionWhenRequested) {
+TEST_F(
+    SpotlightSessionManagerTest,
+    InitiatesSpotlightSessionWithTeacherEmailWhenBocaSpotlightRobotRequesterDisabled) {
+  scoped_feature_list().Reset();
+  scoped_feature_list().InitWithFeatures(
+      {ash::features::kBocaSpotlight},
+      /*disabled_features=*/{ash::features::kBocaSpotlightRobotRequester});
   base::HistogramTester histograms;
 
   ::boca::StudentDevice device;
@@ -205,7 +213,90 @@
   activities.emplace(kGaiaId, status);
 
   // Expect CRD to return an connection code.
-  EXPECT_CALL(*spotlight_crd_manager(), InitiateSpotlightSession)
+  EXPECT_CALL(*spotlight_crd_manager(), InitiateSpotlightSession(_, kUserEmail))
+      .WillOnce(WithArg<0>(Invoke([&](auto callback) {
+        std::move(callback).Run(kSpotlightConnectionCode);
+      })));
+  // Expect sending the code to server.
+  EXPECT_CALL(*spotlight_service(),
+              RegisterScreen(kSpotlightConnectionCode, kTestBaseUrl, _))
+      .WillOnce(WithArg<2>(Invoke(
+          [&](auto callback) { std::move(callback).Run(base::ok(true)); })));
+  // Expect persistent notification to show after countdown.
+  EXPECT_CALL(*spotlight_crd_manager(),
+              ShowPersistentNotification(kUserFullName))
+      .Times(1);
+  EXPECT_CALL(*session_manager(), LoadCurrentSession(false)).Times(1);
+
+  ::boca::UserIdentity producer;
+  producer.set_email(kUserEmail);
+  producer.set_full_name(kUserFullName);
+  spotlight_session_manager_->OnSessionStarted(kSessionId, producer);
+  spotlight_session_manager_->OnConsumerActivityUpdated(activities);
+  task_environment_.FastForwardBy(kTestNotificationDuration);
+
+  histograms.ExpectTotalCount(kOnRegisterScreenRequestSentErrorCodeUmaPath, 0);
+}
+
+TEST_F(SpotlightSessionManagerTest,
+       InitiatesSpotlightSessionWithServiceAccountWhenProvided) {
+  base::HistogramTester histograms;
+
+  ::boca::StudentDevice device;
+  device.mutable_view_screen_config()->set_view_screen_state(
+      ::boca::ViewScreenConfig::REQUESTED);
+  device.mutable_view_screen_config()
+      ->mutable_view_screen_requester()
+      ->mutable_service_account()
+      ->set_email(kRobotEmail);
+  ::boca::StudentStatus status;
+  status.mutable_devices()->emplace(kDeviceId, device);
+
+  std::map<std::string, ::boca::StudentStatus> activities;
+  activities.emplace(kGaiaId, status);
+
+  // Expect CRD to return an connection code.
+  EXPECT_CALL(*spotlight_crd_manager(),
+              InitiateSpotlightSession(_, kRobotEmail))
+      .WillOnce(WithArg<0>(Invoke([&](auto callback) {
+        std::move(callback).Run(kSpotlightConnectionCode);
+      })));
+  // Expect sending the code to server.
+  EXPECT_CALL(*spotlight_service(),
+              RegisterScreen(kSpotlightConnectionCode, kTestBaseUrl, _))
+      .WillOnce(WithArg<2>(Invoke(
+          [&](auto callback) { std::move(callback).Run(base::ok(true)); })));
+  // Expect persistent notification to show after countdown.
+  EXPECT_CALL(*spotlight_crd_manager(),
+              ShowPersistentNotification(kUserFullName))
+      .Times(1);
+  EXPECT_CALL(*session_manager(), LoadCurrentSession(false)).Times(1);
+
+  ::boca::UserIdentity producer;
+  producer.set_email(kUserEmail);
+  producer.set_full_name(kUserFullName);
+  spotlight_session_manager_->OnSessionStarted(kSessionId, producer);
+  spotlight_session_manager_->OnConsumerActivityUpdated(activities);
+  task_environment_.FastForwardBy(kTestNotificationDuration);
+
+  histograms.ExpectTotalCount(kOnRegisterScreenRequestSentErrorCodeUmaPath, 0);
+}
+
+TEST_F(SpotlightSessionManagerTest,
+       InitiatesSpotlightSessionUsesTeacherEmailWhenServiceAccountIsEmpty) {
+  base::HistogramTester histograms;
+
+  ::boca::StudentDevice device;
+  device.mutable_view_screen_config()->set_view_screen_state(
+      ::boca::ViewScreenConfig::REQUESTED);
+  ::boca::StudentStatus status;
+  status.mutable_devices()->emplace(kDeviceId, device);
+
+  std::map<std::string, ::boca::StudentStatus> activities;
+  activities.emplace(kGaiaId, status);
+
+  // Expect CRD to return an connection code.
+  EXPECT_CALL(*spotlight_crd_manager(), InitiateSpotlightSession(_, kUserEmail))
       .WillOnce(WithArg<0>(Invoke([&](auto callback) {
         std::move(callback).Run(kSpotlightConnectionCode);
       })));
diff --git a/chromeos/ui/frame/caption_buttons/snap_controller.h b/chromeos/ui/frame/caption_buttons/snap_controller.h
index 596d2aaf..b185f90 100644
--- a/chromeos/ui/frame/caption_buttons/snap_controller.h
+++ b/chromeos/ui/frame/caption_buttons/snap_controller.h
@@ -48,7 +48,6 @@
   enum class SnapRequestSource {
     kSnapButton,
     kWindowLayoutMenu,
-    kFromLacrosSnapButtonOrWindowLayoutMenu,
   };
 
   virtual ~SnapController();
diff --git a/clank b/clank
index de8849c..dfbdf5e 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit de8849c98f8b6f841b915b569f38ac6c7e3cbf77
+Subproject commit dfbdf5ea48d8bb96bb4fd791866c160bd6b6d3e1
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 9d9799773..1957811b 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -338,7 +338,7 @@
     "integrators/optimization_guide/autofill_optimization_guide.cc",
     "integrators/optimization_guide/autofill_optimization_guide.h",
     "integrators/password_form_classification.h",
-    "integrators/password_manager/autofill_password_manager_delegate.h",
+    "integrators/password_manager/password_manager_delegate.h",
     "integrators/plus_addresses/autofill_plus_address_delegate.h",
     "integrators/touch_to_fill/touch_to_fill_delegate.h",
     "logging/log_buffer_submitter.cc",
@@ -1043,8 +1043,8 @@
     "integrators/identity_credential/mock_identity_credential_delegate.h",
     "integrators/optimization_guide/mock_autofill_optimization_guide.cc",
     "integrators/optimization_guide/mock_autofill_optimization_guide.h",
-    "integrators/password_manager/mock_autofill_password_manager_delegate.cc",
-    "integrators/password_manager/mock_autofill_password_manager_delegate.h",
+    "integrators/password_manager/mock_password_manager_delegate.cc",
+    "integrators/password_manager/mock_password_manager_delegate.h",
     "integrators/plus_addresses/mock_autofill_plus_address_delegate.cc",
     "integrators/plus_addresses/mock_autofill_plus_address_delegate.h",
     "logging/stub_log_manager.cc",
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc
index 105f820..93c418f 100644
--- a/components/autofill/core/browser/autofill_field.cc
+++ b/components/autofill/core/browser/autofill_field.cc
@@ -150,6 +150,13 @@
 // want to prioritize local heuristics over the autocomplete type.
 bool PreferHeuristicOverHtml(FieldType heuristic_type,
                              HtmlFieldType html_type) {
+  if (base::FeatureList::IsEnabled(
+          features::kAutofillEnableEmailOrLoyaltyCardsFilling) &&
+      heuristic_type == EMAIL_OR_LOYALTY_MEMBERSHIP_ID &&
+      html_type == HtmlFieldType::kEmail) {
+    return true;
+  }
+
   return base::Contains(kAutofillHeuristicsVsHtmlOverrides,
                         std::make_pair(heuristic_type, html_type));
 }
@@ -161,6 +168,12 @@
 // can help the server to "learn" the correct classification for these fields.
 bool PreferHeuristicOverServer(FieldType heuristic_type,
                                FieldType server_type) {
+  if (base::FeatureList::IsEnabled(
+          features::kAutofillEnableEmailOrLoyaltyCardsFilling) &&
+      heuristic_type == EMAIL_OR_LOYALTY_MEMBERSHIP_ID &&
+      server_type == EMAIL_ADDRESS) {
+    return true;
+  }
   // Until we gain confidence in the precision of AutofillAI predictions, they
   // should not overrule local heuristics. The AutofillAI prediction itself can
   // always be retrieved via `GetAutofillAiServerTypePredictions`.
diff --git a/components/autofill/core/browser/autofill_field_unittest.cc b/components/autofill/core/browser/autofill_field_unittest.cc
index 3da2c68..2e11e75 100644
--- a/components/autofill/core/browser/autofill_field_unittest.cc
+++ b/components/autofill/core/browser/autofill_field_unittest.cc
@@ -322,6 +322,10 @@
     : public testing::TestWithParam<AutofillLocalHeuristicsOverridesParams> {
  public:
   AutofillLocalHeuristicsOverridesTest() = default;
+
+ private:
+  base::test::ScopedFeatureList feature_{
+      features::kAutofillEnableEmailOrLoyaltyCardsFilling};
 };
 
 // Tests the correctness of local heuristic overrides while computing the
@@ -418,6 +422,18 @@
             .heuristic_type = ADDRESS_HOME_OVERFLOW,
             .expected_result = ADDRESS_HOME_OVERFLOW,
             .expected_source = AutofillPredictionSource::kHeuristics},
+        AutofillLocalHeuristicsOverridesParams{
+            .html_field_type = HtmlFieldType::kUnrecognized,
+            .server_type = EMAIL_ADDRESS,
+            .heuristic_type = EMAIL_OR_LOYALTY_MEMBERSHIP_ID,
+            .expected_result = EMAIL_OR_LOYALTY_MEMBERSHIP_ID,
+            .expected_source = AutofillPredictionSource::kHeuristics},
+        AutofillLocalHeuristicsOverridesParams{
+            .html_field_type = HtmlFieldType::kEmail,
+            .server_type = NO_SERVER_DATA,
+            .heuristic_type = EMAIL_OR_LOYALTY_MEMBERSHIP_ID,
+            .expected_result = EMAIL_OR_LOYALTY_MEMBERSHIP_ID,
+            .expected_source = AutofillPredictionSource::kHeuristics},
         // Test non-override behaviour.
         AutofillLocalHeuristicsOverridesParams{
             .html_field_type = HtmlFieldType::kStreetAddress,
diff --git a/components/autofill/core/browser/form_parsing/email_field_parser.cc b/components/autofill/core/browser/form_parsing/email_field_parser.cc
index 7115765..344be5b 100644
--- a/components/autofill/core/browser/form_parsing/email_field_parser.cc
+++ b/components/autofill/core/browser/form_parsing/email_field_parser.cc
@@ -7,6 +7,7 @@
 #include "base/feature_list.h"
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/data_quality/validation.h"
+#include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
 #include "components/autofill/core/browser/form_parsing/regex_patterns.h"
 #include "components/autofill/core/common/autofill_features.h"
@@ -19,9 +20,23 @@
     ParsingContext& context,
     AutofillScanner* scanner) {
   std::optional<FieldAndMatchInfo> match;
-
-  if (ParseField(context, scanner, "EMAIL_ADDRESS", &match)) {
-    return std::make_unique<EmailFieldParser>(std::move(*match));
+  const size_t saved_cursor = scanner->CursorPosition();
+  // Try parsing an email field.
+  const bool parsed_email =
+      ParseField(context, scanner, "EMAIL_ADDRESS", &match);
+  if (parsed_email) {
+    // Try parsing the same field as a loyalty card field.
+    scanner->RewindTo(saved_cursor);
+    const bool parsed_loyalty_card =
+        base::FeatureList::IsEnabled(
+            features::kAutofillEnableEmailOrLoyaltyCardsFilling) &&
+        ParseField(context, scanner, "LOYALTY_MEMBERSHIP_ID", &match);
+    if (parsed_loyalty_card) {
+      return std::make_unique<EmailFieldParser>(std::move(*match),
+                                                EMAIL_OR_LOYALTY_MEMBERSHIP_ID);
+    }
+    scanner->Advance();
+    return std::make_unique<EmailFieldParser>(std::move(*match), EMAIL_ADDRESS);
   }
 
   // TODO(crbug.com/361560365): Consider moving this into the JSON files once
@@ -35,20 +50,23 @@
     // Since this is either a placeholder or a label match, it's technically not
     // necessarily a high quality label match. However, since this logic
     // predates the low/high quality label distinction, its behavior was kept.
-    return std::make_unique<EmailFieldParser>(FieldAndMatchInfo{
-        field,
-        {.matched_attribute = MatchInfo::MatchAttribute::kHighQualityLabel}});
+    return std::make_unique<EmailFieldParser>(
+        FieldAndMatchInfo{field,
+                          {.matched_attribute =
+                               MatchInfo::MatchAttribute::kHighQualityLabel}},
+        EMAIL_ADDRESS);
   }
 
   return nullptr;
 }
 
-EmailFieldParser::EmailFieldParser(FieldAndMatchInfo match)
-    : match_(std::move(match)) {}
+EmailFieldParser::EmailFieldParser(FieldAndMatchInfo match,
+                                   FieldType email_type)
+    : match_(std::move(match)), email_type_(email_type) {}
 
 void EmailFieldParser::AddClassifications(
     FieldCandidatesMap& field_candidates) const {
-  AddClassification(match_, EMAIL_ADDRESS, kBaseEmailParserScore,
+  AddClassification(match_, email_type_, kBaseEmailParserScore,
                     field_candidates);
 }
 
diff --git a/components/autofill/core/browser/form_parsing/email_field_parser.h b/components/autofill/core/browser/form_parsing/email_field_parser.h
index b0c0245..326de31 100644
--- a/components/autofill/core/browser/form_parsing/email_field_parser.h
+++ b/components/autofill/core/browser/form_parsing/email_field_parser.h
@@ -19,7 +19,7 @@
  public:
   static std::unique_ptr<FormFieldParser> Parse(ParsingContext& context,
                                                 AutofillScanner* scanner);
-  explicit EmailFieldParser(FieldAndMatchInfo match);
+  explicit EmailFieldParser(FieldAndMatchInfo match, FieldType email_type);
 
   EmailFieldParser(const EmailFieldParser&) = delete;
   EmailFieldParser& operator=(const EmailFieldParser&) = delete;
@@ -29,6 +29,10 @@
 
  private:
   FieldAndMatchInfo match_;
+  // Email related types e.g. email-only or "email or loyalty card" fields.
+  // In particular, it can not have the joint email address/username type as
+  // value.
+  const FieldType email_type_;
 };
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/form_parsing/email_field_parser_unittest.cc b/components/autofill/core/browser/form_parsing/email_field_parser_unittest.cc
index c7322aa8..519e685c 100644
--- a/components/autofill/core/browser/form_parsing/email_field_parser_unittest.cc
+++ b/components/autofill/core/browser/form_parsing/email_field_parser_unittest.cc
@@ -15,7 +15,14 @@
 class EmailFieldParserTest : public FormFieldParserTestBase,
                              public ::testing::Test {
  public:
-  EmailFieldParserTest() = default;
+  EmailFieldParserTest() {
+    feature_list_.InitWithFeatures(
+        /*enabled_features=*/{features::kAutofillParseEmailLabelAndPlaceholder,
+                              features::kAutofillEnableLoyaltyCardsFilling,
+                              features::
+                                  kAutofillEnableEmailOrLoyaltyCardsFilling},
+        /*disabled_features=*/{});
+  }
   EmailFieldParserTest(const EmailFieldParserTest&) = delete;
   EmailFieldParserTest& operator=(const EmailFieldParserTest&) = delete;
 
@@ -26,8 +33,7 @@
   }
 
  private:
-  base::test::ScopedFeatureList feature_list_{
-      features::kAutofillParseEmailLabelAndPlaceholder};
+  base::test::ScopedFeatureList feature_list_;
 };
 
 // Tests that a field whose label has the format of an email address is parsed
@@ -38,6 +44,15 @@
   ClassifyAndVerify(ParseResult::kParsed);
 }
 
+// Tests that a field that accepts email or loyalty card fields are parsed as
+// `EMAIL_OR_LOYALTY_MEMBERSHIP_ID`.
+TEST_F(EmailFieldParserTest, ParseEmailOrLoyaltyCardAddressLabel) {
+  AddTextFormFieldData(/*name=*/"email-or-loyalty-card",
+                       /*label=*/"email-or-loyalty-card",
+                       EMAIL_OR_LOYALTY_MEMBERSHIP_ID);
+  ClassifyAndVerify(ParseResult::kParsed);
+}
+
 // Tests that a field whose placeholder has the format of an email address is
 // parsed as `EMAIL_ADDRESS`.
 TEST_F(EmailFieldParserTest, ParseEmailAddressPlaceholder) {
diff --git a/components/autofill/core/browser/form_parsing/form_field_parser.cc b/components/autofill/core/browser/form_parsing/form_field_parser.cc
index a4e3460..4c12440 100644
--- a/components/autofill/core/browser/form_parsing/form_field_parser.cc
+++ b/components/autofill/core/browser/form_parsing/form_field_parser.cc
@@ -313,6 +313,11 @@
     permitted_single_field_types.insert(LOYALTY_MEMBERSHIP_ID);
   }
 
+  if (base::FeatureList::IsEnabled(
+          features::kAutofillEnableEmailOrLoyaltyCardsFilling)) {
+    permitted_single_field_types.insert(EMAIL_OR_LOYALTY_MEMBERSHIP_ID);
+  }
+
   // For historic reasons email addresses are only retained if they appear in
   // a <form> tag. It's unclear whether that's necessary.
   FieldTypeSet permitted_single_field_types_in_form{EMAIL_ADDRESS};
@@ -398,13 +403,6 @@
   ParseFormFieldsPass(IbanFieldParser::Parse, context, processed_fields,
                       field_candidates);
 
-  if (base::FeatureList::IsEnabled(
-          features::kAutofillEnableLoyaltyCardsFilling)) {
-    // Loyalty Cards pass.
-    ParseFormFieldsPass(LoyaltyFieldParser::Parse, context, processed_fields,
-                        field_candidates);
-  }
-
   if (AddressFieldParser::IsStandaloneZipSupported(context.client_country)) {
     // In some countries we observe address forms that are particularly small
     // (e.g. only a zip code.)
@@ -413,6 +411,21 @@
   }
 }
 
+void FormFieldParser::ParseStandaloneLoyaltyCardFields(
+    ParsingContext& context,
+    const std::vector<std::unique_ptr<AutofillField>>& fields,
+    FieldCandidatesMap& field_candidates) {
+  std::vector<raw_ptr<AutofillField, VectorExperimental>> processed_fields =
+      RemoveCheckableFields(fields);
+
+  if (base::FeatureList::IsEnabled(
+          features::kAutofillEnableLoyaltyCardsFilling)) {
+    // Loyalty Cards pass.
+    ParseFormFieldsPass(LoyaltyFieldParser::Parse, context, processed_fields,
+                        field_candidates);
+  }
+}
+
 void FormFieldParser::ParseStandaloneCVCFields(
     ParsingContext& context,
     const std::vector<std::unique_ptr<AutofillField>>& fields,
@@ -812,10 +825,4 @@
   return match_type.contains(type);
 }
 
-// static
-bool FormFieldParser::IsSingleFieldParseableType(FieldType field_type) {
-  return field_type == MERCHANT_PROMO_CODE || field_type == IBAN_VALUE ||
-         field_type == CREDIT_CARD_STANDALONE_VERIFICATION_CODE;
-}
-
 }  // namespace autofill
diff --git a/components/autofill/core/browser/form_parsing/form_field_parser.h b/components/autofill/core/browser/form_parsing/form_field_parser.h
index 68866b54..b645d0f 100644
--- a/components/autofill/core/browser/form_parsing/form_field_parser.h
+++ b/components/autofill/core/browser/form_parsing/form_field_parser.h
@@ -169,6 +169,15 @@
       const std::vector<std::unique_ptr<AutofillField>>& fields,
       FieldCandidatesMap& field_candidates);
 
+  // Search for standalone loyalty card fields inside `fields`. Standalone
+  // loyalty card fields are fields that should exclusively accept loyalty card
+  // numbers, differentiating them from multi-purpose input fields that might
+  // also accept emails or other data types
+  static void ParseStandaloneLoyaltyCardFields(
+      ParsingContext& context,
+      const std::vector<std::unique_ptr<AutofillField>>& fields,
+      FieldCandidatesMap& field_candidates);
+
   // Search for standalone CVC fields inside `fields`. Standalone CVC fields
   // are CVC fields that should appear without any credit card field or email
   // address in the same form. Each field has a derived unique name that is
@@ -275,9 +284,6 @@
                                      DenseSet<FormControlType> match_type);
 
  protected:
-  // Returns true if |field_type| is a single field parseable type.
-  static bool IsSingleFieldParseableType(FieldType field_type);
-
   // Derived classes must implement this interface to supply field type
   // information.  |ParseFormFields| coordinates the parsing and extraction
   // of types from an input vector of |AutofillField| objects and delegates
diff --git a/components/autofill/core/browser/form_parsing/form_field_parser_unittest.cc b/components/autofill/core/browser/form_parsing/form_field_parser_unittest.cc
index 75d31601..834e0ec 100644
--- a/components/autofill/core/browser/form_parsing/form_field_parser_unittest.cc
+++ b/components/autofill/core/browser/form_parsing/form_field_parser_unittest.cc
@@ -72,6 +72,15 @@
     return field_candidates_map_.size();
   }
 
+  int ParseStandaloneLoyaltyCardFields() {
+    ParsingContext context(GeoIpCountryCode(""), LanguageCode(""),
+                           GetActivePatternFile().value(),
+                           GetActiveRegexFeatures());
+    FormFieldParser::ParseStandaloneLoyaltyCardFields(context, fields_,
+                                                      field_candidates_map_);
+    return field_candidates_map_.size();
+  }
+
   // FormFieldParserTestBase:
   // This function is unused in these unit tests, because FormFieldParser is not
   // a parser itself, but the infrastructure combining them.
@@ -246,19 +255,40 @@
 // Test that `ParseSingleFields` parses a single loyalty card field.
 // LOYALTY_MEMBERSHIP_ID is allowlisted to be produced by the field
 // classification even if the form does not have >= 3 recognized field types.
-TEST_F(FormFieldParserTest, ParseSingleFieldsLoyaltyCard) {
-  base::test::ScopedFeatureList scoped_feature_list_{
-      features::kAutofillEnableLoyaltyCardsFilling};
+TEST_F(FormFieldParserTest, ParseStandaloneLoyaltyCardFields) {
+  base::test::ScopedFeatureList scoped_feature_list_;
+  scoped_feature_list_.InitWithFeatures(
+      {features::kAutofillEnableLoyaltyCardsFilling,
+       features::kAutofillEnableEmailOrLoyaltyCardsFilling},
+      {});
+
   // Parse single field loyalty card.
   AddTextFormFieldData("", "frequent-flyer", LOYALTY_MEMBERSHIP_ID);
-  EXPECT_EQ(1, ParseSingleFields());
+  EXPECT_EQ(1, ParseStandaloneLoyaltyCardFields());
   TestClassificationExpectations();
 
   // Don't parse other fields.
   // UNKNOWN_TYPE is used as the expected type, which prevents it from being
   // part of the expectations in `TestClassificationExpectations()`.
   AddTextFormFieldData("", "Address line 1", UNKNOWN_TYPE);
-  EXPECT_EQ(1, ParseSingleFields());
+  EXPECT_EQ(1, ParseStandaloneLoyaltyCardFields());
+  TestClassificationExpectations();
+}
+
+// Tests that email or loyalty cards fields are parsed as
+// `EMAIL_OR_LOYALTY_MEMBERSHIP_ID`.
+TEST_F(FormFieldParserTest, ParseFormFieldsFieldsEmailOrLoyaltyCard) {
+  base::test::ScopedFeatureList scoped_feature_list_;
+  scoped_feature_list_.InitWithFeatures(
+      {features::kAutofillEnableLoyaltyCardsFilling,
+       features::kAutofillEnableEmailOrLoyaltyCardsFilling},
+      {});
+  AddTextFormFieldData("", "Email Or Loyalty Card",
+                       EMAIL_OR_LOYALTY_MEMBERSHIP_ID);
+  AddTextFormFieldData("", "Password", UNKNOWN_TYPE);
+
+  // `ParseFormFields` should detect the email or loyalty card field.
+  EXPECT_EQ(1, ParseFormFields());
   TestClassificationExpectations();
 }
 
diff --git a/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json b/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json
index 0875d24..1b7104ac 100644
--- a/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json
+++ b/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json
@@ -3939,7 +3939,8 @@
           ],
           "form_control_types": [
             "INPUT_TEXT",
-            "INPUT_SEARCH"
+            "INPUT_SEARCH",
+            "INPUT_NUMBER"
           ]
         }
       ]
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index 60165eb..d468e01 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -692,6 +692,11 @@
       FormFieldParser::ParseStandaloneEmailFields(context, fields_,
                                                   field_type_map);
     }
+    // Try parsing standalone loyalty card fields after an attempt has been
+    // made to parse multi-purpose input fields e.g. email or loyalty number
+    // fields.
+    FormFieldParser::ParseStandaloneLoyaltyCardFields(context, fields_,
+                                                      field_type_map);
   }
   return field_type_map;
 }
diff --git a/components/autofill/core/browser/foundations/autofill_client.cc b/components/autofill/core/browser/foundations/autofill_client.cc
index 5a4c500..1cf13d66 100644
--- a/components/autofill/core/browser/foundations/autofill_client.cc
+++ b/components/autofill/core/browser/foundations/autofill_client.cc
@@ -15,7 +15,7 @@
 #include "components/autofill/core/browser/integrators/autofill_ai/autofill_ai_delegate.h"
 #include "components/autofill/core/browser/integrators/compose/autofill_compose_delegate.h"
 #include "components/autofill/core/browser/integrators/identity_credential/identity_credential_delegate.h"
-#include "components/autofill/core/browser/integrators/password_manager/autofill_password_manager_delegate.h"
+#include "components/autofill/core/browser/integrators/password_manager/password_manager_delegate.h"
 #include "components/autofill/core/browser/integrators/plus_addresses/autofill_plus_address_delegate.h"
 #include "components/autofill/core/browser/payments/credit_card_access_manager.h"
 #include "components/autofill/core/browser/studies/autofill_ablation_study.h"
@@ -93,7 +93,7 @@
   return nullptr;
 }
 
-AutofillPasswordManagerDelegate* AutofillClient::GetPasswordManagerDelegate() {
+PasswordManagerDelegate* AutofillClient::GetPasswordManagerDelegate() {
   return nullptr;
 }
 
diff --git a/components/autofill/core/browser/foundations/autofill_client.h b/components/autofill/core/browser/foundations/autofill_client.h
index 684807c..a52a667 100644
--- a/components/autofill/core/browser/foundations/autofill_client.h
+++ b/components/autofill/core/browser/foundations/autofill_client.h
@@ -27,7 +27,7 @@
 #include "components/autofill/core/browser/integrators/fast_checkout/fast_checkout_client.h"
 #include "components/autofill/core/browser/integrators/identity_credential/identity_credential_delegate.h"
 #include "components/autofill/core/browser/integrators/password_form_classification.h"
-#include "components/autofill/core/browser/integrators/password_manager/autofill_password_manager_delegate.h"
+#include "components/autofill/core/browser/integrators/password_manager/password_manager_delegate.h"
 #include "components/autofill/core/browser/suggestions/suggestion.h"
 #include "components/autofill/core/browser/suggestions/suggestion_hiding_reason.h"
 #include "components/autofill/core/browser/suggestions/suggestion_type.h"
@@ -326,8 +326,8 @@
   // the window of this tab.
   virtual AutofillPlusAddressDelegate* GetPlusAddressDelegate();
 
-  // Returns the `AutofillPasswordManagerDelegate`.
-  virtual AutofillPasswordManagerDelegate* GetPasswordManagerDelegate();
+  // Returns the `PasswordManagerDelegate`.
+  virtual PasswordManagerDelegate* GetPasswordManagerDelegate();
 
   // TODO(crbug.com/365494310): Move these methods to a plus-address-specific
   // client class.
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager.cc b/components/autofill/core/browser/foundations/browser_autofill_manager.cc
index 0af868e..9be15007 100644
--- a/components/autofill/core/browser/foundations/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/foundations/browser_autofill_manager.cc
@@ -96,7 +96,7 @@
 #include "components/autofill/core/browser/geo/phone_number_i18n.h"
 #include "components/autofill/core/browser/integrators/compose/autofill_compose_delegate.h"
 #include "components/autofill/core/browser/integrators/optimization_guide/autofill_optimization_guide.h"
-#include "components/autofill/core/browser/integrators/password_manager/autofill_password_manager_delegate.h"
+#include "components/autofill/core/browser/integrators/password_manager/password_manager_delegate.h"
 #include "components/autofill/core/browser/logging/log_manager.h"
 #include "components/autofill/core/browser/metrics/autofill_in_devtools_metrics.h"
 #include "components/autofill/core/browser/metrics/autofill_metrics.h"
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager.h b/components/autofill/core/browser/foundations/browser_autofill_manager.h
index ccefbad..4bbbf6d 100644
--- a/components/autofill/core/browser/foundations/browser_autofill_manager.h
+++ b/components/autofill/core/browser/foundations/browser_autofill_manager.h
@@ -37,7 +37,7 @@
 #include "components/autofill/core/browser/integrators/autofill_ai/autofill_ai_delegate.h"
 #include "components/autofill/core/browser/integrators/fast_checkout/fast_checkout_delegate.h"
 #include "components/autofill/core/browser/integrators/password_form_classification.h"
-#include "components/autofill/core/browser/integrators/password_manager/autofill_password_manager_delegate.h"
+#include "components/autofill/core/browser/integrators/password_manager/password_manager_delegate.h"
 #include "components/autofill/core/browser/integrators/plus_addresses/autofill_plus_address_delegate.h"
 #include "components/autofill/core/browser/integrators/touch_to_fill/touch_to_fill_delegate.h"
 #include "components/autofill/core/browser/metrics/autofill_metrics.h"
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
index 299f39d..5644ffe 100644
--- a/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
@@ -78,8 +78,8 @@
 #include "components/autofill/core/browser/integrators/identity_credential/mock_identity_credential_delegate.h"
 #include "components/autofill/core/browser/integrators/optimization_guide/mock_autofill_optimization_guide.h"
 #include "components/autofill/core/browser/integrators/password_form_classification.h"
-#include "components/autofill/core/browser/integrators/password_manager/autofill_password_manager_delegate.h"
-#include "components/autofill/core/browser/integrators/password_manager/mock_autofill_password_manager_delegate.h"
+#include "components/autofill/core/browser/integrators/password_manager/mock_password_manager_delegate.h"
+#include "components/autofill/core/browser/integrators/password_manager/password_manager_delegate.h"
 #include "components/autofill/core/browser/integrators/plus_addresses/autofill_plus_address_delegate.h"
 #include "components/autofill/core/browser/integrators/plus_addresses/mock_autofill_plus_address_delegate.h"
 #include "components/autofill/core/browser/metrics/form_events/form_events.h"
@@ -8881,7 +8881,7 @@
       external_delegate()->suggestions().front(), {});
 }
 
-// Fixture setting the BAM's `AutofillPasswordManagerDelegate` to a mock instead
+// Fixture setting the BAM's `PasswordManagerDelegate` to a mock instead
 // of the default `nullptr`. Enables any features if necessary.
 class BrowserAutofillManagerUsingPasswordDelegateTest
     : public BrowserAutofillManagerTest {
@@ -8896,19 +8896,16 @@
     BrowserAutofillManagerTest::TearDown();
   }
 
-  MockAutofillPasswordManagerDelegate& password_delegate() {
-    return *delegate_;
-  }
+  MockPasswordManagerDelegate& password_delegate() { return *delegate_; }
 
  private:
-  std::unique_ptr<AutofillPasswordManagerDelegate> CreatePasswordDelegate() {
-    auto password_delegate =
-        std::make_unique<MockAutofillPasswordManagerDelegate>();
+  std::unique_ptr<PasswordManagerDelegate> CreatePasswordDelegate() {
+    auto password_delegate = std::make_unique<MockPasswordManagerDelegate>();
     delegate_ = password_delegate.get();
     return password_delegate;
   }
 
-  raw_ptr<MockAutofillPasswordManagerDelegate> delegate_ = nullptr;
+  raw_ptr<MockPasswordManagerDelegate> delegate_ = nullptr;
 };
 
 // Test that the BAM queries the password delegate as soon as it's present.
diff --git a/components/autofill/core/browser/foundations/test_autofill_client.h b/components/autofill/core/browser/foundations/test_autofill_client.h
index 950e3e5..153821a0 100644
--- a/components/autofill/core/browser/foundations/test_autofill_client.h
+++ b/components/autofill/core/browser/foundations/test_autofill_client.h
@@ -36,7 +36,7 @@
 #include "components/autofill/core/browser/integrators/fast_checkout/mock_fast_checkout_client.h"
 #include "components/autofill/core/browser/integrators/identity_credential/identity_credential_delegate.h"
 #include "components/autofill/core/browser/integrators/optimization_guide/mock_autofill_optimization_guide.h"
-#include "components/autofill/core/browser/integrators/password_manager/autofill_password_manager_delegate.h"
+#include "components/autofill/core/browser/integrators/password_manager/password_manager_delegate.h"
 #include "components/autofill/core/browser/integrators/plus_addresses/autofill_plus_address_delegate.h"
 #include "components/autofill/core/browser/logging/log_manager.h"
 #include "components/autofill/core/browser/logging/log_router.h"
@@ -194,7 +194,7 @@
     return identity_credential_delegate_.get();
   }
 
-  AutofillPasswordManagerDelegate* GetPasswordManagerDelegate() override {
+  PasswordManagerDelegate* GetPasswordManagerDelegate() override {
     return password_manager_delegate_.get();
   }
 
@@ -598,8 +598,7 @@
   }
 
   void set_password_manager_delegate(
-      std::unique_ptr<AutofillPasswordManagerDelegate>
-          password_manager_delegate) {
+      std::unique_ptr<PasswordManagerDelegate> password_manager_delegate) {
     password_manager_delegate_ = std::move(password_manager_delegate);
   }
 
@@ -623,7 +622,7 @@
   raw_ptr<syncer::SyncService> test_sync_service_ = nullptr;
   std::unique_ptr<AutofillPlusAddressDelegate> plus_address_delegate_;
   std::unique_ptr<IdentityCredentialDelegate> identity_credential_delegate_;
-  std::unique_ptr<AutofillPasswordManagerDelegate> password_manager_delegate_;
+  std::unique_ptr<PasswordManagerDelegate> password_manager_delegate_;
   TestAddressNormalizer test_address_normalizer_;
   std::unique_ptr<::testing::NiceMock<MockAutofillOptimizationGuide>>
       mock_autofill_optimization_guide_ =
diff --git a/components/autofill/core/browser/integrators/README_class.plantuml b/components/autofill/core/browser/integrators/README_class.plantuml
index db0a647..c32c2bd 100644
--- a/components/autofill/core/browser/integrators/README_class.plantuml
+++ b/components/autofill/core/browser/integrators/README_class.plantuml
@@ -14,10 +14,10 @@
 @startuml
 interface "TouchToFillDelegate" as ttfd
 interface "FastCheckoutDelegate" as fcod
-interface "AutofillPasswordManagerDelegate" as pmd
+interface "PasswordManagerDelegate" as pmd
 interface "AutofillSuggestionDelegate" as asd
 class "AutofillExternalDelegate" as aed
-class "AutofillPasswordManagerDelegateImpl" as pmdi
+class "PasswordManagerDelegateImpl" as pmdi
 class "PasswordAutofillManager" as pam
 class "BrowserAutofillManager" as bam {
   + set_fast_checkout_delegate
diff --git a/components/autofill/core/browser/integrators/README_class.png b/components/autofill/core/browser/integrators/README_class.png
index 7bdd15f..a92c1f1 100644
--- a/components/autofill/core/browser/integrators/README_class.png
+++ b/components/autofill/core/browser/integrators/README_class.png
Binary files differ
diff --git a/components/autofill/core/browser/integrators/README_seq_generate.plantuml b/components/autofill/core/browser/integrators/README_seq_generate.plantuml
index 7214cfd..2c7298d 100644
--- a/components/autofill/core/browser/integrators/README_seq_generate.plantuml
+++ b/components/autofill/core/browser/integrators/README_seq_generate.plantuml
@@ -14,16 +14,16 @@
  ' for display.
  '/
 @startuml
-Title: Generating suggestions with AutofillPasswordManagerDelegate
+Title: Generating suggestions with PasswordManagerDelegate
 
 participant BrowserAutofillManager as bam
 participant AutofillClient as afc
-participant AutofillPasswordManagerDelegate as apmd
+participant PasswordManagerDelegate as apmd
 participant PasswordAutofillManager_Frame_1 as pam1
 participant PasswordAutofillManager_Frame_2 as pam2
 
 bam -> afc:  getPasswordManagerDelegate()
-afc --> bam:  AutofillPasswordManagerDelegate
+afc --> bam:  PasswordManagerDelegate
 bam -> apmd:  GetSuggestions(TriggeringField)
 apmd -> apmd: for (apm : all_apm) GetSuggestionsForField(TriggeringField)
 apmd -> pam1: GetSuggestionsForField(TriggeringField)
diff --git a/components/autofill/core/browser/integrators/README_seq_generate.png b/components/autofill/core/browser/integrators/README_seq_generate.png
index 896c187..1df4089 100644
--- a/components/autofill/core/browser/integrators/README_seq_generate.png
+++ b/components/autofill/core/browser/integrators/README_seq_generate.png
Binary files differ
diff --git a/components/autofill/core/browser/integrators/password_manager/mock_autofill_password_manager_delegate.cc b/components/autofill/core/browser/integrators/password_manager/mock_autofill_password_manager_delegate.cc
deleted file mode 100644
index 8e69fd347..0000000
--- a/components/autofill/core/browser/integrators/password_manager/mock_autofill_password_manager_delegate.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2025 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/integrators/password_manager/mock_autofill_password_manager_delegate.h"
-
-namespace autofill {
-
-MockAutofillPasswordManagerDelegate::MockAutofillPasswordManagerDelegate() =
-    default;
-
-MockAutofillPasswordManagerDelegate::~MockAutofillPasswordManagerDelegate() =
-    default;
-
-}  // namespace autofill
diff --git a/components/autofill/core/browser/integrators/password_manager/mock_password_manager_delegate.cc b/components/autofill/core/browser/integrators/password_manager/mock_password_manager_delegate.cc
new file mode 100644
index 0000000..9511701
--- /dev/null
+++ b/components/autofill/core/browser/integrators/password_manager/mock_password_manager_delegate.cc
@@ -0,0 +1,13 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/integrators/password_manager/mock_password_manager_delegate.h"
+
+namespace autofill {
+
+MockPasswordManagerDelegate::MockPasswordManagerDelegate() = default;
+
+MockPasswordManagerDelegate::~MockPasswordManagerDelegate() = default;
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/integrators/password_manager/mock_autofill_password_manager_delegate.h b/components/autofill/core/browser/integrators/password_manager/mock_password_manager_delegate.h
similarity index 61%
rename from components/autofill/core/browser/integrators/password_manager/mock_autofill_password_manager_delegate.h
rename to components/autofill/core/browser/integrators/password_manager/mock_password_manager_delegate.h
index 18cf125..1f030f62 100644
--- a/components/autofill/core/browser/integrators/password_manager/mock_autofill_password_manager_delegate.h
+++ b/components/autofill/core/browser/integrators/password_manager/mock_password_manager_delegate.h
@@ -2,24 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_INTEGRATORS_PASSWORD_MANAGER_MOCK_AUTOFILL_PASSWORD_MANAGER_DELEGATE_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_INTEGRATORS_PASSWORD_MANAGER_MOCK_AUTOFILL_PASSWORD_MANAGER_DELEGATE_H_
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_INTEGRATORS_PASSWORD_MANAGER_MOCK_PASSWORD_MANAGER_DELEGATE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_INTEGRATORS_PASSWORD_MANAGER_MOCK_PASSWORD_MANAGER_DELEGATE_H_
 
-#include "components/autofill/core/browser/integrators/password_manager/autofill_password_manager_delegate.h"
+#include "components/autofill/core/browser/integrators/password_manager/password_manager_delegate.h"
 #include "components/autofill/core/common/password_form_fill_data.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace autofill {
 
-class MockAutofillPasswordManagerDelegate
-    : public AutofillPasswordManagerDelegate {
+class MockPasswordManagerDelegate : public PasswordManagerDelegate {
  public:
-  MockAutofillPasswordManagerDelegate();
-  MockAutofillPasswordManagerDelegate(
-      const MockAutofillPasswordManagerDelegate&) = delete;
-  MockAutofillPasswordManagerDelegate& operator=(
-      const MockAutofillPasswordManagerDelegate&) = delete;
-  ~MockAutofillPasswordManagerDelegate() override;
+  MockPasswordManagerDelegate();
+  MockPasswordManagerDelegate(const MockPasswordManagerDelegate&) = delete;
+  MockPasswordManagerDelegate& operator=(const MockPasswordManagerDelegate&) =
+      delete;
+  ~MockPasswordManagerDelegate() override;
 
   MOCK_METHOD((void),
               ShowSuggestions,
@@ -36,4 +34,4 @@
 
 }  // namespace autofill
 
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_INTEGRATORS_PASSWORD_MANAGER_MOCK_AUTOFILL_PASSWORD_MANAGER_DELEGATE_H_
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_INTEGRATORS_PASSWORD_MANAGER_MOCK_PASSWORD_MANAGER_DELEGATE_H_
diff --git a/components/autofill/core/browser/integrators/password_manager/autofill_password_manager_delegate.h b/components/autofill/core/browser/integrators/password_manager/password_manager_delegate.h
similarity index 81%
rename from components/autofill/core/browser/integrators/password_manager/autofill_password_manager_delegate.h
rename to components/autofill/core/browser/integrators/password_manager/password_manager_delegate.h
index d42673eb..eb64c23 100644
--- a/components/autofill/core/browser/integrators/password_manager/autofill_password_manager_delegate.h
+++ b/components/autofill/core/browser/integrators/password_manager/password_manager_delegate.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 COMPONENTS_AUTOFILL_CORE_BROWSER_INTEGRATORS_PASSWORD_MANAGER_AUTOFILL_PASSWORD_MANAGER_DELEGATE_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_INTEGRATORS_PASSWORD_MANAGER_AUTOFILL_PASSWORD_MANAGER_DELEGATE_H_
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_INTEGRATORS_PASSWORD_MANAGER_PASSWORD_MANAGER_DELEGATE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_INTEGRATORS_PASSWORD_MANAGER_PASSWORD_MANAGER_DELEGATE_H_
 
 #include "components/autofill/core/common/password_form_fill_data.h"
 
@@ -13,9 +13,9 @@
 // Password Manager logic into `AutofillManager::OnAskForForValuesToFill`.
 // If password suggestions are required, the work is performed by the underlying
 // `PasswordAutofillManager`.
-class AutofillPasswordManagerDelegate {
+class PasswordManagerDelegate {
  public:
-  virtual ~AutofillPasswordManagerDelegate() = default;
+  virtual ~PasswordManagerDelegate() = default;
 
   virtual void ShowSuggestions(
       const autofill::TriggeringField& triggering_field) = 0;
@@ -28,4 +28,4 @@
 
 }  // namespace autofill
 
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_INTEGRATORS_PASSWORD_MANAGER_AUTOFILL_PASSWORD_MANAGER_DELEGATE_H_
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_INTEGRATORS_PASSWORD_MANAGER_PASSWORD_MANAGER_DELEGATE_H_
diff --git a/components/autofill/core/browser/ml_model/autofill_ai/autofill_ai_model_executor_impl_unittest.cc b/components/autofill/core/browser/ml_model/autofill_ai/autofill_ai_model_executor_impl_unittest.cc
index 71ea937..757b9de 100644
--- a/components/autofill/core/browser/ml_model/autofill_ai/autofill_ai_model_executor_impl_unittest.cc
+++ b/components/autofill/core/browser/ml_model/autofill_ai/autofill_ai_model_executor_impl_unittest.cc
@@ -29,7 +29,6 @@
 #include "components/optimization_guide/core/optimization_guide_proto_util.h"
 #include "components/optimization_guide/proto/features/common_quality_data.pb.h"
 #include "components/optimization_guide/proto/features/forms_classifications.pb.h"
-#include "components/optimization_guide/proto/features/forms_predictions.pb.h"
 #include "components/prefs/testing_pref_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc
index 9e2c059..e95d10c 100644
--- a/components/exo/shell_surface_base.cc
+++ b/components/exo/shell_surface_base.cc
@@ -24,7 +24,6 @@
 #include "base/containers/flat_set.h"
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
-#include "base/notreached.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
@@ -410,8 +409,7 @@
                 float snap_ratio) {
   chromeos::SnapController::Get()->CommitSnap(
       window, snap_direction, snap_ratio,
-      chromeos::SnapController::SnapRequestSource::
-          kFromLacrosSnapButtonOrWindowLayoutMenu);
+      chromeos::SnapController::SnapRequestSource::kWindowLayoutMenu);
 }
 
 }  // namespace
diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn
index 542bf47..21f19c3 100644
--- a/components/metrics/BUILD.gn
+++ b/components/metrics/BUILD.gn
@@ -348,6 +348,8 @@
   static_library("test_support") {
     testonly = true
     sources = [
+      "test/scoped_metrics_id_provider.cc",
+      "test/scoped_metrics_id_provider.h",
       "test/test_enabled_state_provider.cc",
       "test/test_enabled_state_provider.h",
       "test/test_metrics_log_uploader.cc",
diff --git a/components/metrics/cloned_install_detector.cc b/components/metrics/cloned_install_detector.cc
index f9a7a61..3ea3687b 100644
--- a/components/metrics/cloned_install_detector.cc
+++ b/components/metrics/cloned_install_detector.cc
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/callback_list.h"
+#include "base/check_is_test.h"
 #include "base/functional/bind.h"
 #include "base/location.h"
 #include "base/metrics/histogram_macros.h"
@@ -24,6 +25,26 @@
 
 namespace {
 
+MachineIdProvider* g_machine_id_provider_for_testing = nullptr;
+
+bool HasMachineId() {
+  if (g_machine_id_provider_for_testing) {
+    CHECK_IS_TEST();
+    return g_machine_id_provider_for_testing->HasId();
+  }
+
+  return MachineIdProvider().HasId();
+}
+
+std::string GetMachineId() {
+  if (g_machine_id_provider_for_testing) {
+    CHECK_IS_TEST();
+    return g_machine_id_provider_for_testing->GetMachineId();
+  }
+
+  return MachineIdProvider().GetMachineId();
+}
+
 uint32_t HashRawId(const std::string& value) {
   uint64_t hash = base::HashMetricName(value);
 
@@ -54,15 +75,16 @@
 }
 
 void ClonedInstallDetector::CheckForClonedInstall(PrefService* local_state) {
-  if (!MachineIdProvider::HasId())
+  if (!HasMachineId()) {
     return;
+  }
 
   base::Time check_initiated_timestamp = base::Time::Now();
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE,
       {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
        base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-      base::BindOnce(&MachineIdProvider::GetMachineId),
+      base::BindOnce(&GetMachineId),
       base::BindOnce(&ClonedInstallDetector::SaveMachineId,
                      weak_ptr_factory_.GetWeakPtr(), local_state,
                      check_initiated_timestamp));
@@ -137,6 +159,13 @@
 }
 
 // static
+void ClonedInstallDetector::SetMachineIdProviderForTesting(
+    MachineIdProvider* machine_id_provider) {
+  CHECK_IS_TEST();
+  g_machine_id_provider_for_testing = machine_id_provider;
+}
+
+// static
 void ClonedInstallDetector::RegisterPrefs(PrefRegistrySimple* registry) {
   registry->RegisterBooleanPref(prefs::kMetricsResetIds, false);
   registry->RegisterIntegerPref(prefs::kMetricsMachineId, 0);
diff --git a/components/metrics/cloned_install_detector.h b/components/metrics/cloned_install_detector.h
index 8964d4c..3a1f779 100644
--- a/components/metrics/cloned_install_detector.h
+++ b/components/metrics/cloned_install_detector.h
@@ -15,6 +15,8 @@
 
 namespace metrics {
 
+class MachineIdProvider;
+
 // A struct that holds cloned install related fields in prefs that need to be
 // reported in the system_profile.
 struct ClonedInstallInfo {
@@ -55,7 +57,7 @@
   static void ClearClonedInstallInfo(PrefService* local_state);
 
   // Updates cloned install info fields in |local_state| on reset.
-  static void RecordClonedInstallInfo(PrefService* local_state);
+  void RecordClonedInstallInfo(PrefService* local_state);
 
   // Returns true for the whole session if we detected a cloned install during
   // the construction of a client id.
@@ -76,6 +78,11 @@
   void SaveMachineIdForTesting(PrefService* local_state,
                                const std::string& raw_id);
 
+  // Sets `machine_id_provider` as the global testing provider instance, that
+  // gets used over the default ones used in prod.
+  static void SetMachineIdProviderForTesting(
+      MachineIdProvider* machine_id_provider);
+
  private:
   FRIEND_TEST_ALL_PREFIXES(ClonedInstallDetectorTest, SaveId);
   FRIEND_TEST_ALL_PREFIXES(ClonedInstallDetectorTest, DetectClone);
diff --git a/components/metrics/machine_id_provider.h b/components/metrics/machine_id_provider.h
index adc6cca..64e67433 100644
--- a/components/metrics/machine_id_provider.h
+++ b/components/metrics/machine_id_provider.h
@@ -15,21 +15,22 @@
 // platform.
 class MachineIdProvider {
  public:
-  MachineIdProvider() = delete;
+  MachineIdProvider();
   MachineIdProvider(const MachineIdProvider&) = delete;
   MachineIdProvider& operator=(const MachineIdProvider&) = delete;
+  virtual ~MachineIdProvider();
 
   // Returns true if this platform provides a non-empty GetMachineId(). This is
   // useful to avoid an async call to GetMachineId() on platforms with no
   // implementation.
-  static bool HasId();
+  virtual bool HasId() const;
 
   // Get a string containing machine characteristics, to be used as a machine
   // id. The implementation is split into Windows and non-Windows. The former
   // returns the drive serial number and the latter returns the hardware
   // model name. Should not be called if HasId() returns false.
   // The return value should not be stored to disk or transmitted.
-  static std::string GetMachineId();
+  virtual std::string GetMachineId() const;
 };
 
 }  //  namespace metrics
diff --git a/components/metrics/machine_id_provider_nonwin.cc b/components/metrics/machine_id_provider_nonwin.cc
index c419b312..283f4dc 100644
--- a/components/metrics/machine_id_provider_nonwin.cc
+++ b/components/metrics/machine_id_provider_nonwin.cc
@@ -11,14 +11,18 @@
 
 namespace metrics {
 
+MachineIdProvider::MachineIdProvider() = default;
+
+MachineIdProvider::~MachineIdProvider() = default;
+
 // Checks if hardware model name is available.
-bool MachineIdProvider::HasId() {
+bool MachineIdProvider::HasId() const {
   return !base::SysInfo::HardwareModelName().empty();
 }
 
 // On non-windows, the machine id is based on the hardware model name.
 // This will suffice as users are unlikely to change to the same machine model.
-std::string MachineIdProvider::GetMachineId() {
+std::string MachineIdProvider::GetMachineId() const {
   // Gets hardware model name. (e.g. 'Macbook Pro 16,1', 'iPhone 9,3')
   std::string hardware_model_name = base::SysInfo::HardwareModelName();
 
diff --git a/components/metrics/machine_id_provider_nonwin_unittest.cc b/components/metrics/machine_id_provider_nonwin_unittest.cc
index c701a7d..d54e36b 100644
--- a/components/metrics/machine_id_provider_nonwin_unittest.cc
+++ b/components/metrics/machine_id_provider_nonwin_unittest.cc
@@ -19,14 +19,14 @@
 
   // Should only return a machine ID if the hardware model name is available.
   if (has_machine_name) {
-    const std::string id1 = MachineIdProvider::GetMachineId();
-    EXPECT_TRUE(MachineIdProvider::HasId());
+    const std::string id1 = MachineIdProvider().GetMachineId();
+    EXPECT_TRUE(MachineIdProvider().HasId());
     EXPECT_NE(std::string(), id1);
 
-    const std::string id2 = MachineIdProvider::GetMachineId();
+    const std::string id2 = MachineIdProvider().GetMachineId();
     EXPECT_EQ(id1, id2);
   } else {
-    EXPECT_FALSE(MachineIdProvider::HasId());
+    EXPECT_FALSE(MachineIdProvider().HasId());
   }
 }
 
diff --git a/components/metrics/machine_id_provider_win.cc b/components/metrics/machine_id_provider_win.cc
index f26a7ba..0090f5c 100644
--- a/components/metrics/machine_id_provider_win.cc
+++ b/components/metrics/machine_id_provider_win.cc
@@ -18,15 +18,17 @@
 
 namespace metrics {
 
-// static
-bool MachineIdProvider::HasId() {
+MachineIdProvider::MachineIdProvider() = default;
+
+MachineIdProvider::~MachineIdProvider() = default;
+
+bool MachineIdProvider::HasId() const {
   return true;
 }
 
 // On windows, the machine id is based on the serial number of the drive Chrome
 // is running from.
-// static
-std::string MachineIdProvider::GetMachineId() {
+std::string MachineIdProvider::GetMachineId() const {
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                 base::BlockingType::MAY_BLOCK);
 
diff --git a/components/metrics/machine_id_provider_win_unittest.cc b/components/metrics/machine_id_provider_win_unittest.cc
index 1bc2ffa..77f5e99a 100644
--- a/components/metrics/machine_id_provider_win_unittest.cc
+++ b/components/metrics/machine_id_provider_win_unittest.cc
@@ -9,12 +9,12 @@
 namespace metrics {
 
 TEST(MachineIdProviderWinTest, GetId) {
-  EXPECT_TRUE(MachineIdProvider::HasId());
+  EXPECT_TRUE(MachineIdProvider().HasId());
 
-  const std::string id1 = MachineIdProvider::GetMachineId();
+  const std::string id1 = MachineIdProvider().GetMachineId();
   EXPECT_NE(std::string(), id1);
 
-  const std::string id2 = MachineIdProvider::GetMachineId();
+  const std::string id2 = MachineIdProvider().GetMachineId();
   EXPECT_EQ(id1, id2);
 }
 
diff --git a/components/metrics/metrics_state_manager.cc b/components/metrics/metrics_state_manager.cc
index f4f490f..ff852e9 100644
--- a/components/metrics/metrics_state_manager.cc
+++ b/components/metrics/metrics_state_manager.cc
@@ -505,6 +505,11 @@
   BackUpCurrentClientInfo();
 }
 
+const ClonedInstallDetector& MetricsStateManager::GetClonedInstallDetector()
+    const {
+  return cloned_install_detector_;
+}
+
 void MetricsStateManager::CheckForClonedInstall() {
   cloned_install_detector_.CheckForClonedInstall(local_state_);
 }
@@ -653,7 +658,7 @@
   local_state_->ClearPref(prefs::kMetricsLogRecordId);
   EntropyState::ClearPrefs(local_state_);
 
-  ClonedInstallDetector::RecordClonedInstallInfo(local_state_);
+  cloned_install_detector_.RecordClonedInstallInfo(local_state_);
 
   // Also clear the backed up client info. This is asynchronus; any reads
   // shortly after may retrieve the old ClientInfo from the backup.
diff --git a/components/metrics/metrics_state_manager.h b/components/metrics/metrics_state_manager.h
index f43482f5..2f49e29 100644
--- a/components/metrics/metrics_state_manager.h
+++ b/components/metrics/metrics_state_manager.h
@@ -24,6 +24,10 @@
 class PrefService;
 class PrefRegistrySimple;
 
+namespace metrics_services_manager {
+class MetricsServicesManager;
+}
+
 namespace metrics {
 
 class EnabledStateProvider;
@@ -232,6 +236,7 @@
                            ProvisionalClientId_PersistedAcrossFirstRuns);
   FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, ResetBackup);
   FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, ResetMetricsIDs);
+  friend class ::metrics_services_manager::MetricsServicesManager;
 
   // Designates which entropy source was returned from this class.
   // This is used for testing to validate that we return the correct source
@@ -281,6 +286,12 @@
                       StoreClientInfoCallback store_client_info,
                       LoadClientInfoCallback load_client_info);
 
+  // Returns the ClonedInstallDetector. This is useful in case we're checking
+  // whether an install was detected in this session.
+  // Marked as private (exposed selectively via friend classes) for the metrics
+  // team to be able to control and monitor if/how this function gets called.
+  const ClonedInstallDetector& GetClonedInstallDetector() const;
+
   // Returns a MetricsStateManagerProvider instance and sets its
   // |log_normal_metric_state_.gen| with the provided random seed.
   std::unique_ptr<MetricsProvider> GetProviderAndSetRandomSeedForTesting(
diff --git a/components/metrics/test/scoped_metrics_id_provider.cc b/components/metrics/test/scoped_metrics_id_provider.cc
new file mode 100644
index 0000000..9ae68a2
--- /dev/null
+++ b/components/metrics/test/scoped_metrics_id_provider.cc
@@ -0,0 +1,26 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/test/scoped_metrics_id_provider.h"
+
+#include "components/metrics/cloned_install_detector.h"
+
+namespace metrics {
+
+ScopedMachineIdProvider::ScopedMachineIdProvider() {
+  ClonedInstallDetector::SetMachineIdProviderForTesting(this);
+}
+
+ScopedMachineIdProvider::~ScopedMachineIdProvider() {
+  ClonedInstallDetector::SetMachineIdProviderForTesting(nullptr);
+}
+
+bool ScopedMachineIdProvider::HasId() const {
+  return !machine_id.empty();
+}
+std::string ScopedMachineIdProvider::GetMachineId() const {
+  return machine_id;
+}
+
+}  // namespace metrics
diff --git a/components/metrics/test/scoped_metrics_id_provider.h b/components/metrics/test/scoped_metrics_id_provider.h
new file mode 100644
index 0000000..d3f83d3
--- /dev/null
+++ b/components/metrics/test/scoped_metrics_id_provider.h
@@ -0,0 +1,28 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_METRICS_TEST_SCOPED_METRICS_ID_PROVIDER_H_
+#define COMPONENTS_METRICS_TEST_SCOPED_METRICS_ID_PROVIDER_H_
+
+#include "components/metrics/machine_id_provider.h"
+
+namespace metrics {
+
+// Helper class to automatically set and reset a global `MachineIdProvider`
+// instance in tests, see
+// `ClonedInstallDetector::SetMachineIdProviderForTesting`.
+class ScopedMachineIdProvider : public MachineIdProvider {
+ public:
+  ScopedMachineIdProvider();
+  ~ScopedMachineIdProvider() override;
+
+  bool HasId() const override;
+  std::string GetMachineId() const override;
+
+  std::string machine_id;
+};
+
+}  // namespace metrics
+
+#endif  // COMPONENTS_METRICS_TEST_SCOPED_METRICS_ID_PROVIDER_H_
diff --git a/components/metrics_services_manager/metrics_services_manager.cc b/components/metrics_services_manager/metrics_services_manager.cc
index 2e42ee5..f6791d0 100644
--- a/components/metrics_services_manager/metrics_services_manager.cc
+++ b/components/metrics_services_manager/metrics_services_manager.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/check.h"
+#include "base/check_is_test.h"
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_macros.h"
 #include "components/metrics/dwa/dwa_recorder.h"
@@ -111,6 +112,18 @@
       /*enable_limited_entropy_mode=*/true);
 }
 
+metrics::ClonedInstallDetector*
+MetricsServicesManager::GetClonedInstallDetectorForTesting() {
+  CHECK_IS_TEST();
+  return client_->GetMetricsStateManager()
+      ->cloned_install_detector_for_testing();  // IN-TEST
+}
+
+const metrics::ClonedInstallDetector&
+MetricsServicesManager::GetClonedInstallDetector() const {
+  return client_->GetMetricsStateManager()->GetClonedInstallDetector();
+}
+
 metrics::MetricsServiceClient*
 MetricsServicesManager::GetMetricsServiceClient() {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/components/metrics_services_manager/metrics_services_manager.h b/components/metrics_services_manager/metrics_services_manager.h
index b5eeb68..6a2ec2d 100644
--- a/components/metrics_services_manager/metrics_services_manager.h
+++ b/components/metrics_services_manager/metrics_services_manager.h
@@ -15,12 +15,17 @@
 namespace metrics {
 class MetricsService;
 class MetricsServiceClient;
+class ClonedInstallDetector;
 }  // namespace metrics
 
 namespace metrics::structured {
 class StructuredMetricsService;
 }
 
+namespace search_engines {
+class SearchEngineChoiceServiceClient;
+}
+
 namespace ukm {
 class UkmService;
 }
@@ -120,7 +125,17 @@
   std::unique_ptr<const variations::EntropyProviders>
   CreateEntropyProvidersForTesting();
 
+  // Returns the ClonedInstallDetector associated with the `client_`.
+  metrics::ClonedInstallDetector* GetClonedInstallDetectorForTesting();
+
  private:
+  friend class search_engines::SearchEngineChoiceServiceClient;
+
+  // Returns the ClonedInstallDetector associated with the `client_`.
+  // Marked as private (exposed selectively via friend classes) for the metrics
+  // team to be able to control and monitor if/how this function gets called.
+  const metrics::ClonedInstallDetector& GetClonedInstallDetector() const;
+
   // Returns the MetricsServiceClient, creating it if it hasn't been
   // created yet (and additionally creating the MetricsService in that case).
   metrics::MetricsServiceClient* GetMetricsServiceClient();
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal
index 7062789..f58041b 160000
--- a/components/optimization_guide/internal
+++ b/components/optimization_guide/internal
@@ -1 +1 @@
-Subproject commit 7062789227d77cf3b9d99e973da9b0ecc29056c9
+Subproject commit f58041bc19d8cd401fe481331f0b399ccc3a73a4
diff --git a/components/optimization_guide/proto/BUILD.gn b/components/optimization_guide/proto/BUILD.gn
index 8c63fd5..3253289e 100644
--- a/components/optimization_guide/proto/BUILD.gn
+++ b/components/optimization_guide/proto/BUILD.gn
@@ -24,9 +24,7 @@
     "features/default.proto",
     "features/enhanced_calendar.proto",
     "features/example_for_testing.proto",
-    "features/forms_annotations.proto",
     "features/forms_classifications.proto",
-    "features/forms_predictions.proto",
     "features/history_answer.proto",
     "features/history_query.proto",
     "features/history_query_intent.proto",
diff --git a/components/optimization_guide/proto/features/forms_annotations.proto b/components/optimization_guide/proto/features/forms_annotations.proto
deleted file mode 100644
index 9d85f82..0000000
--- a/components/optimization_guide/proto/features/forms_annotations.proto
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-syntax = "proto3";
-
-package optimization_guide.proto;
-
-import "components/optimization_guide/proto/features/common_quality_data.proto";
-
-import "components/optimization_guide/proto/model_quality_metadata.proto";
-
-option optimize_for = LITE_RUNTIME;
-option java_package = "org.chromium.components.optimization_guide.features.proto";
-
-option java_outer_classname = "FormsAnnotationsProto";
-
-// DO NOT EDIT THIS FILE DIRECTLY!
-//
-// This file is generated in g3 and then synced to Chrome. Instead, please
-// refer to http://go/chrome-intelligence-feature-protos (Google-internal link),
-// and then changes will be synced with Chrome automatically.
-
-// Next ID: 5
-message FormsAnnotationsLoggingData {
-  FormsAnnotationsRequest request = 1;
-
-  FormsAnnotationsResponse response = 2;
-
-  FormsAnnotationsQuality quality = 3;
-
-  ModelExecutionInfo model_execution_info = 4;
-}
-
-message FormsAnnotationsRequest {
-  // The context of the page that the form is on.
-  PageContext page_context = 1;
-
-  // The form to build annotations for.
-  FormData form_data = 4;
-
-  // The current entries in the user annotations database.
-  repeated UserAnnotationsEntry entries = 5;
-}
-
-message FormsAnnotationsResponse {
-  // The user annotations entries that were newly added or updated to the
-  // database. New entries will have 0 as entry id.
-  repeated UserAnnotationsEntry upserted_entries = 1;
-
-  // The user annotations entry IDs that were not changed.
-  repeated int64 unchanged_entry_ids = 2;
-
-  // The user annotations entry IDs that were deleted.
-  repeated int64 deleted_entry_ids = 3;
-}
-
-message FormsAnnotationsQuality {
-  UserFeedback user_feedback = 1;
-
-  // The action the user took when presented with the save prompt.
-  FormsAnnotationsSavePromptAction save_prompt_action = 3;
-}
-
-enum FormsAnnotationsSavePromptAction {
-  FORMS_ANNOTATIONS_SAVE_PROMPT_ACTION_UNSPECIFIED = 0;
-
-  // User explicitly accepted the save prompt.
-  FORMS_ANNOTATIONS_SAVE_PROMPT_ACTION_ACCEPTED = 1;
-
-  // User explicitly rejected the save prompt.
-  FORMS_ANNOTATIONS_SAVE_PROMPT_ACTION_REJECTED = 2;
-}
diff --git a/components/optimization_guide/proto/features/forms_predictions.proto b/components/optimization_guide/proto/features/forms_predictions.proto
deleted file mode 100644
index f5b1271..0000000
--- a/components/optimization_guide/proto/features/forms_predictions.proto
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-syntax = "proto3";
-
-package optimization_guide.proto;
-
-import "components/optimization_guide/proto/features/common_quality_data.proto";
-
-import "components/optimization_guide/proto/model_quality_metadata.proto";
-
-option optimize_for = LITE_RUNTIME;
-option java_package = "org.chromium.components.optimization_guide.features.proto";
-
-option java_outer_classname = "FormsPredictionsProto";
-
-// DO NOT EDIT THIS FILE DIRECTLY!
-//
-// This file is generated in g3 and then synced to Chrome. Instead, please
-// refer to http://go/chrome-intelligence-feature-protos (Google-internal link),
-// and then changes will be synced with Chrome automatically.
-
-// Next ID: 5
-message FormsPredictionsLoggingData {
-  FormsPredictionsRequest request = 1;
-
-  FormsPredictionsResponse response = 2;
-
-  FormsPredictionsQuality quality = 3;
-
-  ModelExecutionInfo model_execution_info = 4;
-}
-
-message FormsPredictionsRequest {
-  // The context of the page that the form is on.
-  PageContext page_context = 1;
-
-  // The form to predict values for. It is expected for the values for each
-  // field to be empty.
-  FormData form_data = 4;
-
-  // The current entries in the user annotations database helpful for filling
-  // out this form.
-  repeated UserAnnotationsEntry entries = 5;
-}
-
-message FormsPredictionsResponse {
-  // The confidence of the prediction. Will be between 0 and 1, inclusive.
-  float confidence = 1;
-
-  // The filled out form.
-  FilledFormData form_data = 2;
-}
-
-message FilledFormData {
-  // The data for each field that was filled out.
-  repeated FilledFormFieldData filled_form_field_data = 1;
-}
-
-message FilledFormFieldData {
-  // The field that was filled out.
-  FormFieldData field_data = 1;
-
-  // The predicted values for the field, allowing multiple predictions.
-  repeated PredictedValue predicted_values = 2;
-
-  // A user-friendly version of the field's label, suitable for display.
-  // If empty or not provided, the original field label should be used.
-  string normalized_label = 3;
-
-  // The index of the field in the request form.
-  int32 request_field_index = 4;
-}
-
-message PredictedValue {
-  string value = 1;
-}
-
-message FormsPredictionsQuality {
-  UserFeedback user_feedback = 1;
-}
diff --git a/components/optimization_guide/proto/model_quality_service.proto b/components/optimization_guide/proto/model_quality_service.proto
index d3f6632..34e82e87 100644
--- a/components/optimization_guide/proto/model_quality_service.proto
+++ b/components/optimization_guide/proto/model_quality_service.proto
@@ -10,9 +10,7 @@
 import "components/optimization_guide/proto/features/compose.proto";
 import "components/optimization_guide/proto/features/default.proto";
 import "components/optimization_guide/proto/features/enhanced_calendar.proto";
-import "components/optimization_guide/proto/features/forms_annotations.proto";
 import "components/optimization_guide/proto/features/forms_classifications.proto";
-import "components/optimization_guide/proto/features/forms_predictions.proto";
 import "components/optimization_guide/proto/features/history_answer.proto";
 import "components/optimization_guide/proto/features/history_query.proto";
 import "components/optimization_guide/proto/features/history_query_intent.proto";
@@ -36,6 +34,8 @@
 // A request to send AI data logs to the model quality server. Data logging for
 // an AI feature with metadata specific to the logging.
 message LogAiDataRequest {
+  reserved 10, 11;
+
   // Information about a feature's AiLoggingData, such as training opt-outs.
   LoggingMetadata logging_metadata = 1;
 
@@ -58,10 +58,6 @@
 
     ProductSpecificationsLoggingData product_specifications = 9;
 
-    FormsAnnotationsLoggingData forms_annotations = 10;
-
-    FormsPredictionsLoggingData forms_predictions = 11;
-
     ModelPrototypingLoggingData model_prototyping = 12;
 
     BlingPrototypingLoggingData bling_prototyping = 14;
diff --git a/components/search_engines/search_engine_choice/search_engine_choice_service.cc b/components/search_engines/search_engine_choice/search_engine_choice_service.cc
index df637f62..5759e42 100644
--- a/components/search_engines/search_engine_choice/search_engine_choice_service.cc
+++ b/components/search_engines/search_engine_choice/search_engine_choice_service.cc
@@ -650,6 +650,12 @@
   regional_capabilities_service_->ClearCountryIdCacheForTesting();  // IN-TEST
 }
 
+SearchEngineChoiceService::Client&
+SearchEngineChoiceService::GetClientForTesting() {
+  CHECK_IS_TEST();
+  return *client_.get();
+}
+
 bool SearchEngineChoiceService::IsDsePropagationAllowedForGuest() const {
   if (client_->IsProfileEligibleForDseGuestPropagation()) {
     return regional_capabilities_service_->IsInEeaCountry();
diff --git a/components/search_engines/search_engine_choice/search_engine_choice_service.h b/components/search_engines/search_engine_choice/search_engine_choice_service.h
index 2ea17e9..3ba2ad3 100644
--- a/components/search_engines/search_engine_choice/search_engine_choice_service.h
+++ b/components/search_engines/search_engine_choice/search_engine_choice_service.h
@@ -62,6 +62,13 @@
 
     // Returns whether Chrome detected in this current run that its data has
     // been transferred / restored to a new device.
+    //
+    // In practice, this function is not reliable on desktop. That's because
+    // "detected in current session" happens asynchronously, so it's possible
+    // to call this function and get a "false" value in a session where it will
+    // end up returning true at some point. And in the next session, "detected
+    // in current session" would be false too. It's possible to miss an actual
+    // true value due to timing of calls to this function.
     virtual bool IsDeviceRestoreDetectedInCurrentSession() = 0;
 
     // Returns whether the search engine choice described in `choice_metadata`
@@ -139,6 +146,10 @@
   // TODO(crbug.com/328040066): Move to `//components/regional_capabilities`.
   void ClearCountryIdCacheForTesting();
 
+  // Returns a reference to the `SearchEngineChoiceService::Client` owned and
+  // used by this service.
+  Client& GetClientForTesting();
+
   // Returns whether the profile is eligible for the default search engine to be
   // used across all guest sessions.
   bool IsDsePropagationAllowedForGuest() const;
diff --git a/components/tabs/BUILD.gn b/components/tabs/BUILD.gn
index a5693a24..db6309f 100644
--- a/components/tabs/BUILD.gn
+++ b/components/tabs/BUILD.gn
@@ -11,7 +11,11 @@
     "public/split_tab_visual_data.h",
     "public/supports_handles.h",
     "public/tab_collection.h",
+    "public/tab_group.h",
+    "public/tab_group_tab_collection.h",
     "public/tab_interface.h",
+    "public/tab_strip_collection.h",
+    "public/unpinned_tab_collection.h",
   ]
 
   # TODO(crbug.com/404296389): Move to the non-public target and refactor
@@ -22,6 +26,7 @@
     "//base",
     "//components/tab_groups",
   ]
+  deps = [ "//ui/gfx/range" ]
 }
 
 source_set("tabs") {
@@ -32,6 +37,10 @@
     "split_tab_visual_data.cc",
     "tab_collection.cc",
     "tab_collection_storage.cc",
+    "tab_group.cc",
+    "tab_group_tab_collection.cc",
+    "tab_strip_collection.cc",
+    "unpinned_tab_collection.cc",
   ]
   deps = [ ":public" ]
 }
@@ -53,5 +62,6 @@
     ":tabs",
     "//testing/gmock",
     "//testing/gtest",
+    "//ui/gfx/range",
   ]
 }
diff --git a/components/tabs/DEPS b/components/tabs/DEPS
index 173322a..3e77572 100644
--- a/components/tabs/DEPS
+++ b/components/tabs/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
   "+components/tab_groups",
+  "+ui/gfx",
 ]
diff --git a/chrome/browser/ui/tabs/tab_group.h b/components/tabs/public/tab_group.h
similarity index 65%
rename from chrome/browser/ui/tabs/tab_group.h
rename to components/tabs/public/tab_group.h
index c8d07e3..a28ee1e 100644
--- a/chrome/browser/ui/tabs/tab_group.h
+++ b/components/tabs/public/tab_group.h
@@ -2,26 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_TABS_TAB_GROUP_H_
-#define CHROME_BROWSER_UI_TABS_TAB_GROUP_H_
+#ifndef COMPONENTS_TABS_PUBLIC_TAB_GROUP_H_
+#define COMPONENTS_TABS_PUBLIC_TAB_GROUP_H_
 
-#include <stddef.h>
-#include <stdint.h>
-
-#include <map>
 #include <memory>
-#include <optional>
 #include <string>
-#include <vector>
 
 #include "base/memory/raw_ptr.h"
-#include "base/types/pass_key.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
 #include "ui/gfx/range/range.h"
 
-class TabGroupController;
-class TabGroupModel;
+namespace tabs {
+
+class TabGroupTabCollection;
+class TabInterface;
+
+}  // namespace tabs
 
 // The metadata and state of a tab group. This handles state changes that are
 // specific to tab groups and not grouped tabs. The latter (i.e. the groupness
@@ -30,7 +27,7 @@
 // handles similar notifications for tab group state changes.
 class TabGroup {
  public:
-  TabGroup(TabGroupController* controller,
+  TabGroup(tabs::TabGroupTabCollection* collection,
            const tab_groups::TabGroupId& id,
            const tab_groups::TabGroupVisualData& visual_data);
   ~TabGroup();
@@ -49,18 +46,8 @@
   void SetGroupIsClosing(bool is_closing);
   bool IsGroupClosing() { return is_closing_; }
 
-  // Returns a user-visible string describing the contents of the group, such as
-  // "Google Search and 3 other tabs". Used for accessibly describing the group,
-  // as well as for displaying in context menu items and tooltips when the group
-  // is unnamed.
-  std::u16string GetContentString() const;
-
-  // Updates internal bookkeeping for group contents, and notifies the
-  // controller that contents changed when a tab is added.
+  // Updates internal bookkeeping for group contents.
   void AddTab();
-
-  // Updates internal bookkeeping for group contents, and notifies the
-  // controller that contents changed when a tab is removed.
   void RemoveTab();
 
   // The number of tabs in this group, determined by AddTab() and
@@ -73,15 +60,13 @@
   // Returns whether the user has explicitly set the visual data themselves.
   bool IsCustomized() const;
 
-  // Gets the model index of this group's first tab, or nullopt if it is
-  // empty. Similar to ListTabs() it traverses through TabStripModel's
-  // tabs. Unlike ListTabs() this is always safe to call.
-  std::optional<int> GetFirstTab() const;
+  // Get the first tab in the Tab Group or nullptr if the group is currently
+  // empty.
+  tabs::TabInterface* GetFirstTab() const;
 
-  // Gets the model index of this group's last tab, or nullopt if it is
-  // empty. Similar to ListTabs() it traverses through TabStripModel's
-  // tabs. Unlike ListTabs() this is always safe to call.
-  std::optional<int> GetLastTab() const;
+  // Get the last tab in the Tab Group or nullptr if the group is currently
+  // empty.
+  tabs::TabInterface* GetLastTab() const;
 
   // Returns the range of tab model indices this group contains. Notably
   // does not rely on the TabGroup's internal metadata, but rather
@@ -102,13 +87,9 @@
   // steps.
   gfx::Range ListTabs() const;
 
-  void set_controller(TabGroupController* controller,
-                      base::PassKey<TabGroupModel>) {
-    controller_ = controller;
-  }
-
  private:
-  raw_ptr<TabGroupController> controller_;
+  // The collection that owns the TabGroup.
+  raw_ptr<tabs::TabGroupTabCollection> collection_;
 
   tab_groups::TabGroupId id_;
   std::unique_ptr<tab_groups::TabGroupVisualData> visual_data_;
@@ -119,4 +100,4 @@
   bool is_customized_ = false;
 };
 
-#endif  // CHROME_BROWSER_UI_TABS_TAB_GROUP_H_
+#endif  // COMPONENTS_TABS_PUBLIC_TAB_GROUP_H_
diff --git a/chrome/browser/ui/tabs/tab_group_tab_collection.h b/components/tabs/public/tab_group_tab_collection.h
similarity index 78%
rename from chrome/browser/ui/tabs/tab_group_tab_collection.h
rename to components/tabs/public/tab_group_tab_collection.h
index a117bd78..a468ac0 100644
--- a/chrome/browser/ui/tabs/tab_group_tab_collection.h
+++ b/components/tabs/public/tab_group_tab_collection.h
@@ -2,12 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_TABS_TAB_GROUP_TAB_COLLECTION_H_
-#define CHROME_BROWSER_UI_TABS_TAB_GROUP_TAB_COLLECTION_H_
+#ifndef COMPONENTS_TABS_PUBLIC_TAB_GROUP_TAB_COLLECTION_H_
+#define COMPONENTS_TABS_PUBLIC_TAB_GROUP_TAB_COLLECTION_H_
 
 #include <memory>
 
-#include "chrome/browser/ui/tabs/tab_group_controller.h"
 #include "components/tab_groups/tab_group_visual_data.h"
 #include "components/tabs/public/tab_collection.h"
 
@@ -22,8 +21,7 @@
 class TabGroupTabCollection : public TabCollection {
  public:
   TabGroupTabCollection(tab_groups::TabGroupId group_id,
-                        tab_groups::TabGroupVisualData visual_data,
-                        TabGroupController* controller);
+                        tab_groups::TabGroupVisualData visual_data);
   ~TabGroupTabCollection() override;
   TabGroupTabCollection(const TabGroupTabCollection&) = delete;
   TabGroupTabCollection& operator=(const TabGroupTabCollection&) = delete;
@@ -41,4 +39,4 @@
 
 }  // namespace tabs
 
-#endif  // CHROME_BROWSER_UI_TABS_TAB_GROUP_TAB_COLLECTION_H_
+#endif  // COMPONENTS_TABS_PUBLIC_TAB_GROUP_TAB_COLLECTION_H_
diff --git a/chrome/browser/ui/tabs/tab_strip_collection.h b/components/tabs/public/tab_strip_collection.h
similarity index 97%
rename from chrome/browser/ui/tabs/tab_strip_collection.h
rename to components/tabs/public/tab_strip_collection.h
index dd94a13c..0552c8c 100644
--- a/chrome/browser/ui/tabs/tab_strip_collection.h
+++ b/components/tabs/public/tab_strip_collection.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 CHROME_BROWSER_UI_TABS_TAB_STRIP_COLLECTION_H_
-#define CHROME_BROWSER_UI_TABS_TAB_STRIP_COLLECTION_H_
+#ifndef COMPONENTS_TABS_PUBLIC_TAB_STRIP_COLLECTION_H_
+#define COMPONENTS_TABS_PUBLIC_TAB_STRIP_COLLECTION_H_
 
 #include <memory>
 #include <optional>
@@ -178,4 +178,4 @@
 
 }  // namespace tabs
 
-#endif  // CHROME_BROWSER_UI_TABS_TAB_STRIP_COLLECTION_H_
+#endif  // COMPONENTS_TABS_PUBLIC_TAB_STRIP_COLLECTION_H_
diff --git a/chrome/browser/ui/tabs/unpinned_tab_collection.h b/components/tabs/public/unpinned_tab_collection.h
similarity index 83%
rename from chrome/browser/ui/tabs/unpinned_tab_collection.h
rename to components/tabs/public/unpinned_tab_collection.h
index 91bfe093..681ed275 100644
--- a/chrome/browser/ui/tabs/unpinned_tab_collection.h
+++ b/components/tabs/public/unpinned_tab_collection.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 CHROME_BROWSER_UI_TABS_UNPINNED_TAB_COLLECTION_H_
-#define CHROME_BROWSER_UI_TABS_UNPINNED_TAB_COLLECTION_H_
+#ifndef COMPONENTS_TABS_PUBLIC_UNPINNED_TAB_COLLECTION_H_
+#define COMPONENTS_TABS_PUBLIC_UNPINNED_TAB_COLLECTION_H_
 
 #include <optional>
 
@@ -32,4 +32,4 @@
 
 }  // namespace tabs
 
-#endif  // CHROME_BROWSER_UI_TABS_UNPINNED_TAB_COLLECTION_H_
+#endif  // COMPONENTS_TABS_PUBLIC_UNPINNED_TAB_COLLECTION_H_
diff --git a/components/tabs/tab_group.cc b/components/tabs/tab_group.cc
new file mode 100644
index 0000000..700f371
--- /dev/null
+++ b/components/tabs/tab_group.cc
@@ -0,0 +1,121 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/tabs/public/tab_group.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "components/tab_groups/tab_group_id.h"
+#include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_collection.h"
+#include "components/tabs/public/tab_group_tab_collection.h"
+#include "components/tabs/public/tab_interface.h"
+#include "components/tabs/public/tab_strip_collection.h"
+
+namespace {
+// TODO(crbug.com/418837851) we should be able to ignore this case in the future
+// once detach cases are properly checked for use of TabStripModel indices. Find
+// the TabStripCollection the group exists in. Iterate through collection
+// parents looking for a tabstrip. if none is found, then true indexes cant be
+// derived.
+bool IsInValidCollectionTree(tabs::TabCollection* collection) {
+  while (collection &&
+         collection->type() != tabs::TabCollection::Type::TABSTRIP) {
+    collection = collection->GetParentCollection();
+  }
+  return collection != nullptr;
+}
+
+}  // anonymous namespace
+
+TabGroup::TabGroup(tabs::TabGroupTabCollection* collection,
+                   const tab_groups::TabGroupId& id,
+                   const tab_groups::TabGroupVisualData& visual_data)
+    : collection_(collection),
+      id_(id),
+      visual_data_(
+          std::make_unique<tab_groups::TabGroupVisualData>(visual_data)) {}
+
+TabGroup::~TabGroup() = default;
+
+void TabGroup::SetVisualData(tab_groups::TabGroupVisualData visual_data,
+                             bool is_customized) {
+  visual_data_ = std::make_unique<tab_groups::TabGroupVisualData>(visual_data);
+
+  // Is customized is always true after it has been set to true once.
+  is_customized_ |= is_customized;
+}
+
+void TabGroup::SetGroupIsClosing(bool is_closing) {
+  is_closing_ = is_closing;
+}
+
+void TabGroup::AddTab() {
+  ++tab_count_;
+}
+
+void TabGroup::RemoveTab() {
+  DCHECK_GT(tab_count_, 0);
+  --tab_count_;
+}
+
+bool TabGroup::IsEmpty() const {
+  return tab_count_ == 0;
+}
+
+bool TabGroup::IsCustomized() const {
+  return is_customized_;
+}
+
+tabs::TabInterface* TabGroup::GetFirstTab() const {
+  if (collection_->begin() == collection_->end()) {
+    return nullptr;
+  }
+
+  if (!IsInValidCollectionTree(collection_)) {
+    return nullptr;
+  }
+
+  return collection_->GetTabAtIndexRecursive(0);
+}
+
+tabs::TabInterface* TabGroup::GetLastTab() const {
+  if (collection_->begin() == collection_->end()) {
+    return nullptr;
+  }
+
+  if (!IsInValidCollectionTree(collection_)) {
+    return nullptr;
+  }
+
+  std::vector<tabs::TabInterface*> tabs = collection_->GetTabsRecursive();
+  return tabs.at(tabs.size() - 1);
+}
+
+gfx::Range TabGroup::ListTabs() const {
+  tabs::TabInterface* maybe_first_tab = GetFirstTab();
+  if (!maybe_first_tab) {
+    return gfx::Range();
+  }
+
+  // If there's a first tab, there's a last tab.
+  tabs::TabInterface* last_tab = GetLastTab();
+
+  // Find the TabStripCollection (for which indexes are based off of.)
+  tabs::TabCollection* root_collection = collection_;
+  while (root_collection &&
+         root_collection->type() != tabs::TabCollection::Type::TABSTRIP) {
+    root_collection = root_collection->GetParentCollection();
+  }
+  if (!root_collection) {
+    return gfx::Range();
+  }
+
+  return gfx::Range(
+      root_collection->GetIndexOfTabRecursive(maybe_first_tab).value(),
+      root_collection->GetIndexOfTabRecursive(last_tab).value() + 1);
+}
diff --git a/chrome/browser/ui/tabs/tab_group_tab_collection.cc b/components/tabs/tab_group_tab_collection.cc
similarity index 73%
rename from chrome/browser/ui/tabs/tab_group_tab_collection.cc
rename to components/tabs/tab_group_tab_collection.cc
index 1e1c3f6..3b5a161 100644
--- a/chrome/browser/ui/tabs/tab_group_tab_collection.cc
+++ b/components/tabs/tab_group_tab_collection.cc
@@ -2,25 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/tabs/tab_group_tab_collection.h"
+#include "components/tabs/public/tab_group_tab_collection.h"
 
 #include <memory>
 #include <optional>
 
-#include "chrome/browser/ui/tabs/tab_group.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tabs/public/tab_collection_storage.h"
+#include "components/tabs/public/tab_group.h"
 
 namespace tabs {
 
 TabGroupTabCollection::TabGroupTabCollection(
     tab_groups::TabGroupId group_id,
-    tab_groups::TabGroupVisualData visual_data,
-    TabGroupController* controller)
+    tab_groups::TabGroupVisualData visual_data)
     : TabCollection(TabCollection::Type::GROUP,
                     {TabCollection::Type::SPLIT},
                     /*supports_tabs=*/true) {
-  group_ = std::make_unique<TabGroup>(controller, group_id, visual_data);
+  group_ = std::make_unique<TabGroup>(this, group_id, visual_data);
 }
 
 TabGroupTabCollection::~TabGroupTabCollection() = default;
diff --git a/chrome/browser/ui/tabs/tab_strip_collection.cc b/components/tabs/tab_strip_collection.cc
similarity index 96%
rename from chrome/browser/ui/tabs/tab_strip_collection.cc
rename to components/tabs/tab_strip_collection.cc
index 6c24799b..5b28c1df 100644
--- a/chrome/browser/ui/tabs/tab_strip_collection.cc
+++ b/components/tabs/tab_strip_collection.cc
@@ -2,25 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/tabs/tab_strip_collection.h"
+#include "components/tabs/public/tab_strip_collection.h"
 
-#include <cstddef>
 #include <memory>
 #include <optional>
-#include <utility>
-#include <variant>
+#include <set>
 
 #include "base/containers/adapters.h"
 #include "base/memory/ptr_util.h"
-#include "chrome/browser/ui/tabs/tab_group_tab_collection.h"
-#include "chrome/browser/ui/tabs/unpinned_tab_collection.h"
 #include "components/tabs/public/pinned_tab_collection.h"
 #include "components/tabs/public/split_tab_collection.h"
 #include "components/tabs/public/split_tab_id.h"
 #include "components/tabs/public/split_tab_visual_data.h"
 #include "components/tabs/public/tab_collection.h"
 #include "components/tabs/public/tab_collection_storage.h"
+#include "components/tabs/public/tab_group_tab_collection.h"
 #include "components/tabs/public/tab_interface.h"
+#include "components/tabs/public/unpinned_tab_collection.h"
 
 namespace tabs {
 
@@ -57,13 +55,13 @@
       !GetTabGroupCollection(new_group_id.value())) {
     // Attempt to create a new group for the tab.
     TabGroupTabCollection* group_collection =
-          MaybeAttachDetachedGroupCollection(index, new_group_id.value());
+        MaybeAttachDetachedGroupCollection(index, new_group_id.value());
 
-      // New empty group was attached, append tab to the group.
-      CHECK(group_collection->ChildCount() == 0);
-      TabInterface* inserted_tab = group_collection->AddTab(std::move(tab), 0);
-      CHECK(GetIndexOfTabRecursive(inserted_tab) == index);
-      return;
+    // New empty group was attached, append tab to the group.
+    CHECK(group_collection->ChildCount() == 0);
+    TabInterface* inserted_tab = group_collection->AddTab(std::move(tab), 0);
+    CHECK(GetIndexOfTabRecursive(inserted_tab) == index);
+    return;
   }
 
   auto [tab_collection_ptr, insert_index] =
diff --git a/chrome/browser/ui/tabs/unpinned_tab_collection.cc b/components/tabs/unpinned_tab_collection.cc
similarity index 87%
rename from chrome/browser/ui/tabs/unpinned_tab_collection.cc
rename to components/tabs/unpinned_tab_collection.cc
index 155e0bb..85e8f4f 100644
--- a/chrome/browser/ui/tabs/unpinned_tab_collection.cc
+++ b/components/tabs/unpinned_tab_collection.cc
@@ -2,17 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/tabs/unpinned_tab_collection.h"
+#include "components/tabs/public/unpinned_tab_collection.h"
 
-#include <cstddef>
 #include <memory>
 #include <optional>
 
-#include "base/not_fatal_until.h"
-#include "base/notreached.h"
-#include "chrome/browser/ui/tabs/tab_group_tab_collection.h"
 #include "components/tabs/public/tab_collection.h"
-#include "components/tabs/public/tab_collection_storage.h"
+#include "components/tabs/public/tab_group_tab_collection.h"
 #include "components/tabs/public/tab_interface.h"
 
 namespace tabs {
diff --git a/components/viz/service/layers/layer_context_impl.cc b/components/viz/service/layers/layer_context_impl.cc
index f2ad524..c9b5582a 100644
--- a/components/viz/service/layers/layer_context_impl.cc
+++ b/components/viz/service/layers/layer_context_impl.cc
@@ -754,7 +754,7 @@
   switch (wire.which()) {
     case mojom::TileContents::Tag::kMissingReason:
       return cc::TileDisplayLayerImpl::TileContents(
-          cc::TileDisplayLayerImpl::NoContents());
+          cc::TileDisplayLayerImpl::NoContents(wire.get_missing_reason()));
 
     case mojom::TileContents::Tag::kResource:
       return DeserializeTileResource(*wire.get_resource());
diff --git a/content/browser/back_forward_cache_no_store_browsertest.cc b/content/browser/back_forward_cache_no_store_browsertest.cc
index 9eec1c6e..2f482a6 100644
--- a/content/browser/back_forward_cache_no_store_browsertest.cc
+++ b/content/browser/back_forward_cache_no_store_browsertest.cc
@@ -14,10 +14,12 @@
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/prerender_test_util.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/shell/browser/shell.h"
 #include "net/base/features.h"
@@ -160,41 +162,111 @@
                     {}, {}, {}, FROM_HERE);
 }
 
-namespace {
+enum class TestNavigationType {
+  kNonPrerender,
+  kPrerender,
+};
+
+class BackForwardCacheBrowserTestWithPrerendering
+    : public BackForwardCacheBrowserTest,
+      public ::testing::WithParamInterface<TestNavigationType> {
+ public:
+  static std::string DescribeParams(
+      const ::testing::TestParamInfo<ParamType>& info) {
+    switch (info.param) {
+      case TestNavigationType::kNonPrerender:
+        return "NonPrerender";
+      case TestNavigationType::kPrerender:
+        return "Prerender";
+    }
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
+    // `prerender_helper_` has a ScopedFeatureList so we needed to delay its
+    // creation until the BackForwardCacheBrowserTest finishes setting up the
+    // ScopedFeatureList.
+    prerender_helper_ =
+        std::make_unique<test::PrerenderTestHelper>(base::BindRepeating(
+            &BackForwardCacheBrowserTestWithPrerendering::GetWebContents,
+            base::Unretained(this)));
+    prerender_helper_->RegisterServerRequestMonitor(embedded_test_server());
+  }
+
+  WebContents* GetWebContents() { return web_contents(); }
+
+  test::PrerenderTestHelper& prerender_helper() { return *prerender_helper_; }
+
+ protected:
+  void NavigateToPageWithResponseFromMainWebContents(
+      GURL& url,
+      net::test_server::ControllableHttpResponse& response,
+      const char* response_bytes) {
+    switch (GetParam()) {
+      case TestNavigationType::kNonPrerender: {
+        TestNavigationObserver observer(web_contents());
+        shell()->LoadURL(url);
+        response.WaitForRequest();
+        response.Send(response_bytes);
+        response.Done();
+        observer.Wait();
+        break;
+      }
+      case TestNavigationType::kPrerender: {
+        prerender_helper().AddPrerenderAsync(url);
+        response.WaitForRequest();
+        response.Send(response_bytes);
+        response.Done();
+        TestActivationManager activation_manager(web_contents(), url);
+        ASSERT_TRUE(ExecJs(web_contents()->GetPrimaryMainFrame(),
+                           JsReplace("location = $1", url)));
+        activation_manager.WaitForNavigationFinished();
+        EXPECT_TRUE(activation_manager.was_activated());
+        break;
+      }
+    }
+  }
+
+ private:
+  std::unique_ptr<test::PrerenderTestHelper> prerender_helper_;
+};
 
 class BackForwardCacheBrowserTestAllowCacheControlNoStore
-    : public BackForwardCacheBrowserTest {
+    : public BackForwardCacheBrowserTestWithPrerendering {
  protected:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     EnableFeatureAndSetParams(features::kBackForwardCache, "", "");
     EnableFeatureAndSetParams(
         features::kCacheControlNoStoreEnterBackForwardCache, "level",
         "store-and-evict");
-    BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
+    BackForwardCacheBrowserTestWithPrerendering::SetUpCommandLine(command_line);
   }
 };
 
-}  // namespace
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    BackForwardCacheBrowserTestAllowCacheControlNoStore,
+    ::testing::Values(TestNavigationType::kNonPrerender,
+                      TestNavigationType::kPrerender),
+    &BackForwardCacheBrowserTestAllowCacheControlNoStore::DescribeParams);
 
 // Test that a page with cache-control:no-store enters bfcache with the flag on,
 // but does not get restored and gets evicted.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestAllowCacheControlNoStore,
+IN_PROC_BROWSER_TEST_P(BackForwardCacheBrowserTestAllowCacheControlNoStore,
                        PagesWithCacheControlNoStoreEnterBfcacheAndEvicted) {
   net::test_server::ControllableHttpResponse response(embedded_test_server(),
                                                       "/title1.html");
   ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_initial(embedded_test_server()->GetURL("a.com", "/title3.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), url_initial));
 
   GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
   GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
 
   // 1) Load the document and specify no-store for the main resource.
-  TestNavigationObserver observer(web_contents());
-  shell()->LoadURL(url_a);
+  NavigateToPageWithResponseFromMainWebContents(url_a, response,
+                                                kResponseWithNoCache);
   RenderFrameHostImplWrapper rfh_a(current_frame_host());
-  response.WaitForRequest();
-  response.Send(kResponseWithNoCache);
-  response.Done();
-  observer.Wait();
   rfh_a->GetBackForwardCacheMetrics()->SetObserverForTesting(this);
 
   // 2) Navigate away. |rfh_a| should enter the bfcache.
@@ -216,12 +288,14 @@
 // Test that a page with cache-control:no-store enters bfcache with the flag on,
 // and if a cookie is modified while it is in bfcache via JavaScript, gets
 // evicted with cookie modified marked.
-IN_PROC_BROWSER_TEST_F(
+IN_PROC_BROWSER_TEST_P(
     BackForwardCacheBrowserTestAllowCacheControlNoStore,
     PagesWithCacheControlNoStoreCookieModifiedThroughJavaScript) {
   net::test_server::ControllableHttpResponse response(embedded_test_server(),
                                                       "/title1.html");
   ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_initial(embedded_test_server()->GetURL("a.com", "/title3.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), url_initial));
 
   GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
   GURL url_a_2(embedded_test_server()->GetURL("a.com", "/title2.html"));
@@ -231,13 +305,9 @@
   Shell* tab_to_modify_cookie = CreateBrowser();
 
   // 1) Load the document and specify no-store for the main resource.
-  TestNavigationObserver observer(tab_to_be_bfcached->web_contents());
-  tab_to_be_bfcached->LoadURL(url_a);
+  NavigateToPageWithResponseFromMainWebContents(url_a, response,
+                                                kResponseWithNoCache);
   RenderFrameHostImplWrapper rfh_a(current_frame_host());
-  response.WaitForRequest();
-  response.Send(kResponseWithNoCache);
-  response.Done();
-  observer.Wait();
   rfh_a->GetBackForwardCacheMetrics()->SetObserverForTesting(this);
 
   // 2) Set a normal cookie from JavaScript.
@@ -269,24 +339,89 @@
                   BlockListedFeatures()));
 }
 
+// Test that a prerendered page with cache-control:no-store enters bfcache with
+// the flag on, and if a cookie is modified before the prerendered page is
+// activated via JavaScript, gets evicted with cookie modified marked.
+IN_PROC_BROWSER_TEST_F(
+    BackForwardCacheBrowserTestAllowCacheControlNoStore,
+    PagesWithCacheControlNoStoreCookieModifiedBeforePrerendererActivationThroughJavaScript) {
+  net::test_server::ControllableHttpResponse response(embedded_test_server(),
+                                                      "/title1.html");
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_initial(embedded_test_server()->GetURL("a.com", "/title3.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), url_initial));
+
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  GURL url_a_2(embedded_test_server()->GetURL("a.com", "/title2.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title3.html"));
+
+  Shell* tab_to_be_bfcached = shell();
+  Shell* tab_to_modify_cookie = CreateBrowser();
+
+  // 1) Prerender the document and specify no-store for the main resource.
+  prerender_helper().AddPrerenderAsync(url_a);
+  response.WaitForRequest();
+  response.Send(kResponseWithNoCache);
+  response.Done();
+  TestActivationManager activation_manager(web_contents(), url_a);
+  ASSERT_TRUE(ExecJs(web_contents()->GetPrimaryMainFrame(),
+                     JsReplace("location = $1", url_a)));
+  ASSERT_TRUE(activation_manager.WaitForAfterChecks());
+
+  // 2) Navigate to a.com in |tab_to_modify_cookie| and modify cookie from
+  // JavaScript before the page is activated.
+  EXPECT_TRUE(NavigateToURL(tab_to_modify_cookie, url_a_2));
+  EXPECT_TRUE(ExecJs(tab_to_modify_cookie, "document.cookie='foo=baz'"));
+  EXPECT_EQ("foo=baz", EvalJs(tab_to_modify_cookie, "document.cookie"));
+
+  // 3) Resume the activation.
+  activation_manager.WaitForNavigationFinished();
+  EXPECT_TRUE(activation_manager.was_activated());
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+  rfh_a->GetBackForwardCacheMetrics()->SetObserverForTesting(this);
+
+  // 4) Navigate away. |rfh_a| should enter bfcache.
+  EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_b));
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+
+  // 5) Go back. |rfh_a| should be evicted upon restoration.
+  ASSERT_TRUE(HistoryGoBack(tab_to_be_bfcached->web_contents()));
+
+  EXPECT_EQ("foo=baz", EvalJs(tab_to_be_bfcached, "document.cookie"));
+  ExpectNotRestored({NotRestoredReason::kCacheControlNoStoreCookieModified}, {},
+                    {}, {}, {}, FROM_HERE);
+  // Make sure that the tree result also has the same reason.
+  EXPECT_THAT(GetTreeResult()->GetDocumentResult(),
+              MatchesDocumentResult(
+                  NotRestoredReasons(
+                      {NotRestoredReason::kCacheControlNoStoreCookieModified}),
+                  BlockListedFeatures()));
+}
+
 // Test that a page with cache-control:no-store enters bfcache with the flag on,
 // and if a cookie is modified, it gets evicted with cookie changed, but if
 // navigated away again and navigated back, it gets evicted without cookie
 // change marked.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestAllowCacheControlNoStore,
+IN_PROC_BROWSER_TEST_P(BackForwardCacheBrowserTestAllowCacheControlNoStore,
                        PagesWithCacheControlNoStoreCookieModifiedBackTwice) {
+  net::test_server::ControllableHttpResponse response(embedded_test_server(),
+                                                      "/title1.html");
+  net::test_server::ControllableHttpResponse response_back(
+      embedded_test_server(), "/title1.html");
   ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_initial(embedded_test_server()->GetURL("a.com", "/title3.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), url_initial));
 
-  GURL url_a(embedded_test_server()->GetURL(
-      "a.com", "/set-header?Cache-Control: no-store"));
-  GURL url_a_2(embedded_test_server()->GetURL("a.com", "/title1.html"));
-  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  GURL url_a_2(embedded_test_server()->GetURL("a.com", "/title2.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
 
   Shell* tab_to_be_bfcached = shell();
   Shell* tab_to_modify_cookie = CreateBrowser();
 
   // 1) Load the document and specify no-store for the main resource.
-  EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_a));
+  NavigateToPageWithResponseFromMainWebContents(url_a, response,
+                                                kResponseWithNoCache);
   RenderFrameHostImplWrapper rfh_a(current_frame_host());
   rfh_a->GetBackForwardCacheMetrics()->SetObserverForTesting(this);
 
@@ -306,7 +441,12 @@
   EXPECT_EQ("foo=baz", EvalJs(tab_to_modify_cookie, "document.cookie"));
 
   // 5) Go back. |rfh_a| should be evicted upon restoration.
-  ASSERT_TRUE(HistoryGoBack(tab_to_be_bfcached->web_contents()));
+  TestNavigationObserver observer(tab_to_be_bfcached->web_contents());
+  tab_to_be_bfcached->web_contents()->GetController().GoBack();
+  response_back.WaitForRequest();
+  response_back.Send(kResponseWithNoCache);
+  response_back.Done();
+  observer.Wait();
 
   EXPECT_EQ("foo=baz", EvalJs(tab_to_be_bfcached, "document.cookie"));
   ExpectNotRestored({NotRestoredReason::kCacheControlNoStoreCookieModified}, {},
@@ -337,12 +477,14 @@
 // Test that a page with cache-control:no-store enters bfcache with the flag on,
 // and even if a cookie is modified on a different domain than the entry, the
 // entry is not marked as cookie modified.
-IN_PROC_BROWSER_TEST_F(
+IN_PROC_BROWSER_TEST_P(
     BackForwardCacheBrowserTestAllowCacheControlNoStore,
     PagesWithCacheControlNoStoreCookieModifiedThroughJavaScriptOnDifferentDomain) {
   net::test_server::ControllableHttpResponse response(embedded_test_server(),
                                                       "/title1.html");
   ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_initial(embedded_test_server()->GetURL("a.com", "/title3.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), url_initial));
 
   GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
   GURL url_a_2(embedded_test_server()->GetURL("a.com", "/title2.html"));
@@ -352,13 +494,9 @@
   Shell* tab_to_modify_cookie = CreateBrowser();
 
   // 1) Load the document and specify no-store for the main resource.
-  TestNavigationObserver observer(tab_to_be_bfcached->web_contents());
-  tab_to_be_bfcached->LoadURL(url_a);
+  NavigateToPageWithResponseFromMainWebContents(url_a, response,
+                                                kResponseWithNoCache);
   RenderFrameHostImplWrapper rfh_a(current_frame_host());
-  response.WaitForRequest();
-  response.Send(kResponseWithNoCache);
-  response.Done();
-  observer.Wait();
   rfh_a->GetBackForwardCacheMetrics()->SetObserverForTesting(this);
 
   // 2) Navigate away. |rfh_a| should enter bfcache.
@@ -384,17 +522,21 @@
 
 // Test that a page with cache-control:no-store records other not restored
 // reasons along with kCacheControlNoStore when eviction happens.
-IN_PROC_BROWSER_TEST_F(
+IN_PROC_BROWSER_TEST_P(
     BackForwardCacheBrowserTestAllowCacheControlNoStore,
     PagesWithCacheControlNoStoreRecordOtherReasonsWhenEvictionHappens) {
+  net::test_server::ControllableHttpResponse response(embedded_test_server(),
+                                                      "/title1.html");
   ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_initial(embedded_test_server()->GetURL("a.com", "/title3.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), url_initial));
 
-  GURL url_a(embedded_test_server()->GetURL(
-      "a.com", "/set-header?Cache-Control: no-store"));
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
   GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
 
   // 1) Load the document and specify no-store for the main resource.
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  NavigateToPageWithResponseFromMainWebContents(url_a, response,
+                                                kResponseWithNoCache);
   RenderFrameHostImplWrapper rfh_a(current_frame_host());
   rfh_a->GetBackForwardCacheMetrics()->SetObserverForTesting(this);
 
@@ -421,6 +563,9 @@
 // Test that a page with cache-control:no-store records other not restored
 // reasons along with kCacheControlNoStore when there are other blocking reasons
 // upon entering bfcache.
+// TODO(crbug.com/417215501): this test is not using `embedded_test_server()` so
+// the current set up for prerendering doesn't work, we will only test the
+// normal navigation.
 IN_PROC_BROWSER_TEST_F(
     BackForwardCacheBrowserTestAllowCacheControlNoStore,
     PagesWithCacheControlNoStoreRecordOtherReasonsUponEntrance) {
@@ -456,17 +601,21 @@
 
 // Test that a page with cache-control:no-store records eviction reasons along
 // with kCacheControlNoStore when the entry is evicted for other reasons.
-IN_PROC_BROWSER_TEST_F(
+IN_PROC_BROWSER_TEST_P(
     BackForwardCacheBrowserTestAllowCacheControlNoStore,
     PagesWithCacheControlNoStoreRecordOtherReasonsForEviction) {
+  net::test_server::ControllableHttpResponse response(embedded_test_server(),
+                                                      "/title1.html");
   ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_initial(embedded_test_server()->GetURL("a.com", "/title3.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), url_initial));
 
-  GURL url_a(embedded_test_server()->GetURL(
-      "a.com", "/set-header?Cache-Control: no-store"));
+  GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
   GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
 
   // 1) Load the document and specify no-store for the main resource.
-  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  NavigateToPageWithResponseFromMainWebContents(url_a, response,
+                                                kResponseWithNoCache);
   RenderFrameHostImplWrapper rfh_a(current_frame_host());
   rfh_a->GetBackForwardCacheMetrics()->SetObserverForTesting(this);
 
@@ -527,11 +676,13 @@
 // Test that a page with cache-control:no-store enters bfcache with the flag on,
 // and if a cookie is modified while it is in bfcache via response header, gets
 // evicted with cookie modified marked.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestAllowCacheControlNoStore,
+IN_PROC_BROWSER_TEST_P(BackForwardCacheBrowserTestAllowCacheControlNoStore,
                        PagesWithCacheControlNoStoreSetFromResponseHeader) {
   net::test_server::ControllableHttpResponse response(embedded_test_server(),
                                                       "/title1.html");
   ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_initial(embedded_test_server()->GetURL("a.com", "/title3.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), url_initial));
 
   GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
   GURL url_a_2(embedded_test_server()->GetURL("a.com", "/title2.html"));
@@ -541,13 +692,9 @@
   Shell* tab_to_modify_cookie = CreateBrowser();
 
   // 1) Load the document and specify no-store for the main resource.
-  TestNavigationObserver observer(tab_to_be_bfcached->web_contents());
-  tab_to_be_bfcached->LoadURL(url_a);
+  NavigateToPageWithResponseFromMainWebContents(url_a, response,
+                                                kResponseWithNoCacheWithCookie);
   RenderFrameHostImplWrapper rfh_a(current_frame_host());
-  response.WaitForRequest();
-  response.Send(kResponseWithNoCacheWithCookie);
-  response.Done();
-  observer.Wait();
   rfh_a->GetBackForwardCacheMetrics()->SetObserverForTesting(this);
   EXPECT_EQ("foo=bar", EvalJs(tab_to_be_bfcached, "document.cookie"));
 
@@ -577,6 +724,9 @@
 // Test that a page with cache-control:no-store enters bfcache with the flag on,
 // and if HTTPOnly cookie is modified while it is in bfcache, gets evicted with
 // HTTPOnly cookie modified marked.
+// TODO(crbug.com/417215501): this test is not using `embedded_test_server()` so
+// the current set up for prerendering doesn't work, we will only test the
+// normal navigation.
 IN_PROC_BROWSER_TEST_F(
     BackForwardCacheBrowserTestAllowCacheControlNoStore,
     PagesWithCacheControlNoStoreSetFromResponseHeaderHTTPOnlyCookie) {
@@ -637,6 +787,9 @@
 // and if a HTTPOnly cookie is modified, it gets evicted with cookie changed,
 // but if navigated away again and navigated back, it gets evicted without
 // HTTPOnly cookie change marked.
+// TODO(crbug.com/417215501): this test is not using `embedded_test_server()` so
+// the current set up for prerendering doesn't work, we will only test the
+// normal navigation.
 IN_PROC_BROWSER_TEST_F(
     BackForwardCacheBrowserTestAllowCacheControlNoStore,
     PagesWithCacheControlNoStoreHTTPOnlyCookieModifiedBackTwice) {
@@ -1025,7 +1178,7 @@
   void SetIsCookieEnabled(bool new_value) { is_cookie_enabled_ = new_value; }
 
   bool CanBackForwardCachedPageReceiveCookieChanges(
-      content::BrowserContext& browser_context,
+      BrowserContext& browser_context,
       const GURL& url,
       const net::SiteForCookies& site_for_cookies,
       const url::Origin& top_frame_origin,
@@ -1938,22 +2091,22 @@
 
 #if BUILDFLAG(ENABLE_DEVICE_BOUND_SESSIONS)
 
-class DeviceBoundSessionAccessObserver : public content::WebContentsObserver {
+class DeviceBoundSessionAccessObserver : public WebContentsObserver {
  public:
   DeviceBoundSessionAccessObserver(
-      content::WebContents* web_contents,
+      WebContents* web_contents,
       base::RepeatingCallback<void(
           const net::device_bound_sessions::SessionAccess&)> on_access_callback)
       : WebContentsObserver(web_contents),
         on_access_callback_(std::move(on_access_callback)) {}
 
   void OnDeviceBoundSessionAccessed(
-      content::NavigationHandle* navigation,
+      NavigationHandle* navigation,
       const net::device_bound_sessions::SessionAccess& access) override {
     on_access_callback_.Run(access);
   }
   void OnDeviceBoundSessionAccessed(
-      content::RenderFrameHost* rfh,
+      RenderFrameHost* rfh,
       const net::device_bound_sessions::SessionAccess& access) override {
     on_access_callback_.Run(access);
   }
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index a65b70e..a5caadf 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -733,6 +733,9 @@
 }
 
 void NavigationURLLoaderImpl::Restart() {
+  TRACE_EVENT_WITH_FLOW0("navigation", "NavigationURLLoaderImpl::Restart",
+                         TRACE_ID_LOCAL(this),
+                         TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
   // Cancel all inflight early hints preloads except for same origin redirects.
   if (!IsSameOriginRedirect(resource_request_->navigation_redirect_chain)) {
     early_hints_manager_.reset();
diff --git a/content/browser/renderer_host/back_forward_cache_impl.cc b/content/browser/renderer_host/back_forward_cache_impl.cc
index a642528..a6a1960 100644
--- a/content/browser/renderer_host/back_forward_cache_impl.cc
+++ b/content/browser/renderer_host/back_forward_cache_impl.cc
@@ -1843,18 +1843,14 @@
 
 BackForwardCache::DisabledReason::DisabledReason(
     const BackForwardCache::DisabledReason& reason) = default;
-bool BackForwardCache::DisabledReason::operator<(
+std::weak_ordering BackForwardCache::DisabledReason::operator<=>(
     const DisabledReason& other) const {
-  return std::tie(source, id) < std::tie(other.source, other.id);
+  return std::tie(source, id) <=> std::tie(other.source, other.id);
 }
 bool BackForwardCache::DisabledReason::operator==(
     const DisabledReason& other) const {
   return std::tie(source, id) == std::tie(other.source, other.id);
 }
-bool BackForwardCache::DisabledReason::operator!=(
-    const DisabledReason& other) const {
-  return !(*this == other);
-}
 
 BackForwardCacheCanStoreTreeResult::BackForwardCacheCanStoreTreeResult(
     RenderFrameHostImpl* rfh,
diff --git a/content/browser/renderer_host/display_feature.cc b/content/browser/renderer_host/display_feature.cc
index 1114b7f..b59c316 100644
--- a/content/browser/renderer_host/display_feature.cc
+++ b/content/browser/renderer_host/display_feature.cc
@@ -6,15 +6,6 @@
 
 namespace content {
 
-bool DisplayFeature::operator==(const DisplayFeature& other) const {
-  return orientation == other.orientation && offset == other.offset &&
-         mask_length == other.mask_length;
-}
-
-bool DisplayFeature::operator!=(const DisplayFeature& other) const {
-  return !(*this == other);
-}
-
 std::vector<gfx::Rect> DisplayFeature::ComputeViewportSegments(
     const gfx::Size& visible_viewport_size,
     int root_view_offset_from_origin) const {
diff --git a/content/browser/renderer_host/display_feature.h b/content/browser/renderer_host/display_feature.h
index 487e99f..1f8fd70 100644
--- a/content/browser/renderer_host/display_feature.h
+++ b/content/browser/renderer_host/display_feature.h
@@ -56,8 +56,8 @@
   // A display feature that only splits content will have a 0 |mask_length|.
   int mask_length = 0;
 
-  bool operator==(const DisplayFeature& other) const;
-  bool operator!=(const DisplayFeature& other) const;
+  friend bool operator==(const DisplayFeature&,
+                         const DisplayFeature&) = default;
 
   // Computes logical segments of the |visible_viewport_size|, based on
   // this display feature. These segments are in DIPs relative to the widget
diff --git a/content/browser/renderer_host/frame_tree.h b/content/browser/renderer_host/frame_tree.h
index 67316c6a..23921f3d5 100644
--- a/content/browser/renderer_host/frame_tree.h
+++ b/content/browser/renderer_host/frame_tree.h
@@ -87,7 +87,6 @@
     NodeIterator& AdvanceSkippingChildren();
 
     bool operator==(const NodeIterator& rhs) const;
-    bool operator!=(const NodeIterator& rhs) const { return !(*this == rhs); }
 
     FrameTreeNode* operator*() { return current_node_; }
 
diff --git a/content/browser/renderer_host/input/autoscroll_browsertest.cc b/content/browser/renderer_host/input/autoscroll_browsertest.cc
index 95c1783c..d8c99b0 100644
--- a/content/browser/renderer_host/input/autoscroll_browsertest.cc
+++ b/content/browser/renderer_host/input/autoscroll_browsertest.cc
@@ -261,8 +261,17 @@
 }
 
 // Checks that wheel scrolling works after autoscroll cancelation.
+// TODO(https://crbug.com/418936120): Flaky on
+// linux-blink-web-tests-force-accessibility-rel
+#if BUILDFLAG(IS_LINUX)
+#define MAYBE_WheelScrollingWorksAfterAutoscrollCancel \
+  DISABLED_WheelScrollingWorksAfterAutoscrollCancel
+#else
+#define MAYBE_WheelScrollingWorksAfterAutoscrollCancel \
+  WheelScrollingWorksAfterAutoscrollCancel
+#endif
 IN_PROC_BROWSER_TEST_F(AutoscrollBrowserTest,
-                       WheelScrollingWorksAfterAutoscrollCancel) {
+                       MAYBE_WheelScrollingWorksAfterAutoscrollCancel) {
   LoadURL(kAutoscrollDataURL);
 
   // Start autoscroll with middle click.
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index deb3de2..62f577b2 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -3004,19 +3004,21 @@
   // The `CookieChangeListener` will only be set up if all of these are true:
   // (1) the navigation's protocol is HTTP(s).
   // (2) we allow a document with `Cache-control: no-store` header to
-  // enter BFCache.
+  // enter back/forward.
   // (3) the navigation is neither a same-document navigation nor a page
   // activation, since in these cases, an existing `RenderFrameHost` will be
   // used, and it would already have an existing listener, so we should skip the
   // initialization.
-  // (4) the navigation is a primary main frame navigation, as the cookie
-  // change information will only be used in the inactive document control
-  // logic.
+  // (4) the navigation is a primary main frame navigation or it's for
+  // prerendering a main frame, as the cookie change information will only be
+  // used to determined if a page can be restored from back/forward cache, so
+  // subframe navigation can be ignored.
   return frame_tree_node_->navigator()
              .controller()
              .GetBackForwardCache()
              .should_allow_storing_pages_with_cache_control_no_store() &&
-         !IsPageActivation() && !IsSameDocument() && IsInPrimaryMainFrame() &&
+         !IsPageActivation() && !IsSameDocument() &&
+         (IsInPrimaryMainFrame() || IsInPrerenderedMainFrame()) &&
          common_params_->url.SchemeIsHTTPOrHTTPS();
 }
 
diff --git a/content/browser/renderer_host/policy_container_host.cc b/content/browser/renderer_host/policy_container_host.cc
index e044d0d0..5b9977d 100644
--- a/content/browser/renderer_host/policy_container_host.cc
+++ b/content/browser/renderer_host/policy_container_host.cc
@@ -35,31 +35,6 @@
 
 namespace content {
 
-bool operator==(const PolicyContainerPolicies& lhs,
-                const PolicyContainerPolicies& rhs) {
-  return lhs.referrer_policy == rhs.referrer_policy &&
-         lhs.ip_address_space == rhs.ip_address_space &&
-         lhs.is_web_secure_context == rhs.is_web_secure_context &&
-         std::ranges::equal(lhs.content_security_policies,
-                            rhs.content_security_policies) &&
-         lhs.cross_origin_opener_policy == rhs.cross_origin_opener_policy &&
-         lhs.cross_origin_embedder_policy == rhs.cross_origin_embedder_policy &&
-         lhs.document_isolation_policy == rhs.document_isolation_policy &&
-         lhs.integrity_policy == rhs.integrity_policy &&
-         lhs.integrity_policy_report_only == rhs.integrity_policy_report_only &&
-         lhs.sandbox_flags == rhs.sandbox_flags &&
-         lhs.is_credentialless == rhs.is_credentialless &&
-         lhs.can_navigate_top_without_user_gesture ==
-             rhs.can_navigate_top_without_user_gesture &&
-         lhs.cross_origin_isolation_enabled_by_dip ==
-             rhs.cross_origin_isolation_enabled_by_dip;
-}
-
-bool operator!=(const PolicyContainerPolicies& lhs,
-                const PolicyContainerPolicies& rhs) {
-  return !(lhs == rhs);
-}
-
 std::ostream& operator<<(std::ostream& out,
                          const PolicyContainerPolicies& policies) {
   out << "{ referrer_policy: " << policies.referrer_policy
diff --git a/content/browser/renderer_host/policy_container_host.h b/content/browser/renderer_host/policy_container_host.h
index 9ab9c211..8771bbc6 100644
--- a/content/browser/renderer_host/policy_container_host.h
+++ b/content/browser/renderer_host/policy_container_host.h
@@ -82,6 +82,11 @@
   blink::mojom::PolicyContainerPoliciesPtr ToMojoPolicyContainerPolicies()
       const;
 
+  // PolicyContainerPolicies structs are comparable for equality.
+  CONTENT_EXPORT friend bool operator==(const PolicyContainerPolicies&,
+                                        const PolicyContainerPolicies&) =
+      default;
+
   // The referrer policy for the associated document. If not overwritten via a
   // call to SetReferrerPolicy (for example after parsing the Referrer-Policy
   // header or a meta tag), the default referrer policy will be applied to the
@@ -155,12 +160,6 @@
   bool cross_origin_isolation_enabled_by_dip = false;
 };
 
-// PolicyContainerPolicies structs are comparable for equality.
-CONTENT_EXPORT bool operator==(const PolicyContainerPolicies& lhs,
-                               const PolicyContainerPolicies& rhs);
-CONTENT_EXPORT bool operator!=(const PolicyContainerPolicies& lhs,
-                               const PolicyContainerPolicies& rhs);
-
 // Streams a human-readable string representation of |policies| to |out|.
 CONTENT_EXPORT std::ostream& operator<<(
     std::ostream& out,
diff --git a/content/browser/webrtc/resources/webrtc_internals.html b/content/browser/webrtc/resources/webrtc_internals.html
index f8c498a..4c73020 100644
--- a/content/browser/webrtc/resources/webrtc_internals.html
+++ b/content/browser/webrtc/resources/webrtc_internals.html
@@ -138,34 +138,13 @@
     </details>
 
     <p id="content-root"></p>
-    <template id="statsrow-template">
-      <td></td>
-      <td></td>
-      <td><a></a></td>
-    </template>
+    <template id="statsrow-template"><td></td><td></td><td><a></a></td></template>
     <template id="summary-template"><td><details><summary></summary></details></td></template>
-    <template id="container-template">
-      <div></div>
-      <div><canvas></canvas></div>
-    </template>
-    <template id="summary-span-template">
-      <summary><span></span></summary>
-    </template>
-    <template id="checkbox-template">
-      <input type="checkbox" checked />
-    </template>
-    <template id="trth-template">
-      <tbody>
-        <tr>
-          <th colspan=2></th>
-        </tr>
-      </tbody>
-    </template>
-    <template id="td-colspan-template">
-      <td colspan=2></td>
-    </template>
-    <template id="time-event-template"><tbody>
-      <tr><th>Time</th><th class="update-log-header-event">Event</th></tr>
-    </tbody></template>
+    <template id="container-template"><div></div><div><canvas></canvas></div></template>
+    <template id="summary-span-template"><summary><span></span></summary></template>
+    <template id="checkbox-template"><input type="checkbox" checked></template>
+    <template id="trth-template"><tbody><tr><th colspan=2></th></tr></tbody></template>
+    <template id="td-colspan-template"><td colspan=2></td></template>
+    <template id="time-event-template"><tbody><tr><th>Time</th><th class="update-log-header-event">Event</th></tr></tbody></template>
   </body>
 </html>
\ No newline at end of file
diff --git a/content/public/browser/back_forward_cache.h b/content/public/browser/back_forward_cache.h
index 02ef6858..495a34f5 100644
--- a/content/public/browser/back_forward_cache.h
+++ b/content/public/browser/back_forward_cache.h
@@ -163,9 +163,8 @@
     // will mask extension related reasons as "Extensions".
     const std::string report_string;
 
-    bool operator<(const DisabledReason&) const;
+    std::weak_ordering operator<=>(const DisabledReason&) const;
     bool operator==(const DisabledReason&) const;
-    bool operator!=(const DisabledReason&) const;
   };
 
   // Prevents the `render_frame_host` from entering the BackForwardCache. A
diff --git a/docs/ios/build_instructions.md b/docs/ios/build_instructions.md
index f667e929..3cfed37 100644
--- a/docs/ios/build_instructions.md
+++ b/docs/ios/build_instructions.md
@@ -324,9 +324,8 @@
 $ out/Debug-iphonesimulator/iossim -i out/Debug-iphonesimulator/Chromium.app
 ```
 
-From Xcode 9 on, `iossim` no longer automatically launches the Simulator. This must now
-be done manually from within Xcode (`Xcode > Open Developer Tool > Simulator`), and
-also must be done *after* running `iossim`.
+Note that `iossim` does not automatically launch the Simulator. This must be
+done manually *after* running `iossim`.
 
 ### Passing arguments
 
@@ -434,10 +433,9 @@
 files; instead see the procedures for [working with
 files](working_with_files.md).
 
-If you have problems building, join us in `#chromium` on `irc.freenode.net` and
-ask there. As mentioned above, be sure that the
-[waterfall](https://build.chromium.org/buildbot/waterfall/) is green and the tree
-is open before checking out. This will increase your chances of success.
+If you have problems building, you can join us on
+[Slack](https://www.chromium.org/developers/slack/) or one of our [mailing
+lists](https://www.chromium.org/developers/technical-discussion-groups/).
 
 ### Debugging
 
diff --git "a/infra/config/generated/builders/ci/Android x64 Builder All Targets \050dbg\051/properties.json" "b/infra/config/generated/builders/ci/Android x64 Builder All Targets \050dbg\051/properties.json"
index d1b6c0a..aace681a 100644
--- "a/infra/config/generated/builders/ci/Android x64 Builder All Targets \050dbg\051/properties.json"
+++ "b/infra/config/generated/builders/ci/Android x64 Builder All Targets \050dbg\051/properties.json"
@@ -57,13 +57,15 @@
   },
   "$build/siso": {
     "configs": [
-      "builder"
+      "builder",
+      "remote-link"
     ],
     "enable_cloud_monitoring": true,
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
     "metrics_project": "chromium-reclient-metrics",
+    "output_local_strategy": "greedy",
     "project": "rbe-chromium-trusted",
     "remote_jobs": 500
   },
diff --git "a/infra/config/generated/builders/ci/Android x64 Builder All Targets \050dbg\051/shadow-properties.json" "b/infra/config/generated/builders/ci/Android x64 Builder All Targets \050dbg\051/shadow-properties.json"
index dc0a10e9..074c5b0 100644
--- "a/infra/config/generated/builders/ci/Android x64 Builder All Targets \050dbg\051/shadow-properties.json"
+++ "b/infra/config/generated/builders/ci/Android x64 Builder All Targets \050dbg\051/shadow-properties.json"
@@ -1,13 +1,15 @@
 {
   "$build/siso": {
     "configs": [
-      "builder"
+      "builder",
+      "remote-link"
     ],
     "enable_cloud_monitoring": true,
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
     "experiments": [],
     "metrics_project": "chromium-reclient-metrics",
+    "output_local_strategy": "greedy",
     "project": "rbe-chromium-untrusted",
     "remote_jobs": 500
   }
diff --git a/infra/config/subprojects/chromium/ci/chromium.android.star b/infra/config/subprojects/chromium/ci/chromium.android.star
index 3971fe6..ae49a5e 100644
--- a/infra/config/subprojects/chromium/ci/chromium.android.star
+++ b/infra/config/subprojects/chromium/ci/chromium.android.star
@@ -413,6 +413,9 @@
     cq_mirrors_console_view = "mirrors",
     contact_team_email = "clank-engprod@google.com",
     execution_timeout = 7 * time.hour,
+    # enable remote link to mitigate bot died https://crbug.com/418817397
+    siso_output_local_strategy = "greedy",
+    siso_remote_linking = True,
 )
 
 ci.builder(
diff --git a/ios/chrome/browser/account_picker/ui_bundled/account_picker_coordinator.mm b/ios/chrome/browser/account_picker/ui_bundled/account_picker_coordinator.mm
index 04b3fa35..198cc52 100644
--- a/ios/chrome/browser/account_picker/ui_bundled/account_picker_coordinator.mm
+++ b/ios/chrome/browser/account_picker/ui_bundled/account_picker_coordinator.mm
@@ -38,6 +38,9 @@
     UINavigationControllerDelegate,
     UIViewControllerTransitioningDelegate>
 
+// YES if the an add account operation is in progress.
+@property(nonatomic, assign) BOOL openAddAccountOperationInProgress;
+
 @end
 
 @implementation AccountPickerCoordinator {
@@ -167,9 +170,16 @@
 
 // Opens an AddAccountSigninCoordinator to add an account to the device.
 - (void)openAddAccountCoordinator {
+  if (self.openAddAccountOperationInProgress) {
+    // According to crbug.com/418774148, it is possible for the user to start
+    // twice an open add account operation. Ignore the second call.
+    return;
+  }
+  self.openAddAccountOperationInProgress = YES;
   __weak __typeof(self) weakSelf = self;
   [self.delegate accountPickerCoordinator:self
              openAddAccountWithCompletion:^(id<SystemIdentity> identity) {
+               weakSelf.openAddAccountOperationInProgress = NO;
                [weakSelf addAccountCompletionWithIdentity:identity];
              }];
   [self.logger logAccountPickerAddAccountScreenOpened];
diff --git a/ios/chrome/browser/intelligence/glic/coordinator/BUILD.gn b/ios/chrome/browser/intelligence/glic/coordinator/BUILD.gn
index 611d450..3efe2ba 100644
--- a/ios/chrome/browser/intelligence/glic/coordinator/BUILD.gn
+++ b/ios/chrome/browser/intelligence/glic/coordinator/BUILD.gn
@@ -9,6 +9,11 @@
     "glic_consent_mediator.h",
     "glic_consent_mediator.mm",
     "glic_consent_mediator_delegate.h",
+    "glic_coordinator.h",
+    "glic_coordinator.mm",
+    "glic_mediator.h",
+    "glic_mediator.mm",
+    "glic_mediator_delegate.h",
     "glic_promo_coordinator.h",
     "glic_promo_coordinator.mm",
     "glic_promo_scene_agent.h",
diff --git a/ios/chrome/browser/intelligence/glic/coordinator/glic_coordinator.h b/ios/chrome/browser/intelligence/glic/coordinator/glic_coordinator.h
new file mode 100644
index 0000000..9328d5d
--- /dev/null
+++ b/ios/chrome/browser/intelligence/glic/coordinator/glic_coordinator.h
@@ -0,0 +1,15 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_COORDINATOR_GLIC_COORDINATOR_H_
+#define IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_COORDINATOR_GLIC_COORDINATOR_H_
+
+#import "ios/chrome/browser/shared/coordinator/chrome_coordinator/chrome_coordinator.h"
+
+// Coordinator that manages the first run and any GLIC triggers.
+@interface GLICCoordinator : ChromeCoordinator
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_COORDINATOR_GLIC_COORDINATOR_H_
diff --git a/ios/chrome/browser/intelligence/glic/coordinator/glic_coordinator.mm b/ios/chrome/browser/intelligence/glic/coordinator/glic_coordinator.mm
new file mode 100644
index 0000000..2fb198b
--- /dev/null
+++ b/ios/chrome/browser/intelligence/glic/coordinator/glic_coordinator.mm
@@ -0,0 +1,54 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/intelligence/glic/coordinator/glic_coordinator.h"
+
+#import "ios/chrome/browser/intelligence/glic/coordinator/glic_mediator.h"
+#import "ios/chrome/browser/intelligence/glic/coordinator/glic_mediator_delegate.h"
+#import "ios/chrome/browser/intelligence/glic/ui/glic_navigation_controller.h"
+#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
+
+@interface GLICCoordinator () <UISheetPresentationControllerDelegate,
+                               GLICMediatorDelegate>
+
+@end
+
+@implementation GLICCoordinator {
+  // Mediator for handling all logic related to GLIC.
+  GLICMediator* _mediator;
+  // Navigation view controller owning the promo and the consent UI.
+  GLICNavigationController* _navigationController;
+}
+
+#pragma mark - ChromeCoordinator
+
+- (void)start {
+  PrefService* pref_service = self.profile->GetPrefs();
+  CHECK(pref_service);
+
+  _mediator = [[GLICMediator alloc] initWithPrefService:pref_service];
+  _mediator.delegate = self;
+
+  _navigationController = [[GLICNavigationController alloc] init];
+  _navigationController.sheetPresentationController.delegate = self;
+  _navigationController.mutator = _mediator;
+
+  [self.baseViewController presentViewController:_navigationController
+                                        animated:YES
+                                      completion:nil];
+  [super start];
+}
+
+- (void)stop {
+  [super stop];
+}
+
+#pragma mark - GLICConsentMediatorDelegate
+
+// Dismisses the UI by stopping the coordinator.
+- (void)dismissGLICConsentUI {
+  [self stop];
+}
+
+@end
diff --git a/ios/chrome/browser/intelligence/glic/coordinator/glic_mediator.h b/ios/chrome/browser/intelligence/glic/coordinator/glic_mediator.h
new file mode 100644
index 0000000..688a00b
--- /dev/null
+++ b/ios/chrome/browser/intelligence/glic/coordinator/glic_mediator.h
@@ -0,0 +1,26 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_COORDINATOR_GLIC_MEDIATOR_H_
+#define IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_COORDINATOR_GLIC_MEDIATOR_H_
+
+#import <Foundation/Foundation.h>
+
+#import "ios/chrome/browser/intelligence/glic/ui/glic_consent_mutator.h"
+
+class PrefService;
+
+@protocol GLICMediatorDelegate;
+
+// GLIC Mediator.
+@interface GLICMediator : NSObject <GLICConsentMutator>
+
+- (instancetype)initWithPrefService:(PrefService*)prefService;
+
+// The delegate for this mediator.
+@property(nonatomic, weak) id<GLICMediatorDelegate> delegate;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_COORDINATOR_GLIC_MEDIATOR_H_
diff --git a/ios/chrome/browser/intelligence/glic/coordinator/glic_mediator.mm b/ios/chrome/browser/intelligence/glic/coordinator/glic_mediator.mm
new file mode 100644
index 0000000..bc15ab3
--- /dev/null
+++ b/ios/chrome/browser/intelligence/glic/coordinator/glic_mediator.mm
@@ -0,0 +1,49 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/intelligence/glic/coordinator/glic_mediator.h"
+
+#import <memory>
+
+#import "base/metrics/histogram_functions.h"
+#import "components/prefs/pref_service.h"
+#import "ios/chrome/browser/intelligence/glic/coordinator/glic_mediator_delegate.h"
+#import "ios/chrome/browser/intelligence/glic/metrics/glic_metrics.h"
+#import "ios/chrome/browser/shared/model/prefs/pref_names.h"
+
+@implementation GLICMediator {
+  raw_ptr<PrefService> _prefService;
+}
+
+- (instancetype)initWithPrefService:(PrefService*)prefService {
+  self = [super init];
+  if (self) {
+    _prefService = prefService;
+  }
+  return self;
+}
+
+#pragma mark - GLICConsentMutator
+
+// Did consent to GLIC.
+- (void)didConsentGLIC {
+  base::UmaHistogramEnumeration(kGLICConsentTypeHistogram,
+                                GLICConsentType::kAccept);
+  _prefService->SetBoolean(prefs::kIOSGLICConsent, YES);
+  [_delegate dismissGLICConsentUI];
+}
+
+// Did dismisses the Consent UI.
+- (void)didRefuseGLICConsent {
+  base::UmaHistogramEnumeration(kGLICConsentTypeHistogram,
+                                GLICConsentType::kCancel);
+  [_delegate dismissGLICConsentUI];
+}
+
+// Did close GLIC Promo UI.
+- (void)didCloseGLICPromo {
+  [_delegate dismissGLICConsentUI];
+}
+
+@end
diff --git a/ios/chrome/browser/intelligence/glic/coordinator/glic_mediator_delegate.h b/ios/chrome/browser/intelligence/glic/coordinator/glic_mediator_delegate.h
new file mode 100644
index 0000000..1d417f3
--- /dev/null
+++ b/ios/chrome/browser/intelligence/glic/coordinator/glic_mediator_delegate.h
@@ -0,0 +1,18 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_COORDINATOR_GLIC_MEDIATOR_DELEGATE_H_
+#define IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_COORDINATOR_GLIC_MEDIATOR_DELEGATE_H_
+
+@class GLICConsentMediator;
+
+// Delegate for the GLICMediator.
+@protocol GLICMediatorDelegate
+
+// Dismisses the GLIC consent UI.
+- (void)dismissGLICConsentUI;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_COORDINATOR_GLIC_MEDIATOR_DELEGATE_H_
diff --git a/ios/chrome/browser/intelligence/page_action_menu/coordinator/page_action_menu_coordinator.mm b/ios/chrome/browser/intelligence/page_action_menu/coordinator/page_action_menu_coordinator.mm
index 51b25258..d044517c 100644
--- a/ios/chrome/browser/intelligence/page_action_menu/coordinator/page_action_menu_coordinator.mm
+++ b/ios/chrome/browser/intelligence/page_action_menu/coordinator/page_action_menu_coordinator.mm
@@ -97,6 +97,7 @@
 
 // Shows GLIC consent.
 - (void)showGLICConsent {
+  // TODO(crbug.com/418752929): Call GLICCoordinator to call GLIC consent.
   _glicConsentCoordinator = [[GLICConsentCoordinator alloc]
       initWithBaseViewController:self.baseViewController
                          browser:self.browser];
diff --git a/ios/chrome/browser/metrics/model/tab_usage_recorder_egtest.mm b/ios/chrome/browser/metrics/model/tab_usage_recorder_egtest.mm
index 87f5ba5..35359fc 100644
--- a/ios/chrome/browser/metrics/model/tab_usage_recorder_egtest.mm
+++ b/ios/chrome/browser/metrics/model/tab_usage_recorder_egtest.mm
@@ -488,15 +488,7 @@
 
 // Test that the USER_DID_NOT_WAIT metric is not logged when the user opens
 // and closes the settings UI while the evicted tab is still reloading.
-// TODO(crbug.com/369787152): The test is flaky on simulator.
-#if TARGET_OS_SIMULATOR
-#define MAYBE_testEvictedTabReloadSettingsAndBack \
-  FLAKY_testEvictedTabReloadSettingsAndBack
-#else
-#define MAYBE_testEvictedTabReloadSettingsAndBack \
-  testEvictedTabReloadSettingsAndBack
-#endif
-- (void)MAYBE_testEvictedTabReloadSettingsAndBack {
+- (void)testEvictedTabReloadSettingsAndBack {
   std::map<GURL, std::string> responses;
   const GURL slowURL = web::test::HttpServer::MakeUrl("http://slow");
   responses[slowURL] = "Slow Page";
diff --git a/ios/chrome/browser/shared/model/profile/scoped_profile_keep_alive_ios.h b/ios/chrome/browser/shared/model/profile/scoped_profile_keep_alive_ios.h
index 2d65941c..e3dd4cb 100644
--- a/ios/chrome/browser/shared/model/profile/scoped_profile_keep_alive_ios.h
+++ b/ios/chrome/browser/shared/model/profile/scoped_profile_keep_alive_ios.h
@@ -28,7 +28,7 @@
 // ProfileManagerIOS is destroyed. A good way to ensure this happen is
 // to implement ProfileManagerObserverIOS API and to reset the objects
 // when `OnProfileManagerWillBeDestroyed(...)` is called.
-class ScopedProfileKeepAliveIOS {
+class [[maybe_unused, nodiscard]] ScopedProfileKeepAliveIOS {
  public:
   using Cleanup = base::OnceClosure;
   using PassKey = base::PassKey<ProfileManagerIOS>;
diff --git a/net/third_party/quiche/src b/net/third_party/quiche/src
index 8f26ded..7802d58 160000
--- a/net/third_party/quiche/src
+++ b/net/third_party/quiche/src
@@ -1 +1 @@
-Subproject commit 8f26ded8fab679ca935e490a1a324faeccbd78e5
+Subproject commit 7802d58f2294c60cbe063fce822d4872aaa52724
diff --git a/services/network/public/cpp/simple_host_resolver_unittest.cc b/services/network/public/cpp/simple_host_resolver_unittest.cc
index dcfc3f3b..e929436 100644
--- a/services/network/public/cpp/simple_host_resolver_unittest.cc
+++ b/services/network/public/cpp/simple_host_resolver_unittest.cc
@@ -139,11 +139,16 @@
     if (request.reset_client) {
       network_context->SetResetClientFor(request.host_port_pair);
     }
+    // The ios simulator may return the NAT64 address rather than
+    // the IPv4 address. The parameters specify the dns query type
+    // to resolve the issue.
+    auto resolver_parameters = network::mojom::ResolveHostParameters::New();
+    resolver_parameters->dns_query_type = net::DnsQueryType::A;
     simple_resolver->ResolveHost(
         network::mojom::HostResolverHost::NewHostPortPair(
             request.host_port_pair),
-        net::NetworkAnonymizationKey(),
-        /*optional_parameters=*/nullptr, future->GetCallback());
+        net::NetworkAnonymizationKey(), std::move(resolver_parameters),
+        future->GetCallback());
     futures.emplace_back(std::move(future), std::move(result));
   }
 
diff --git a/services/viz/public/mojom/BUILD.gn b/services/viz/public/mojom/BUILD.gn
index bb54157..ded05f80 100644
--- a/services/viz/public/mojom/BUILD.gn
+++ b/services/viz/public/mojom/BUILD.gn
@@ -69,6 +69,7 @@
     "//cc/mojom:element_id",
     "//cc/mojom:hit_test_opaqueness",
     "//cc/mojom:layer_type",
+    "//cc/mojom:missing_tile_reason",
     "//cc/mojom:paint_flags",
     "//cc/mojom:ui_resource_id",
     "//gpu/ipc/common:interfaces",
diff --git a/services/viz/public/mojom/compositing/tiling.mojom b/services/viz/public/mojom/compositing/tiling.mojom
index 26dd1de..0f751629 100644
--- a/services/viz/public/mojom/compositing/tiling.mojom
+++ b/services/viz/public/mojom/compositing/tiling.mojom
@@ -7,6 +7,7 @@
 import "services/viz/public/mojom/compositing/transferable_resource.mojom";
 import "skia/public/mojom/skcolor4f.mojom";
 import "ui/gfx/geometry/mojom/geometry.mojom";
+import "cc/mojom/missing_tile_reason.mojom";
 
 // Describes a tile resource prepared by the client.
 struct TileResource {
@@ -17,17 +18,10 @@
   bool is_checkered;
 };
 
-// For tiles that are missing or otherwise not ready to draw, this is the
-// reason why.
-enum MissingTileReason {
-  kOutOfMemory,
-  kResourceNotReady,
-};
-
 // Describes the visual contents of a tile.
 union TileContents {
   // No contents.
-  MissingTileReason missing_reason;
+  cc.mojom.MissingTileReason missing_reason;
 
   // A rasterized tile, identified by a Viz resource which the client produced.
   TileResource resource;
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 2dcd46c..13535b78 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -8430,28 +8430,6 @@
             ]
         }
     ],
-    "DropInputEventsWhilePaintHolding": [
-        {
-            "platforms": [
-                "android",
-                "android_weblayer",
-                "android_webview",
-                "chromeos",
-                "chromeos_lacros",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "DropInputEventsWhilePaintHolding"
-                    ]
-                }
-            ]
-        }
-    ],
     "DwaFeature": [
         {
             "platforms": [
diff --git a/third_party/README.chromium.template b/third_party/README.chromium.template
index 25f426a4..e9d643b 100644
--- a/third_party/README.chromium.template
+++ b/third_party/README.chromium.template
@@ -4,6 +4,7 @@
 Version: A searchable version number for the package (if the package does not version or is versioned by date or revision this field should be "N/A" and the revision, or date should be enumerated in the appropriate field).  If the dependency is managed by an autoroller or a script, you must ensure the uprev process also updates the README.chromium file with the correct Version.
 Date: (OPTIONAL if Version or Revision is supplied) The date that the package was updated, in format YYYY-MM-DD.
 Revision: (REQUIRED for dependencies which have a git repository as an upstream, OPTIONAL if the upstream is not a git repository and Version or Date is supplied). If the dependency is managed by an autoroller or a script, you must ensure the uprev process also updates the README.chromium file with the correct Revision.
+Update Mechanism: (REQUIRED, one of ('Autoroll', 'Manual', 'Static', or 'Static.HardFork')) Optionally followed by a link to approval in the form of a crbug. Specifies by what general mechanism (if any) the dependency is updated. Refer to //docs/adding_to_third_party.md#update-mechanism for the complete list of specifiers, their meanings, and requirements for bug links.
 License: The license/s under which the package is distributed. See ALLOWED_SPDX_LICENSES in depot_tools for the full list of allowed licenses https://source.chromium.org/chromium/chromium/tools/depot_tools/+/main:metadata/fields/custom/license_allowlist.py. If your dependency has multiple licenses, see https://chromium.googlesource.com/chromium/src/+/main/docs/adding_to_third_party.md#add-a-license-file-and-run-related-checks for guidance on how supply multiple entries or choose the best fit.
 License File: A file path from //third_party or a relative path from the README.chromium to a child directory, whichever makes more sense for your dependency. The file should contain a copy of the package's license and correspond to the License provided above. All packages should contain a valid license, regardless of whether it is shipped or not.
 Shipped: Either yes or no depending on whether this package should be included in about:credits. Anything shipped as part of a release or by component-updater should be credited.
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle
index c701446b..4235b4f 100644
--- a/third_party/androidx/build.gradle
+++ b/third_party/androidx/build.gradle
@@ -305,7 +305,7 @@
     google()
     maven {
         // This URL is generated by the fetch_all_androidx.py script.
-        url 'https://androidx.dev/snapshots/builds/13518877/artifacts/repository'
+        url 'https://androidx.dev/snapshots/builds/13522710/artifacts/repository'
     }
     mavenCentral()
 }
diff --git a/third_party/angle b/third_party/angle
index dcbcee8..6518078 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit dcbcee8ab32af9ddc7ae1e91c42d995e5281602c
+Subproject commit 65180785da62e5d12f0d2a28fa0cca1fe98f83ca
diff --git a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
index 9f4ea7b..a961775 100644
--- a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
+++ b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
@@ -4888,6 +4888,10 @@
   kPopoverShown = 5579,
   kInputParsedParentOptionOrOptgroup = 5580,
   kNavigatorUAData_toJSON = 5581,
+  kEditContextUpdateTextRangePrecedesOrOverlapsSelection = 5582,
+  kEditContextUpdateTextRangePrecedesCompositionRange = 5583,
+  kEditContextUpdateTextRangeOverlapsCompositionRange = 5584,
+  kEditContextUpdateSelectionDuringActiveComposition = 5585,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots. Also don't add extra
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index b42efe7..c817715 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -2986,8 +2986,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_transport_error.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl2_rendering_context.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl2_rendering_context.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl2_rendering_context_webgpu.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl2_rendering_context_webgpu.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_active_info.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_active_info.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_blend_func_extended.cc",
@@ -3046,8 +3044,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_renderbuffer.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_rendering_context.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_rendering_context.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_rendering_context_webgpu.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_rendering_context_webgpu.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_sampler.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_sampler.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_webgl_shader.cc",
@@ -3282,8 +3278,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_boolean_mediatrackconstraints.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_canvasfilter_string.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_canvasfilter_string.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_canvasrenderingcontext2d_gpucanvascontext_imagebitmaprenderingcontext_webgl2renderingcontext_webgl2renderingcontextwebgpu_webglrenderingcontext_webglrenderingcontextwebgpu.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_canvasrenderingcontext2d_gpucanvascontext_imagebitmaprenderingcontext_webgl2renderingcontext_webgl2renderingcontextwebgpu_webglrenderingcontext_webglrenderingcontextwebgpu.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_canvasrenderingcontext2d_gpucanvascontext_imagebitmaprenderingcontext_webgl2renderingcontext_webglrenderingcontext.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_canvasrenderingcontext2d_gpucanvascontext_imagebitmaprenderingcontext_webgl2renderingcontext_webglrenderingcontext.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_client_messageport_serviceworker.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_client_messageport_serviceworker.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_constraindomstringparameters_string_stringsequence.cc",
@@ -3310,8 +3306,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_gpuautolayoutmode_gpupipelinelayout.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_gpubufferbinding_gpuexternaltexture_gpusampler_gputextureview.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_gpubufferbinding_gpuexternaltexture_gpusampler_gputextureview.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_gpucanvascontext_imagebitmaprenderingcontext_offscreencanvasrenderingcontext2d_webgl2renderingcontext_webgl2renderingcontextwebgpu_webglrenderingcontext_webglrenderingcontextwebgpu.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_gpucanvascontext_imagebitmaprenderingcontext_offscreencanvasrenderingcontext2d_webgl2renderingcontext_webgl2renderingcontextwebgpu_webglrenderingcontext_webglrenderingcontextwebgpu.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_gpucanvascontext_imagebitmaprenderingcontext_offscreencanvasrenderingcontext2d_webgl2renderingcontext_webglrenderingcontext.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_gpucanvascontext_imagebitmaprenderingcontext_offscreencanvasrenderingcontext2d_webgl2renderingcontext_webglrenderingcontext.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_gpuextent3ddict_unsignedlongenforcerangesequence.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_gpuextent3ddict_unsignedlongenforcerangesequence.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_union_gpuorigin2ddict_unsignedlongenforcerangesequence.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni
index e48d158c..e378f59 100644
--- a/third_party/blink/renderer/bindings/idl_in_modules.gni
+++ b/third_party/blink/renderer/bindings/idl_in_modules.gni
@@ -997,7 +997,6 @@
   "//third_party/blink/renderer/modules/webgl/ovr_multiview_2.idl",
   "//third_party/blink/renderer/modules/webgl/webgl2_rendering_context.idl",
   "//third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.idl",
-  "//third_party/blink/renderer/modules/webgl/webgl2_rendering_context_webgpu.idl",
   "//third_party/blink/renderer/modules/webgl/webgl_active_info.idl",
   "//third_party/blink/renderer/modules/webgl/webgl_blend_func_extended.idl",
   "//third_party/blink/renderer/modules/webgl/webgl_buffer.idl",
@@ -1030,7 +1029,6 @@
   "//third_party/blink/renderer/modules/webgl/webgl_renderbuffer.idl",
   "//third_party/blink/renderer/modules/webgl/webgl_rendering_context.idl",
   "//third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.idl",
-  "//third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu.idl",
   "//third_party/blink/renderer/modules/webgl/webgl_sampler.idl",
   "//third_party/blink/renderer/modules/webgl/webgl_shader.idl",
   "//third_party/blink/renderer/modules/webgl/webgl_shader_pixel_local_storage.idl",
diff --git a/third_party/blink/renderer/core/dom/pseudo_element.cc b/third_party/blink/renderer/core/dom/pseudo_element.cc
index 8191bac..8277f94 100644
--- a/third_party/blink/renderer/core/dom/pseudo_element.cc
+++ b/third_party/blink/renderer/core/dom/pseudo_element.cc
@@ -491,9 +491,21 @@
 
   DCHECK(!style.ContentBehavesAsNormal());
   DCHECK(!style.ContentPreventsBoxGeneration());
-  for (const ContentData* content = style.GetContentData(); content;
+  for (ContentData* content = style.GetContentData(); content;
        content = content->Next()) {
-    if (!content->IsAltText() && !content->IsAltCounter()) {
+    if (auto* alt_counter_data = DynamicTo<AltCounterContentData>(content)) {
+      LayoutObject* child =
+          alt_counter_data->CreateLayoutObject(*layout_object);
+      auto* layout_counter = DynamicTo<LayoutCounter>(child);
+      Vector<int> counter_values = context.counters_context.GetCounterValues(
+          *layout_object, layout_counter->Identifier(),
+          layout_counter->Separator().IsNull());
+      String text = layout_counter->UpdateCounter(std::move(counter_values));
+      alt_counter_data->SetText(std::move(text));
+      child->Destroy();
+      continue;
+    }
+    if (!content->IsAltText()) {
       LayoutObject* child = content->CreateLayoutObject(*layout_object);
       if (layout_object->IsChildAllowed(child, style)) {
         layout_object->AddChild(child);
diff --git a/third_party/blink/renderer/core/editing/ime/edit_context.cc b/third_party/blink/renderer/core/editing/ime/edit_context.cc
index 34ee7c40..366d489 100644
--- a/third_party/blink/renderer/core/editing/ime/edit_context.cc
+++ b/third_party/blink/renderer/core/editing/ime/edit_context.cc
@@ -243,7 +243,16 @@
   TRACE_EVENT2("ime", "EditContext::updateSelection", "start",
                std::to_string(start), "end", std::to_string(end));
 
-  SetSelection(std::min(start, text_.length()), std::min(end, text_.length()));
+  uint32_t bound_start = std::min(start, text_.length());
+  uint32_t bound_end = std::min(end, text_.length());
+  if (has_composition_ &&
+      (bound_start != selection_start_ || bound_end != selection_end_)) {
+    UseCounter::Count(
+        GetExecutionContext(),
+        WebFeature::kEditContextUpdateSelectionDuringActiveComposition);
+  }
+
+  SetSelection(bound_start, bound_end);
   if (!has_composition_)
     return;
 
@@ -309,6 +318,29 @@
   }
   end = std::min(end, text_.length());
   start = std::min(start, end);
+
+  if (OrderedSelectionEnd() > start) {
+    UseCounter::Count(
+        GetExecutionContext(),
+        WebFeature::kEditContextUpdateTextRangePrecedesOrOverlapsSelection);
+  }
+
+  if (has_composition_ && composition_range_end_ > start) {
+    if (composition_range_start_ >= end) {
+      // Example:
+      // Composition range: [3, 6], Update range: [1, 2]
+      UseCounter::Count(
+          GetExecutionContext(),
+          WebFeature::kEditContextUpdateTextRangePrecedesCompositionRange);
+    } else {
+      // Example:
+      // Composition range: [3, 6], Update range: [4, 7]
+      UseCounter::Count(
+          GetExecutionContext(),
+          WebFeature::kEditContextUpdateTextRangeOverlapsCompositionRange);
+    }
+  }
+
   text_ = text_.Substring(0, start) + new_text + text_.Substring(end);
 }
 
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
index 23dea4b..392b7a1c 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
@@ -80,9 +80,9 @@
 class ScriptState;
 class StaticBitmapImage;
 using V8RenderingContext = class
-    V8UnionCanvasRenderingContext2DOrGPUCanvasContextOrImageBitmapRenderingContextOrWebGL2RenderingContextOrWebGL2RenderingContextWebGPUOrWebGLRenderingContextOrWebGLRenderingContextWebGPU;
+    V8UnionCanvasRenderingContext2DOrGPUCanvasContextOrImageBitmapRenderingContextOrWebGL2RenderingContextOrWebGLRenderingContext;
 using V8OffscreenRenderingContext = class
-    V8UnionGPUCanvasContextOrImageBitmapRenderingContextOrOffscreenCanvasRenderingContext2DOrWebGL2RenderingContextOrWebGL2RenderingContextWebGPUOrWebGLRenderingContextOrWebGLRenderingContextWebGPU;
+    V8UnionGPUCanvasContextOrImageBitmapRenderingContextOrOffscreenCanvasRenderingContext2DOrWebGL2RenderingContextOrWebGLRenderingContext;
 class WebGraphicsContext3DVideoFramePool;
 
 class CORE_EXPORT CanvasRenderingContext
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index cd134f42..74f3a28 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -1001,6 +1001,17 @@
   }
 }
 
+void HTMLCanvasElement::ResetLayer() {
+  if (cc_layer_) {
+    // Orphaning the layer is required to trigger the recreation of a new
+    // layer in the case where destruction is caused by a canvas resize. Test:
+    // virtual/gpu/fast/canvas/canvas-resize-after-paint-without-layout.html
+    cc_layer_->RemoveFromParent();
+    cc_layer_->ClearClient();
+    cc_layer_ = nullptr;
+  }
+}
+
 bool HTMLCanvasElement::PaintsIntoCanvasBuffer() const {
   if (HasOffscreenCanvasFrame()) {
     return false;
@@ -1709,6 +1720,12 @@
   return cc_layer_.get();
 }
 
+void HTMLCanvasElement::ClearLayerTexture() {
+  if (cc_layer_) {
+    cc_layer_->ClearTexture();
+  }
+}
+
 Canvas2DLayerBridge* HTMLCanvasElement::GetOrCreateCanvas2DLayerBridge() {
   DCHECK(IsRenderingContext2D());
 
@@ -1741,6 +1758,12 @@
   return canvas2d_bridge_.get();
 }
 
+void HTMLCanvasElement::SetNeedsPushProperties() {
+  if (cc_layer_) {
+    cc_layer_->SetNeedsSetTransferableResource();
+  }
+}
+
 void HTMLCanvasElement::SetResourceProviderForTesting(
     std::unique_ptr<CanvasResourceProvider> provider,
     const gfx::Size& size) {
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
index 73e24f3..69c39fb 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
@@ -189,8 +189,12 @@
 
   cc::TextureLayer* GetOrCreateCcLayerIfNeeded();
   cc::TextureLayer* GetCcLayerForTesting() { return cc_layer_.get(); }
+  void ClearLayerTexture() override;
+
   Canvas2DLayerBridge* GetOrCreateCanvas2DLayerBridge();
 
+  void SetNeedsPushProperties();
+
   void DiscardResourceProvider() override;
 
   TextDirection GetTextDirection(const ComputedStyle*) override;
@@ -396,6 +400,7 @@
   bool AreAuthorShadowsAllowed() const override { return false; }
 
   void Reset();
+  void ResetLayer();
 
   void SetSurfaceSize(gfx::Size);
 
@@ -439,6 +444,8 @@
   bool ignore_reset_ = false;
   gfx::Rect dirty_rect_;
 
+  scoped_refptr<cc::TextureLayer> cc_layer_;
+
   bool is_opaque_ = false;
   bool is_displayed_ = false;
   unsigned frames_since_last_commit_ = 0;
diff --git a/third_party/blink/renderer/core/html/forms/text_control_element.cc b/third_party/blink/renderer/core/html/forms/text_control_element.cc
index 7af62f8..0021da9 100644
--- a/third_party/blink/renderer/core/html/forms/text_control_element.cc
+++ b/third_party/blink/renderer/core/html/forms/text_control_element.cc
@@ -123,6 +123,23 @@
   }
 }
 
+void AppendText(const String& value,
+                wtf_size_t start,
+                wtf_size_t limit,
+                ContainerNode& container) {
+  Document& doc = container.GetDocument();
+  if (!RuntimeEnabledFeatures::TextareaSplitTextEnabled()) {
+    container.AppendChild(
+        Text::Create(doc, value.Substring(start, limit - start)));
+    return;
+  }
+  constexpr wtf_size_t kTextChunkSize = 8192u;
+  for (wtf_size_t i = start; i < limit; i += kTextChunkSize) {
+    container.AppendChild(Text::Create(
+        doc, value.Substring(i, std::min(limit - i, kTextChunkSize))));
+  }
+}
+
 }  // namespace
 
 TextControlElement::TextControlElement(const QualifiedName& tag_name,
@@ -968,7 +985,12 @@
     inner_editor->RemoveChildren();
   } else if (!RuntimeEnabledFeatures::TextareaLineEndingsAsBrEnabled() ||
              IsA<HTMLInputElement>(this)) {
-    ReplaceChildrenWithText(inner_editor, value, ASSERT_NO_EXCEPTION);
+    if (RuntimeEnabledFeatures::TextareaSplitTextEnabled()) {
+      inner_editor->RemoveChildren();
+      AppendText(value, 0, value.length(), *inner_editor);
+    } else {
+      ReplaceChildrenWithText(inner_editor, value, ASSERT_NO_EXCEPTION);
+    }
   } else {
     inner_editor->RemoveChildren();
     // For <textarea>, \n is replaced with <br>.
@@ -992,13 +1014,12 @@
   while (start < value.length()) {
     wtf_size_t i = value.find('\n', start);
     if (i == WTF::kNotFound) {
-      container.AppendChild(Text::Create(doc, value.Substring(start)));
+      AppendText(value, start, value.length(), container);
       break;
     }
     if (start != i) {
       // Append [start, i).
-      container.AppendChild(
-          Text::Create(doc, value.Substring(start, i - start)));
+      AppendText(value, start, i, container);
     }
     // Append a BR.
     container.AppendChild(MakeGarbageCollected<HTMLBRElement>(doc));
diff --git a/third_party/blink/renderer/core/layout/layout_counter.cc b/third_party/blink/renderer/core/layout/layout_counter.cc
index 147f9cc..3436d2f 100644
--- a/third_party/blink/renderer/core/layout/layout_counter.cc
+++ b/third_party/blink/renderer/core/layout/layout_counter.cc
@@ -78,7 +78,7 @@
   LayoutText::WillBeDestroyed();
 }
 
-void LayoutCounter::UpdateCounter(Vector<int> counter_values) {
+String LayoutCounter::UpdateCounter(Vector<int> counter_values) {
   NOT_DESTROYED();
   const CounterStyle* counter_style = NullableCounterStyle();
   String text = GenerateCounterText(counter_style, counter_values.front());
@@ -89,6 +89,7 @@
     }
   }
   SetTextIfNeeded(text);
+  return text;
 }
 
 const CounterStyle* LayoutCounter::NullableCounterStyle() const {
diff --git a/third_party/blink/renderer/core/layout/layout_counter.h b/third_party/blink/renderer/core/layout/layout_counter.h
index 3660df01..3aba900 100644
--- a/third_party/blink/renderer/core/layout/layout_counter.h
+++ b/third_party/blink/renderer/core/layout/layout_counter.h
@@ -45,7 +45,9 @@
     return counter_->Identifier();
   }
 
-  void UpdateCounter(Vector<int> counter_values);
+  // Generates, sets and returns counter text based on computed counter values
+  // and list separators.
+  String UpdateCounter(Vector<int> counter_values);
 
   // Returns true if <counter-style> is "disclosure-open" or
   // "disclosure-closed".
diff --git a/third_party/blink/renderer/core/layout/page_container_layout_algorithm.cc b/third_party/blink/renderer/core/layout/page_container_layout_algorithm.cc
index 9d4cff2..7e4dec4 100644
--- a/third_party/blink/renderer/core/layout/page_container_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/page_container_layout_algorithm.cc
@@ -418,7 +418,7 @@
 
   int quote_depth = 0;
   for (; content; content = content->Next()) {
-    if (content->IsAltText() || content->IsNone()) {
+    if (content->IsAlt() || content->IsNone()) {
       continue;
     }
     LayoutObject* child = content->CreateLayoutObject(*margin_layout_box);
diff --git a/third_party/blink/renderer/core/loader/cookie_jar.cc b/third_party/blink/renderer/core/loader/cookie_jar.cc
index 91be98e4..f86cbf6 100644
--- a/third_party/blink/renderer/core/loader/cookie_jar.cc
+++ b/third_party/blink/renderer/core/loader/cookie_jar.cc
@@ -220,12 +220,17 @@
   }
 
   base::TimeDelta elapsed = timer.Elapsed();
-  base::UmaHistogramTimes("Blink.CookiesTime", elapsed);
+  if (ipc_needed) {
+    base::UmaHistogramTimes("Blink.CookiesTime.IpcNeeded", elapsed);
+  } else {
+    base::UmaHistogramTimes("Blink.CookiesTime.IpcNotNeeded", elapsed);
+  }
 
-  if (base::FeatureList::IsEnabled(kCookieJarAblation)) {
+  // We should run the ablation study only for scenarios with ipc.
+  if (base::FeatureList::IsEnabled(kCookieJarAblation) && ipc_needed) {
     base::TimeDelta delay = elapsed * kCookieJarAblationDelayFactor.Get() +
                             kCookieJarAblationDelayOffset.Get();
-    base::UmaHistogramMediumTimes("Blink.CookiesTime.AblationDelay", delay);
+    base::UmaHistogramMediumTimes("Blink.CookiesTime.AblationDelay2", delay);
     if (delay.is_positive()) {
       base::PlatformThread::Sleep(delay);
     }
diff --git a/third_party/blink/renderer/core/style/content_data.cc b/third_party/blink/renderer/core/style/content_data.cc
index 000bcd07..92f49c65 100644
--- a/third_party/blink/renderer/core/style/content_data.cc
+++ b/third_party/blink/renderer/core/style/content_data.cc
@@ -54,6 +54,20 @@
   visitor->Trace(next_);
 }
 
+String ContentData::ConcatenateAltText(const ContentData& first_alt_data) {
+  DCHECK(first_alt_data.IsAlt());
+  StringBuilder alt_text;
+  for (const ContentData* content_data = &first_alt_data; content_data;
+       content_data = content_data->Next()) {
+    if (auto* alt_counter = DynamicTo<AltCounterContentData>(content_data)) {
+      alt_text.Append(alt_counter->GetText());
+    } else {
+      alt_text.Append(To<AltTextContentData>(content_data)->GetText());
+    }
+  }
+  return alt_text.ToString();
+}
+
 LayoutObject* ImageContentData::CreateLayoutObject(LayoutObject& owner) const {
   LayoutImage* image = LayoutImage::CreateAnonymous(owner.GetDocument());
   bool match_parent_size = image_ && image_->IsGeneratedImage();
diff --git a/third_party/blink/renderer/core/style/content_data.h b/third_party/blink/renderer/core/style/content_data.h
index d602d14e..e4eb2a7 100644
--- a/third_party/blink/renderer/core/style/content_data.h
+++ b/third_party/blink/renderer/core/style/content_data.h
@@ -26,6 +26,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_CONTENT_DATA_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_CONTENT_DATA_H_
 
+#include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css/css_value.h"
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
 #include "third_party/blink/renderer/core/style/style_image.h"
@@ -51,6 +52,10 @@
   virtual bool IsText() const { return false; }
   virtual bool IsAltText() const { return false; }
   virtual bool IsNone() const { return false; }
+  virtual bool IsAlt() const { return IsAltText() || IsAltCounter(); }
+
+  CORE_EXPORT static String ConcatenateAltText(
+      const ContentData& first_alt_data);
 
   // Create a layout object for this piece of content. `owner` is the layout
   // object that has the content property, e.g. a pseudo element, or an @page
@@ -200,14 +205,6 @@
   explicit AltTextContentData(const String& text) : text_(text) {}
 
   String GetText() const { return text_; }
-  String ConcatenateAltText() const {
-    StringBuilder alt_text;
-    for (const ContentData* content_data = this; content_data;
-         content_data = content_data->Next()) {
-      alt_text.Append(To<AltTextContentData>(content_data)->GetText());
-    }
-    return alt_text.ToString();
-  }
   void SetText(const String& text) { text_ = text; }
 
   bool IsAltText() const override { return true; }
@@ -426,7 +423,7 @@
   if (!content_data->IsImage()) {
     return false;
   }
-  if (content_data->Next() && !content_data->Next()->IsAltText()) {
+  if (content_data->Next() && !content_data->Next()->IsAlt()) {
     return false;
   }
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index ab44b19..9e8304a 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -1407,8 +1407,8 @@
   if (element->IsPseudoElement()) {
     for (const ContentData* content_data = style->GetContentData();
          content_data; content_data = content_data->Next()) {
-      if (auto* css_alt = DynamicTo<AltTextContentData>(content_data)) {
-        return css_alt->ConcatenateAltText();
+      if (content_data->IsAlt()) {
+        return ContentData::ConcatenateAltText(*content_data);
       }
     }
     return std::nullopt;
@@ -1419,8 +1419,8 @@
   // there is exactly one piece of content, which is an image.
   const ContentData* content_data = style->GetContentData();
   if (content_data && content_data->IsImage() && content_data->Next() &&
-      content_data->Next()->IsAltText()) {
-    return To<AltTextContentData>(content_data->Next())->ConcatenateAltText();
+      content_data->Next()->IsAlt()) {
+    return ContentData::ConcatenateAltText(*content_data->Next());
   }
 
   return std::nullopt;
diff --git a/third_party/blink/renderer/modules/ai/language_model_prompt_builder.cc b/third_party/blink/renderer/modules/ai/language_model_prompt_builder.cc
index 9d34c9d0..db9eab26 100644
--- a/third_party/blink/renderer/modules/ai/language_model_prompt_builder.cc
+++ b/third_party/blink/renderer/modules/ai/language_model_prompt_builder.cc
@@ -180,6 +180,13 @@
     V8LanguageModelPromptContent* content) {
   switch (type.AsEnum()) {
     case V8LanguageModelPromptType::Enum::kText:
+      if (!content->IsString()) {
+        // TODO(crbug.com/409615288): Throw a TypeError to match the explainer.
+        Reject(DOMException::Create(
+            "The value must be a String for type:'text'",
+            DOMException::GetErrorName(DOMExceptionCode::kSyntaxError)));
+        return nullptr;
+      }
       return ToMojo(content->GetAsString());
     case V8LanguageModelPromptType::Enum::kImage: {
       if (!allowed_types_.Contains(
diff --git a/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.idl b/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.idl
index 261e9ad..70d0c26 100644
--- a/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.idl
+++ b/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.idl
@@ -7,8 +7,6 @@
 typedef (CanvasRenderingContext2D or
          WebGLRenderingContext or
          WebGL2RenderingContext or
-         WebGLRenderingContextWebGPU or
-         WebGL2RenderingContextWebGPU or
          ImageBitmapRenderingContext or
          GPUCanvasContext) RenderingContext;
 
diff --git a/third_party/blink/renderer/modules/canvas/htmlcanvas/v8_rendering_context.h b/third_party/blink/renderer/modules/canvas/htmlcanvas/v8_rendering_context.h
index aa71143..cfa8ac67 100644
--- a/third_party/blink/renderer/modules/canvas/htmlcanvas/v8_rendering_context.h
+++ b/third_party/blink/renderer/modules/canvas/htmlcanvas/v8_rendering_context.h
@@ -8,6 +8,6 @@
 // This is just a forwarding header to avoid including an enormous filename in
 // each file that needs the declaration of the union that is used for
 // RenderingContext.
-#include "third_party/blink/renderer/bindings/modules/v8/v8_union_canvasrenderingcontext2d_gpucanvascontext_imagebitmaprenderingcontext_webgl2renderingcontext_webgl2renderingcontextwebgpu_webglrenderingcontext_webglrenderingcontextwebgpu.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_union_canvasrenderingcontext2d_gpucanvascontext_imagebitmaprenderingcontext_webgl2renderingcontext_webglrenderingcontext.h"
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_HTMLCANVAS_V8_RENDERING_CONTEXT_H_
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_module.idl b/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_module.idl
index a15d8d67..f88b06c 100644
--- a/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_module.idl
+++ b/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_module.idl
@@ -7,8 +7,6 @@
 typedef (OffscreenCanvasRenderingContext2D or
          WebGLRenderingContext or
          WebGL2RenderingContext or
-         WebGLRenderingContextWebGPU or
-         WebGL2RenderingContextWebGPU or
          ImageBitmapRenderingContext or
          GPUCanvasContext) OffscreenRenderingContext;
 enum OffscreenRenderingContextType { "2d", "webgl", "webgl2", "bitmaprenderer", "webgpu" };
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas/v8_offscreen_rendering_context.h b/third_party/blink/renderer/modules/canvas/offscreencanvas/v8_offscreen_rendering_context.h
index 3742d1e..b44bacfe 100644
--- a/third_party/blink/renderer/modules/canvas/offscreencanvas/v8_offscreen_rendering_context.h
+++ b/third_party/blink/renderer/modules/canvas/offscreencanvas/v8_offscreen_rendering_context.h
@@ -8,6 +8,6 @@
 // This is just a forwarding header to avoid including an enormous filename in
 // each file that needs the declaration of the union that is used for
 // OffscreenRenderingContext.
-#include "third_party/blink/renderer/bindings/modules/v8/v8_union_gpucanvascontext_imagebitmaprenderingcontext_offscreencanvasrenderingcontext2d_webgl2renderingcontext_webgl2renderingcontextwebgpu_webglrenderingcontext_webglrenderingcontextwebgpu.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_union_gpucanvascontext_imagebitmaprenderingcontext_offscreencanvasrenderingcontext2d_webgl2renderingcontext_webglrenderingcontext.h"
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_OFFSCREENCANVAS_V8_OFFSCREEN_RENDERING_CONTEXT_H_
diff --git a/third_party/blink/renderer/modules/webgl/BUILD.gn b/third_party/blink/renderer/modules/webgl/BUILD.gn
index 5c1ff9a..08d7b3f 100644
--- a/third_party/blink/renderer/modules/webgl/BUILD.gn
+++ b/third_party/blink/renderer/modules/webgl/BUILD.gn
@@ -79,8 +79,6 @@
     "webgl2_rendering_context.h",
     "webgl2_rendering_context_base.cc",
     "webgl2_rendering_context_base.h",
-    "webgl2_rendering_context_webgpu.cc",
-    "webgl2_rendering_context_webgpu.h",
     "webgl_active_info.h",
     "webgl_blend_func_extended.cc",
     "webgl_blend_func_extended.h",
@@ -153,10 +151,6 @@
     "webgl_rendering_context.h",
     "webgl_rendering_context_base.cc",
     "webgl_rendering_context_base.h",
-    "webgl_rendering_context_webgpu.cc",
-    "webgl_rendering_context_webgpu.h",
-    "webgl_rendering_context_webgpu_base.cc",
-    "webgl_rendering_context_webgpu_base.h",
     "webgl_sampler.cc",
     "webgl_sampler.h",
     "webgl_shader.cc",
diff --git a/third_party/blink/renderer/modules/webgl/DEPS b/third_party/blink/renderer/modules/webgl/DEPS
index b0efa5d..ec20717 100644
--- a/third_party/blink/renderer/modules/webgl/DEPS
+++ b/third_party/blink/renderer/modules/webgl/DEPS
@@ -1,5 +1,4 @@
 include_rules = [
-    "+base/notimplemented.h",
     "+device/vr/buildflags/buildflags.h",
     "+device/vr/public/mojom/vr_service.mojom-blink.h",
     "+device/vr/public/mojom/vr_service.mojom-blink-forward.h",
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_webgpu.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_webgpu.cc
deleted file mode 100644
index 290b5d6..0000000
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_webgpu.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2025 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/webgl/webgl2_rendering_context_webgpu.h"
-
-#include "base/notimplemented.h"
-#include "third_party/blink/renderer/modules/canvas/htmlcanvas/v8_rendering_context.h"
-#include "third_party/blink/renderer/modules/canvas/offscreencanvas/v8_offscreen_rendering_context.h"
-
-namespace blink {
-
-WebGL2RenderingContextWebGPU::WebGL2RenderingContextWebGPU(
-    CanvasRenderingContextHost* host,
-    const CanvasContextCreationAttributesCore& requested_attributes)
-    : WebGLRenderingContextWebGPUBase(host,
-                                      requested_attributes,
-                                      CanvasRenderingAPI::kWebgl2) {}
-
-V8RenderingContext* WebGL2RenderingContextWebGPU::AsV8RenderingContext() {
-  return MakeGarbageCollected<V8RenderingContext>(this);
-}
-
-V8OffscreenRenderingContext*
-WebGL2RenderingContextWebGPU::AsV8OffscreenRenderingContext() {
-  return MakeGarbageCollected<V8OffscreenRenderingContext>(this);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_webgpu.h b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_webgpu.h
deleted file mode 100644
index db83b4a..0000000
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_webgpu.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2025 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL2_RENDERING_CONTEXT_WEBGPU_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL2_RENDERING_CONTEXT_WEBGPU_H_
-
-#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.h"
-
-namespace blink {
-
-class WebGL2RenderingContextWebGPU final
-    : public WebGLRenderingContextWebGPUBase {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  WebGL2RenderingContextWebGPU(
-      CanvasRenderingContextHost* host,
-      const CanvasContextCreationAttributesCore& requested_attributes);
-
-  // CanvasRenderingContext implementation
-  V8RenderingContext* AsV8RenderingContext() final;
-  V8OffscreenRenderingContext* AsV8OffscreenRenderingContext() final;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL2_RENDERING_CONTEXT_WEBGPU_H_
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_webgpu.idl b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_webgpu.idl
deleted file mode 100644
index ac76ded..0000000
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_webgpu.idl
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2025 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7
-
-[
-    ActiveScriptWrappable,
-    Exposed=(Window,Worker),
-    RuntimeEnabled=WebGLOnWebGPU
-] interface WebGL2RenderingContextWebGPU { };
-WebGL2RenderingContextWebGPU includes WebGLRenderingContextBase;
-WebGL2RenderingContextWebGPU includes WebGL2RenderingContextBase;
diff --git a/third_party/blink/renderer/modules/webgl/webgl_context_factory.cc b/third_party/blink/renderer/modules/webgl/webgl_context_factory.cc
index 8a983f1..048feec 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_context_factory.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_context_factory.cc
@@ -4,15 +4,11 @@
 
 #include "third_party/blink/renderer/modules/webgl/webgl_context_factory.h"
 
-#include "base/notimplemented.h"
 #include "third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h"
 #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
 #include "third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h"
-#include "third_party/blink/renderer/modules/webgl/webgl2_rendering_context_webgpu.h"
 #include "third_party/blink/renderer/modules/webgl/webgl_context_event.h"
 #include "third_party/blink/renderer/modules/webgl/webgl_rendering_context.h"
-#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
@@ -32,11 +28,7 @@
 CanvasRenderingContext* WebGLContextFactory::Create(
     CanvasRenderingContextHost* host,
     const CanvasContextCreationAttributesCore& attrs) {
-  if (RuntimeEnabledFeatures::WebGLOnWebGPUEnabled()) {
-    return CreateInternalWebGPU(host, attrs);
-  } else {
-    return CreateInternal(host, attrs);
-  }
+  return CreateInternal(host, attrs);
 }
 
 CanvasRenderingContext* WebGLContextFactory::CreateInternal(
@@ -106,16 +98,6 @@
   }
 }
 
-CanvasRenderingContext* WebGLContextFactory::CreateInternalWebGPU(
-    CanvasRenderingContextHost* host,
-    const CanvasContextCreationAttributesCore& attrs) {
-  if (is_webgl2_) {
-    return MakeGarbageCollected<WebGL2RenderingContextWebGPU>(host, attrs);
-  } else {
-    return MakeGarbageCollected<WebGLRenderingContextWebGPU>(host, attrs);
-  }
-}
-
 CanvasRenderingContext::CanvasRenderingAPI
 WebGLContextFactory::GetRenderingAPI() const {
   if (is_webgl2_) {
diff --git a/third_party/blink/renderer/modules/webgl/webgl_context_factory.h b/third_party/blink/renderer/modules/webgl/webgl_context_factory.h
index e58bbe3..df24c70 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_context_factory.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_context_factory.h
@@ -39,9 +39,6 @@
   CanvasRenderingContext* CreateInternal(
       CanvasRenderingContextHost*,
       const CanvasContextCreationAttributesCore&);
-  CanvasRenderingContext* CreateInternalWebGPU(
-      CanvasRenderingContextHost*,
-      const CanvasContextCreationAttributesCore&);
 
   const char* GetContextName() const;
   Platform::ContextType GetContextType() const;
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu.cc
deleted file mode 100644
index ead3905..0000000
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2025 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu.h"
-
-#include "base/notimplemented.h"
-#include "third_party/blink/renderer/modules/canvas/htmlcanvas/v8_rendering_context.h"
-#include "third_party/blink/renderer/modules/canvas/offscreencanvas/v8_offscreen_rendering_context.h"
-
-namespace blink {
-
-WebGLRenderingContextWebGPU::WebGLRenderingContextWebGPU(
-    CanvasRenderingContextHost* host,
-    const CanvasContextCreationAttributesCore& requested_attributes)
-    : WebGLRenderingContextWebGPUBase(host,
-                                      requested_attributes,
-                                      CanvasRenderingAPI::kWebgl) {}
-
-V8RenderingContext* WebGLRenderingContextWebGPU::AsV8RenderingContext() {
-  return MakeGarbageCollected<V8RenderingContext>(this);
-}
-
-V8OffscreenRenderingContext*
-WebGLRenderingContextWebGPU::AsV8OffscreenRenderingContext() {
-  return MakeGarbageCollected<V8OffscreenRenderingContext>(this);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu.h
deleted file mode 100644
index d0f3d1c3..0000000
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2025 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_RENDERING_CONTEXT_WEBGPU_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_RENDERING_CONTEXT_WEBGPU_H_
-
-#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.h"
-
-namespace blink {
-
-class WebGLRenderingContextWebGPU final
-    : public WebGLRenderingContextWebGPUBase {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  WebGLRenderingContextWebGPU(
-      CanvasRenderingContextHost* host,
-      const CanvasContextCreationAttributesCore& requested_attributes);
-
-  // CanvasRenderingContext implementation
-  V8RenderingContext* AsV8RenderingContext() final;
-  V8OffscreenRenderingContext* AsV8OffscreenRenderingContext() final;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_RENDERING_CONTEXT_WEBGPU_H_
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu.idl b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu.idl
deleted file mode 100644
index 2f4c23c..0000000
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu.idl
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2025 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://www.khronos.org/registry/webgl/specs/latest/1.0/#WebGLRenderingContext
-
-[
-    ActiveScriptWrappable,
-    Exposed=(Window,Worker),
-    RuntimeEnabled=WebGLOnWebGPU
-] interface WebGLRenderingContextWebGPU {
-
-    [RuntimeEnabled=WebGLDrawingBufferStorage] const GLenum RGB8   = 0x8051;
-    [RuntimeEnabled=WebGLDrawingBufferStorage] const GLenum RGBA8  = 0x8058;
-};
-WebGLRenderingContextWebGPU includes WebGLRenderingContextBase;
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.cc
deleted file mode 100644
index 18d26cfe..0000000
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.cc
+++ /dev/null
@@ -1,2475 +0,0 @@
-// Copyright 2025 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.h"
-
-#include "base/notimplemented.h"
-
-namespace blink {
-
-WebGLRenderingContextWebGPUBase::WebGLRenderingContextWebGPUBase(
-    CanvasRenderingContextHost* host,
-    const CanvasContextCreationAttributesCore& requested_attributes,
-    CanvasRenderingAPI api)
-    : WebGLContextObjectSupport(
-          host->GetTopExecutionContext()->GetTaskRunner(TaskType::kWebGL),
-          /* is_webgl2 */ api == CanvasRenderingAPI::kWebgl2),
-      CanvasRenderingContext(host, requested_attributes, api) {}
-
-WebGLRenderingContextWebGPUBase::~WebGLRenderingContextWebGPUBase() {}
-
-// ****************************************************************************
-// Start of WebGLRenderingContextBase's IDL methods
-// ****************************************************************************
-
-V8UnionHTMLCanvasElementOrOffscreenCanvas*
-WebGLRenderingContextWebGPUBase::getHTMLOrOffscreenCanvas() const {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-int WebGLRenderingContextWebGPUBase::drawingBufferWidth() const {
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-int WebGLRenderingContextWebGPUBase::drawingBufferHeight() const {
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-GLenum WebGLRenderingContextWebGPUBase::drawingBufferFormat() const {
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-V8PredefinedColorSpace
-WebGLRenderingContextWebGPUBase::drawingBufferColorSpace() const {
-  NOTIMPLEMENTED();
-  return V8PredefinedColorSpace(V8PredefinedColorSpace::Enum::kSRGB);
-}
-
-void WebGLRenderingContextWebGPUBase::setDrawingBufferColorSpace(
-    const V8PredefinedColorSpace& color_space,
-    ExceptionState&) {
-  NOTIMPLEMENTED();
-}
-
-V8PredefinedColorSpace WebGLRenderingContextWebGPUBase::unpackColorSpace()
-    const {
-  NOTIMPLEMENTED();
-  return V8PredefinedColorSpace(V8PredefinedColorSpace::Enum::kSRGB);
-}
-
-void WebGLRenderingContextWebGPUBase::setUnpackColorSpace(
-    const V8PredefinedColorSpace& color_space,
-    ExceptionState&) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::activeTexture(GLenum texture) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::attachShader(WebGLProgram*,
-                                                   WebGLShader*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::bindAttribLocation(WebGLProgram*,
-                                                         GLuint index,
-                                                         const String& name) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::bindBuffer(GLenum target,
-                                                 WebGLBuffer* buffer) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::bindFramebuffer(GLenum target,
-                                                      WebGLFramebuffer*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::bindRenderbuffer(GLenum target,
-                                                       WebGLRenderbuffer*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::bindTexture(GLenum target,
-                                                  WebGLTexture*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::blendColor(GLfloat red,
-                                                 GLfloat green,
-                                                 GLfloat blue,
-                                                 GLfloat alpha) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::blendEquation(GLenum mode) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::blendEquationSeparate(GLenum mode_rgb,
-                                                            GLenum mode_alpha) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::blendFunc(GLenum sfactor,
-                                                GLenum dfactor) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::blendFuncSeparate(GLenum src_rgb,
-                                                        GLenum dst_rgb,
-                                                        GLenum src_alpha,
-                                                        GLenum dst_alpha) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::bufferData(GLenum target,
-                                                 int64_t size,
-                                                 GLenum usage) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::bufferData(GLenum target,
-                                                 DOMArrayBufferBase* data,
-                                                 GLenum usage) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::bufferData(
-    GLenum target,
-    MaybeShared<DOMArrayBufferView> data,
-    GLenum usage) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::bufferSubData(
-    GLenum target,
-    int64_t offset,
-    base::span<const uint8_t> data) {
-  NOTIMPLEMENTED();
-}
-
-GLenum WebGLRenderingContextWebGPUBase::checkFramebufferStatus(GLenum target) {
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-void WebGLRenderingContextWebGPUBase::clear(GLbitfield mask) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::clearColor(GLfloat red,
-                                                 GLfloat green,
-                                                 GLfloat blue,
-                                                 GLfloat alpha) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::clearDepth(GLfloat) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::clearStencil(GLint) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::colorMask(GLboolean red,
-                                                GLboolean green,
-                                                GLboolean blue,
-                                                GLboolean alpha) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::compileShader(WebGLShader*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::compressedTexImage2D(
-    GLenum target,
-    GLint level,
-    GLenum internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLint border,
-    MaybeShared<DOMArrayBufferView> data) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::compressedTexSubImage2D(
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLsizei width,
-    GLsizei height,
-    GLenum format,
-    MaybeShared<DOMArrayBufferView> data) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::copyTexImage2D(GLenum target,
-                                                     GLint level,
-                                                     GLenum internalformat,
-                                                     GLint x,
-                                                     GLint y,
-                                                     GLsizei width,
-                                                     GLsizei height,
-                                                     GLint border) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::copyTexSubImage2D(GLenum target,
-                                                        GLint level,
-                                                        GLint xoffset,
-                                                        GLint yoffset,
-                                                        GLint x,
-                                                        GLint y,
-                                                        GLsizei width,
-                                                        GLsizei height) {
-  NOTIMPLEMENTED();
-}
-
-WebGLBuffer* WebGLRenderingContextWebGPUBase::createBuffer() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-WebGLFramebuffer* WebGLRenderingContextWebGPUBase::createFramebuffer() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-WebGLProgram* WebGLRenderingContextWebGPUBase::createProgram() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-WebGLRenderbuffer* WebGLRenderingContextWebGPUBase::createRenderbuffer() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-WebGLShader* WebGLRenderingContextWebGPUBase::createShader(GLenum type) {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-WebGLTexture* WebGLRenderingContextWebGPUBase::createTexture() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-void WebGLRenderingContextWebGPUBase::cullFace(GLenum mode) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::deleteBuffer(WebGLBuffer*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::deleteFramebuffer(WebGLFramebuffer*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::deleteProgram(WebGLProgram*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::deleteRenderbuffer(WebGLRenderbuffer*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::deleteShader(WebGLShader*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::deleteTexture(WebGLTexture*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::depthFunc(GLenum) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::depthMask(GLboolean) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::depthRange(GLfloat z_near,
-                                                 GLfloat z_far) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::detachShader(WebGLProgram*,
-                                                   WebGLShader*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::disable(GLenum cap) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::disableVertexAttribArray(GLuint index) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::drawArrays(GLenum mode,
-                                                 GLint first,
-                                                 GLsizei count) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::drawElements(GLenum mode,
-                                                   GLsizei count,
-                                                   GLenum type,
-                                                   int64_t offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::enable(GLenum cap) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::enableVertexAttribArray(GLuint index) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::finish() {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::flush() {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::framebufferRenderbuffer(
-    GLenum target,
-    GLenum attachment,
-    GLenum renderbuffertarget,
-    WebGLRenderbuffer*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::framebufferTexture2D(GLenum target,
-                                                           GLenum attachment,
-                                                           GLenum textarget,
-                                                           WebGLTexture*,
-                                                           GLint level) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::frontFace(GLenum mode) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::generateMipmap(GLenum target) {
-  NOTIMPLEMENTED();
-}
-
-WebGLActiveInfo* WebGLRenderingContextWebGPUBase::getActiveAttrib(
-    WebGLProgram*,
-    GLuint index) {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-WebGLActiveInfo* WebGLRenderingContextWebGPUBase::getActiveUniform(
-    WebGLProgram*,
-    GLuint index) {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-std::optional<HeapVector<Member<WebGLShader>>>
-WebGLRenderingContextWebGPUBase::getAttachedShaders(WebGLProgram*) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-GLint WebGLRenderingContextWebGPUBase::getAttribLocation(WebGLProgram*,
-                                                         const String& name) {
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getBufferParameter(ScriptState*,
-                                                                GLenum target,
-                                                                GLenum pname) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-WebGLContextAttributes* WebGLRenderingContextWebGPUBase::getContextAttributes()
-    const {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-GLenum WebGLRenderingContextWebGPUBase::getError() {
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-ScriptObject WebGLRenderingContextWebGPUBase::getExtension(ScriptState*,
-                                                           const String& name) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getFramebufferAttachmentParameter(
-    ScriptState*,
-    GLenum target,
-    GLenum attachment,
-    GLenum pname) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getParameter(ScriptState*,
-                                                          GLenum pname) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getProgramParameter(ScriptState*,
-                                                                 WebGLProgram*,
-                                                                 GLenum pname) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-String WebGLRenderingContextWebGPUBase::getProgramInfoLog(WebGLProgram*) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getRenderbufferParameter(
-    ScriptState*,
-    GLenum target,
-    GLenum pname) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getShaderParameter(ScriptState*,
-                                                                WebGLShader*,
-                                                                GLenum pname) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-String WebGLRenderingContextWebGPUBase::getShaderInfoLog(WebGLShader*) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-WebGLShaderPrecisionFormat*
-WebGLRenderingContextWebGPUBase::getShaderPrecisionFormat(
-    GLenum shader_type,
-    GLenum precision_type) {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-String WebGLRenderingContextWebGPUBase::getShaderSource(WebGLShader*) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-std::optional<Vector<String>>
-WebGLRenderingContextWebGPUBase::getSupportedExtensions() {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getTexParameter(ScriptState*,
-                                                             GLenum target,
-                                                             GLenum pname) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getUniform(
-    ScriptState*,
-    WebGLProgram*,
-    const WebGLUniformLocation*) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-WebGLUniformLocation* WebGLRenderingContextWebGPUBase::getUniformLocation(
-    WebGLProgram*,
-    const String&) {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getVertexAttrib(ScriptState*,
-                                                             GLuint index,
-                                                             GLenum pname) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-int64_t WebGLRenderingContextWebGPUBase::getVertexAttribOffset(GLuint index,
-                                                               GLenum pname) {
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-void WebGLRenderingContextWebGPUBase::hint(GLenum target, GLenum mode) {
-  NOTIMPLEMENTED();
-}
-
-bool WebGLRenderingContextWebGPUBase::isBuffer(WebGLBuffer*) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-bool WebGLRenderingContextWebGPUBase::isEnabled(GLenum cap) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-bool WebGLRenderingContextWebGPUBase::isFramebuffer(WebGLFramebuffer*) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-bool WebGLRenderingContextWebGPUBase::isProgram(WebGLProgram*) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-bool WebGLRenderingContextWebGPUBase::isRenderbuffer(WebGLRenderbuffer*) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-bool WebGLRenderingContextWebGPUBase::isShader(WebGLShader*) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-bool WebGLRenderingContextWebGPUBase::isTexture(WebGLTexture*) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-void WebGLRenderingContextWebGPUBase::lineWidth(GLfloat) {
-  NOTIMPLEMENTED();
-}
-void WebGLRenderingContextWebGPUBase::linkProgram(WebGLProgram*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::pixelStorei(GLenum pname, GLint param) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::polygonOffset(GLfloat factor,
-                                                    GLfloat units) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::readPixels(
-    GLint x,
-    GLint y,
-    GLsizei width,
-    GLsizei height,
-    GLenum format,
-    GLenum type,
-    MaybeShared<DOMArrayBufferView> pixels) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::renderbufferStorage(GLenum target,
-                                                          GLenum internalformat,
-                                                          GLsizei width,
-                                                          GLsizei height) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::sampleCoverage(GLfloat value,
-                                                     GLboolean invert) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::scissor(GLint x,
-                                              GLint y,
-                                              GLsizei width,
-                                              GLsizei height) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::shaderSource(WebGLShader*,
-                                                   const String&) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::stencilFunc(GLenum func,
-                                                  GLint ref,
-                                                  GLuint mask) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::stencilFuncSeparate(GLenum face,
-                                                          GLenum func,
-                                                          GLint ref,
-                                                          GLuint mask) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::stencilMask(GLuint) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::stencilMaskSeparate(GLenum face,
-                                                          GLuint mask) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::stencilOp(GLenum fail,
-                                                GLenum zfail,
-                                                GLenum zpass) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::stencilOpSeparate(GLenum face,
-                                                        GLenum fail,
-                                                        GLenum zfail,
-                                                        GLenum zpass) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texParameterf(GLenum target,
-                                                    GLenum pname,
-                                                    GLfloat param) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texParameteri(GLenum target,
-                                                    GLenum pname,
-                                                    GLint param) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage2D(
-    GLenum target,
-    GLint level,
-    GLint internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    MaybeShared<DOMArrayBufferView>) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage2D(GLenum target,
-                                                 GLint level,
-                                                 GLint internalformat,
-                                                 GLenum format,
-                                                 GLenum type,
-                                                 ImageData*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage2D(ScriptState*,
-                                                 GLenum target,
-                                                 GLint level,
-                                                 GLint internalformat,
-                                                 GLenum format,
-                                                 GLenum type,
-                                                 HTMLImageElement*,
-                                                 ExceptionState&) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage2D(ScriptState*,
-                                                 GLenum target,
-                                                 GLint level,
-                                                 GLint internalformat,
-                                                 GLenum format,
-                                                 GLenum type,
-                                                 CanvasRenderingContextHost*,
-                                                 ExceptionState&) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage2D(ScriptState*,
-                                                 GLenum target,
-                                                 GLint level,
-                                                 GLint internalformat,
-                                                 GLenum format,
-                                                 GLenum type,
-                                                 HTMLVideoElement*,
-                                                 ExceptionState&) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage2D(ScriptState*,
-                                                 GLenum target,
-                                                 GLint level,
-                                                 GLint internalformat,
-                                                 GLenum format,
-                                                 GLenum type,
-                                                 VideoFrame*,
-                                                 ExceptionState&) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage2D(GLenum target,
-                                                 GLint level,
-                                                 GLint internalformat,
-                                                 GLenum format,
-                                                 GLenum type,
-                                                 ImageBitmap*,
-                                                 ExceptionState&) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage2D(
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLsizei width,
-    GLsizei height,
-    GLenum format,
-    GLenum type,
-    MaybeShared<DOMArrayBufferView>) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage2D(GLenum target,
-                                                    GLint level,
-                                                    GLint xoffset,
-                                                    GLint yoffset,
-                                                    GLenum format,
-                                                    GLenum type,
-                                                    ImageData*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage2D(ScriptState*,
-                                                    GLenum target,
-                                                    GLint level,
-                                                    GLint xoffset,
-                                                    GLint yoffset,
-                                                    GLenum format,
-                                                    GLenum type,
-                                                    HTMLImageElement*,
-                                                    ExceptionState&) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage2D(ScriptState*,
-                                                    GLenum target,
-                                                    GLint level,
-                                                    GLint xoffset,
-                                                    GLint yoffset,
-                                                    GLenum format,
-                                                    GLenum type,
-                                                    CanvasRenderingContextHost*,
-                                                    ExceptionState&) {
-  NOTIMPLEMENTED();
-}
-void WebGLRenderingContextWebGPUBase::texSubImage2D(ScriptState*,
-                                                    GLenum target,
-                                                    GLint level,
-                                                    GLint xoffset,
-                                                    GLint yoffset,
-                                                    GLenum format,
-                                                    GLenum type,
-                                                    HTMLVideoElement*,
-                                                    ExceptionState&) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage2D(ScriptState*,
-                                                    GLenum target,
-                                                    GLint level,
-                                                    GLint xoffset,
-                                                    GLint yoffset,
-                                                    GLenum format,
-                                                    GLenum type,
-                                                    VideoFrame*,
-                                                    ExceptionState&) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage2D(GLenum target,
-                                                    GLint level,
-                                                    GLint xoffset,
-                                                    GLint yoffset,
-                                                    GLenum format,
-                                                    GLenum type,
-                                                    ImageBitmap*,
-                                                    ExceptionState&) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform1f(const WebGLUniformLocation*,
-                                                GLfloat x) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform1fv(const WebGLUniformLocation*,
-                                                 base::span<const GLfloat>) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform1i(const WebGLUniformLocation*,
-                                                GLint x) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform1iv(const WebGLUniformLocation*,
-                                                 base::span<const GLint>) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform2f(const WebGLUniformLocation*,
-                                                GLfloat x,
-                                                GLfloat y) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform2fv(const WebGLUniformLocation*,
-                                                 base::span<const GLfloat>) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform2i(const WebGLUniformLocation*,
-                                                GLint x,
-                                                GLint y) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform2iv(const WebGLUniformLocation*,
-                                                 base::span<const GLint>) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform3f(const WebGLUniformLocation*,
-                                                GLfloat x,
-                                                GLfloat y,
-                                                GLfloat z) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform3fv(const WebGLUniformLocation*,
-                                                 base::span<const GLfloat>) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform3i(const WebGLUniformLocation*,
-                                                GLint x,
-                                                GLint y,
-                                                GLint z) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform3iv(const WebGLUniformLocation*,
-                                                 base::span<const GLint>) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform4f(const WebGLUniformLocation*,
-                                                GLfloat x,
-                                                GLfloat y,
-                                                GLfloat z,
-                                                GLfloat w) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform4fv(const WebGLUniformLocation*,
-                                                 base::span<const GLfloat>) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform4i(const WebGLUniformLocation*,
-                                                GLint x,
-                                                GLint y,
-                                                GLint z,
-                                                GLint w) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform4iv(const WebGLUniformLocation*,
-                                                 base::span<const GLint>) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniformMatrix2fv(
-    const WebGLUniformLocation*,
-    GLboolean transpose,
-    base::span<const GLfloat> value) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniformMatrix3fv(
-    const WebGLUniformLocation*,
-    GLboolean transpose,
-    base::span<const GLfloat> value) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniformMatrix4fv(
-    const WebGLUniformLocation*,
-    GLboolean transpose,
-    base::span<const GLfloat> value) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::useProgram(WebGLProgram*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::validateProgram(WebGLProgram*) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::vertexAttrib1f(GLuint index, GLfloat x) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::vertexAttrib1fv(
-    GLuint index,
-    base::span<const GLfloat> values) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::vertexAttrib2f(GLuint index,
-                                                     GLfloat x,
-                                                     GLfloat y) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::vertexAttrib2fv(
-    GLuint index,
-    base::span<const GLfloat> values) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::vertexAttrib3f(GLuint index,
-                                                     GLfloat x,
-                                                     GLfloat y,
-                                                     GLfloat z) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::vertexAttrib3fv(
-    GLuint index,
-    base::span<const GLfloat> values) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::vertexAttrib4f(GLuint index,
-                                                     GLfloat x,
-                                                     GLfloat y,
-                                                     GLfloat z,
-                                                     GLfloat w) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::vertexAttrib4fv(
-    GLuint index,
-    base::span<const GLfloat> values) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::vertexAttribPointer(GLuint index,
-                                                          GLint size,
-                                                          GLenum type,
-                                                          GLboolean normalized,
-                                                          GLsizei stride,
-                                                          int64_t offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::viewport(GLint x,
-                                               GLint y,
-                                               GLsizei width,
-                                               GLsizei height) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::drawingBufferStorage(GLenum sizedformat,
-                                                           GLsizei width,
-                                                           GLsizei height) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::commit() {
-  NOTIMPLEMENTED();
-}
-
-ScriptPromise<IDLUndefined> WebGLRenderingContextWebGPUBase::makeXRCompatible(
-    ScriptState*,
-    ExceptionState&) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-// ****************************************************************************
-// End of WebGLRenderingContextBase's IDL methods
-// ****************************************************************************
-
-// **************************************************************************
-// Start of WebGL2RenderingContextBase's IDL methods
-// **************************************************************************
-
-void WebGLRenderingContextWebGPUBase::bufferData(
-    GLenum target,
-    MaybeShared<DOMArrayBufferView> srcData,
-    GLenum usage,
-    int64_t srcOffset,
-    GLuint length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::bufferSubData(
-    GLenum target,
-    int64_t offset,
-    MaybeShared<DOMArrayBufferView> srcData,
-    int64_t srcOffset,
-    GLuint length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::copyBufferSubData(GLenum readTarget,
-                                                        GLenum writeTarget,
-                                                        int64_t readOffset,
-                                                        int64_t writeOffset,
-                                                        int64_t size) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::getBufferSubData(
-    GLenum target,
-    int64_t srcByteOffset,
-    MaybeShared<DOMArrayBufferView> dstData,
-    int64_t dstOffset,
-    GLuint length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::blitFramebuffer(GLint src_x0,
-                                                      GLint src_y0,
-                                                      GLint src_x1,
-                                                      GLint src_y1,
-                                                      GLint dst_x0,
-                                                      GLint dst_y0,
-                                                      GLint dst_x1,
-                                                      GLint dst_y1,
-                                                      GLbitfield mask,
-                                                      GLenum filter) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::framebufferTextureLayer(
-    GLenum target,
-    GLenum attachment,
-    WebGLTexture* texture,
-    GLint level,
-    GLint layer) {
-  NOTIMPLEMENTED();
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getInternalformatParameter(
-    ScriptState* script_state,
-    GLenum target,
-    GLenum internalformat,
-    GLenum pname) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-void WebGLRenderingContextWebGPUBase::invalidateFramebuffer(
-    GLenum target,
-    const Vector<GLenum>& attachments) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::invalidateSubFramebuffer(
-    GLenum target,
-    const Vector<GLenum>& attachments,
-    GLint x,
-    GLint y,
-    GLsizei width,
-    GLsizei height) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::readBuffer(GLenum mode) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::renderbufferStorageMultisample(
-    GLenum target,
-    GLsizei samples,
-    GLenum internalformat,
-    GLsizei width,
-    GLsizei height) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage2D(GLenum target,
-                                                 GLint level,
-                                                 GLint internalformat,
-                                                 GLsizei width,
-                                                 GLsizei height,
-                                                 GLint border,
-                                                 GLenum format,
-                                                 GLenum type,
-                                                 int64_t offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage2D(GLenum target,
-                                                 GLint level,
-                                                 GLint internalformat,
-                                                 GLsizei width,
-                                                 GLsizei height,
-                                                 GLint border,
-                                                 GLenum format,
-                                                 GLenum type,
-                                                 ImageData* pixels) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage2D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    HTMLImageElement* image,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage2D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    CanvasRenderingContextHost* canvas,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage2D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    HTMLVideoElement* video,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage2D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    VideoFrame* frame,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage2D(
-    GLenum target,
-    GLint level,
-    GLint internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    ImageBitmap* bitmap,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage2D(
-    GLenum target,
-    GLint level,
-    GLint internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    MaybeShared<DOMArrayBufferView> data,
-    int64_t src_offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texElement2D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint internalformat,
-    GLenum format,
-    GLenum type,
-    Element* element,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage2D(GLenum target,
-                                                    GLint level,
-                                                    GLint xoffset,
-                                                    GLint yoffset,
-                                                    GLsizei width,
-                                                    GLsizei height,
-                                                    GLenum format,
-                                                    GLenum type,
-                                                    int64_t offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage2D(GLenum target,
-                                                    GLint level,
-                                                    GLint xoffset,
-                                                    GLint yoffset,
-                                                    GLsizei width,
-                                                    GLsizei height,
-                                                    GLenum format,
-                                                    GLenum type,
-                                                    ImageData* pixels) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage2D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLsizei width,
-    GLsizei height,
-    GLenum format,
-    GLenum type,
-    HTMLImageElement* image,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage2D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLsizei width,
-    GLsizei height,
-    GLenum format,
-    GLenum type,
-    CanvasRenderingContextHost* canvas,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage2D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLsizei width,
-    GLsizei height,
-    GLenum format,
-    GLenum type,
-    HTMLVideoElement* video,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage2D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLsizei width,
-    GLsizei height,
-    GLenum format,
-    GLenum type,
-    VideoFrame* frame,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage2D(
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLsizei width,
-    GLsizei height,
-    GLenum format,
-    GLenum type,
-    ImageBitmap* bitmap,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage2D(
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLsizei width,
-    GLsizei height,
-    GLenum format,
-    GLenum type,
-    MaybeShared<DOMArrayBufferView> pixels,
-    int64_t src_offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texStorage2D(GLenum target,
-                                                   GLsizei levels,
-                                                   GLenum internalformat,
-                                                   GLsizei width,
-                                                   GLsizei height) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texStorage3D(GLenum target,
-                                                   GLsizei levels,
-                                                   GLenum internalformat,
-                                                   GLsizei width,
-                                                   GLsizei height,
-                                                   GLsizei depth) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage3D(GLenum target,
-                                                 GLint level,
-                                                 GLint internalformat,
-                                                 GLsizei width,
-                                                 GLsizei height,
-                                                 GLsizei depth,
-                                                 GLint border,
-                                                 GLenum format,
-                                                 GLenum type,
-                                                 int64_t offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage3D(GLenum target,
-                                                 GLint level,
-                                                 GLint internalformat,
-                                                 GLsizei width,
-                                                 GLsizei height,
-                                                 GLsizei depth,
-                                                 GLint border,
-                                                 GLenum format,
-                                                 GLenum type,
-                                                 ImageData* pixels) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage3D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    HTMLImageElement* image,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage3D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    CanvasRenderingContextHost* canvas,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage3D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    HTMLVideoElement* video,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage3D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    VideoFrame* frame,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage3D(
-    GLenum target,
-    GLint level,
-    GLint internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    ImageBitmap* bitmap,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage3D(
-    GLenum target,
-    GLint level,
-    GLint internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    MaybeShared<DOMArrayBufferView> pixels) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texImage3D(
-    GLenum target,
-    GLint level,
-    GLint internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    MaybeShared<DOMArrayBufferView> pixels,
-    GLuint src_offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage3D(GLenum target,
-                                                    GLint level,
-                                                    GLint xoffset,
-                                                    GLint yoffset,
-                                                    GLint zoffset,
-                                                    GLsizei width,
-                                                    GLsizei height,
-                                                    GLsizei depth,
-                                                    GLenum format,
-                                                    GLenum type,
-                                                    int64_t offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage3D(GLenum target,
-                                                    GLint level,
-                                                    GLint xoffset,
-                                                    GLint yoffset,
-                                                    GLint zoffset,
-                                                    GLsizei width,
-                                                    GLsizei height,
-                                                    GLsizei depth,
-                                                    GLenum format,
-                                                    GLenum type,
-                                                    ImageData* pixels) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage3D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLint zoffset,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLenum format,
-    GLenum type,
-    HTMLImageElement* image,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage3D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLint zoffset,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLenum format,
-    GLenum type,
-    CanvasRenderingContextHost* context_host,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage3D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLint zoffset,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLenum format,
-    GLenum type,
-    HTMLVideoElement* video,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage3D(
-    ScriptState* script_state,
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLint zoffset,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLenum format,
-    GLenum type,
-    VideoFrame* frame,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage3D(
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLint zoffset,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLenum format,
-    GLenum type,
-    ImageBitmap* bitmap,
-    ExceptionState& exception_state) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage3D(
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLint zoffset,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLenum format,
-    GLenum type,
-    MaybeShared<DOMArrayBufferView> pixels) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::texSubImage3D(
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLint zoffset,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLenum format,
-    GLenum type,
-    MaybeShared<DOMArrayBufferView> pixels,
-    GLuint src_offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::copyTexSubImage3D(GLenum target,
-                                                        GLint level,
-                                                        GLint xoffset,
-                                                        GLint yoffset,
-                                                        GLint zoffset,
-                                                        GLint x,
-                                                        GLint y,
-                                                        GLsizei width,
-                                                        GLsizei height) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::compressedTexImage2D(
-    GLenum target,
-    GLint level,
-    GLenum internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLint border,
-    MaybeShared<DOMArrayBufferView> data,
-    GLuint src_offset,
-    GLuint src_length_override) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::compressedTexSubImage2D(
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLsizei width,
-    GLsizei height,
-    GLenum format,
-    MaybeShared<DOMArrayBufferView> data,
-    GLuint src_offset,
-    GLuint src_length_override) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::compressedTexImage3D(
-    GLenum target,
-    GLint level,
-    GLenum internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLint border,
-    MaybeShared<DOMArrayBufferView> data,
-    GLuint src_offset,
-    GLuint src_length_override) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::compressedTexSubImage3D(
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLint zoffset,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLenum format,
-    MaybeShared<DOMArrayBufferView> data,
-    GLuint src_offset,
-    GLuint src_length_override) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::compressedTexImage2D(
-    GLenum target,
-    GLint level,
-    GLenum internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLint border,
-    GLsizei image_size,
-    int64_t offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::compressedTexSubImage2D(
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLsizei width,
-    GLsizei height,
-    GLenum format,
-    GLsizei image_size,
-    int64_t offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::compressedTexImage3D(
-    GLenum target,
-    GLint level,
-    GLenum internalformat,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLint border,
-    GLsizei image_size,
-    int64_t offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::compressedTexSubImage3D(
-    GLenum target,
-    GLint level,
-    GLint xoffset,
-    GLint yoffset,
-    GLint zoffset,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLenum format,
-    GLsizei image_size,
-    int64_t offset) {
-  NOTIMPLEMENTED();
-}
-
-GLint WebGLRenderingContextWebGPUBase::getFragDataLocation(
-    WebGLProgram* program,
-    const String& name) {
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-void WebGLRenderingContextWebGPUBase::uniform1ui(
-    const WebGLUniformLocation* location,
-    GLuint v0) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform2ui(
-    const WebGLUniformLocation* location,
-    GLuint v0,
-    GLuint v1) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform3ui(
-    const WebGLUniformLocation* location,
-    GLuint v0,
-    GLuint v1,
-    GLuint v2) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform4ui(
-    const WebGLUniformLocation* location,
-    GLuint v0,
-    GLuint v1,
-    GLuint v2,
-    GLuint v3) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform1fv(
-    const WebGLUniformLocation* location,
-    base::span<const GLfloat> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform2fv(
-    const WebGLUniformLocation* location,
-    base::span<const GLfloat> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform3fv(
-    const WebGLUniformLocation* location,
-    base::span<const GLfloat> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform4fv(
-    const WebGLUniformLocation* location,
-    base::span<const GLfloat> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform1iv(
-    const WebGLUniformLocation* location,
-    base::span<const GLint> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform2iv(
-    const WebGLUniformLocation* location,
-    base::span<const GLint> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform3iv(
-    const WebGLUniformLocation* location,
-    base::span<const GLint> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform4iv(
-    const WebGLUniformLocation* location,
-    base::span<const GLint> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform1uiv(
-    const WebGLUniformLocation* location,
-    base::span<const GLuint> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform2uiv(
-    const WebGLUniformLocation* location,
-    base::span<const GLuint> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform3uiv(
-    const WebGLUniformLocation* location,
-    base::span<const GLuint> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniform4uiv(
-    const WebGLUniformLocation* location,
-    base::span<const GLuint> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniformMatrix2fv(
-    const WebGLUniformLocation* location,
-    GLboolean transpose,
-    base::span<const GLfloat> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniformMatrix3fv(
-    const WebGLUniformLocation* location,
-    GLboolean transpose,
-    base::span<const GLfloat> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniformMatrix4fv(
-    const WebGLUniformLocation* location,
-    GLboolean transpose,
-    base::span<const GLfloat> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniformMatrix2x3fv(
-    const WebGLUniformLocation* location,
-    GLboolean transpose,
-    base::span<const GLfloat> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniformMatrix3x2fv(
-    const WebGLUniformLocation* location,
-    GLboolean transpose,
-    base::span<const GLfloat> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniformMatrix2x4fv(
-    const WebGLUniformLocation* location,
-    GLboolean transpose,
-    base::span<const GLfloat> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniformMatrix4x2fv(
-    const WebGLUniformLocation* location,
-    GLboolean transpose,
-    base::span<const GLfloat> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniformMatrix3x4fv(
-    const WebGLUniformLocation* location,
-    GLboolean transpose,
-    base::span<const GLfloat> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::uniformMatrix4x3fv(
-    const WebGLUniformLocation* location,
-    GLboolean transpose,
-    base::span<const GLfloat> v,
-    GLuint src_offset,
-    GLuint src_length) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::vertexAttribI4i(GLuint index,
-                                                      GLint x,
-                                                      GLint y,
-                                                      GLint z,
-                                                      GLint w) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::vertexAttribI4iv(
-    GLuint index,
-    base::span<const GLint> v) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::vertexAttribI4ui(GLuint index,
-                                                       GLuint x,
-                                                       GLuint y,
-                                                       GLuint z,
-                                                       GLuint w) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::vertexAttribI4uiv(
-    GLuint index,
-    base::span<const GLuint> v) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::vertexAttribIPointer(GLuint index,
-                                                           GLint size,
-                                                           GLenum type,
-                                                           GLsizei stride,
-                                                           int64_t offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::vertexAttribDivisor(GLuint index,
-                                                          GLuint divisor) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::drawArraysInstanced(
-    GLenum mode,
-    GLint first,
-    GLsizei count,
-    GLsizei instance_count) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::drawElementsInstanced(
-    GLenum mode,
-    GLsizei count,
-    GLenum type,
-    int64_t offset,
-    GLsizei instance_count) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::drawRangeElements(GLenum mode,
-                                                        GLuint start,
-                                                        GLuint end,
-                                                        GLsizei count,
-                                                        GLenum type,
-                                                        int64_t offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::drawBuffers(
-    const Vector<GLenum>& buffers) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::clearBufferiv(
-    GLenum buffer,
-    GLint drawbuffer,
-    base::span<const GLint> value,
-    GLuint src_offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::clearBufferuiv(
-    GLenum buffer,
-    GLint drawbuffer,
-    base::span<const GLuint> value,
-    GLuint src_offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::clearBufferfv(
-    GLenum buffer,
-    GLint drawbuffer,
-    base::span<const GLfloat> value,
-    GLuint src_offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::clearBufferfi(GLenum buffer,
-                                                    GLint drawbuffer,
-                                                    GLfloat depth,
-                                                    GLint stencil) {
-  NOTIMPLEMENTED();
-}
-
-WebGLQuery* WebGLRenderingContextWebGPUBase::createQuery() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-void WebGLRenderingContextWebGPUBase::deleteQuery(WebGLQuery* query) {
-  NOTIMPLEMENTED();
-}
-
-bool WebGLRenderingContextWebGPUBase::isQuery(WebGLQuery* query) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-void WebGLRenderingContextWebGPUBase::beginQuery(GLenum target,
-                                                 WebGLQuery* query) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::endQuery(GLenum target) {
-  NOTIMPLEMENTED();
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getQuery(ScriptState* script_state,
-                                                      GLenum target,
-                                                      GLenum pname) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getQueryParameter(
-    ScriptState* script_state,
-    WebGLQuery* query,
-    GLenum pname) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-WebGLSampler* WebGLRenderingContextWebGPUBase::createSampler() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-void WebGLRenderingContextWebGPUBase::deleteSampler(WebGLSampler* sampler) {
-  NOTIMPLEMENTED();
-}
-
-bool WebGLRenderingContextWebGPUBase::isSampler(WebGLSampler* sampler) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-void WebGLRenderingContextWebGPUBase::bindSampler(GLuint unit,
-                                                  WebGLSampler* sampler) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::samplerParameteri(WebGLSampler* sampler,
-                                                        GLenum pname,
-                                                        GLint param) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::samplerParameterf(WebGLSampler* sampler,
-                                                        GLenum pname,
-                                                        GLfloat param) {
-  NOTIMPLEMENTED();
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getSamplerParameter(
-    ScriptState* script_state,
-    WebGLSampler* sampler,
-    GLenum pname) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-WebGLSync* WebGLRenderingContextWebGPUBase::fenceSync(GLenum condition,
-                                                      GLbitfield flags) {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-bool WebGLRenderingContextWebGPUBase::isSync(WebGLSync* sync) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-void WebGLRenderingContextWebGPUBase::deleteSync(WebGLSync* sync) {
-  NOTIMPLEMENTED();
-}
-
-GLenum WebGLRenderingContextWebGPUBase::clientWaitSync(WebGLSync* sync,
-                                                       GLbitfield flags,
-                                                       GLuint64 timeout) {
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-void WebGLRenderingContextWebGPUBase::waitSync(WebGLSync* sync,
-                                               GLbitfield flags,
-                                               GLint64 timeout) {
-  NOTIMPLEMENTED();
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getSyncParameter(
-    ScriptState* script_state,
-    WebGLSync* sync,
-    GLenum pname) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-WebGLTransformFeedback*
-WebGLRenderingContextWebGPUBase::createTransformFeedback() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-void WebGLRenderingContextWebGPUBase::deleteTransformFeedback(
-    WebGLTransformFeedback* feedback) {
-  NOTIMPLEMENTED();
-}
-
-bool WebGLRenderingContextWebGPUBase::isTransformFeedback(
-    WebGLTransformFeedback* feedback) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-void WebGLRenderingContextWebGPUBase::bindTransformFeedback(
-    GLenum target,
-    WebGLTransformFeedback* feedback) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::beginTransformFeedback(
-    GLenum primitive_mode) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::endTransformFeedback() {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::transformFeedbackVaryings(
-    WebGLProgram* program,
-    const Vector<String>& varyings,
-    GLenum buffer_mode) {
-  NOTIMPLEMENTED();
-}
-
-WebGLActiveInfo* WebGLRenderingContextWebGPUBase::getTransformFeedbackVarying(
-    WebGLProgram* program,
-    GLuint index) {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-void WebGLRenderingContextWebGPUBase::pauseTransformFeedback() {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::resumeTransformFeedback() {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::bindBufferBase(GLenum target,
-                                                     GLuint index,
-                                                     WebGLBuffer* buffer) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::bindBufferRange(GLenum target,
-                                                      GLuint index,
-                                                      WebGLBuffer* buffer,
-                                                      int64_t offset,
-                                                      int64_t size) {
-  NOTIMPLEMENTED();
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getIndexedParameter(
-    ScriptState* script_state,
-    GLenum target,
-    GLuint index) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-std::optional<Vector<GLuint>>
-WebGLRenderingContextWebGPUBase::getUniformIndices(
-    WebGLProgram* program,
-    const Vector<String>& uniform_names) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getActiveUniforms(
-    ScriptState* script_state,
-    WebGLProgram* program,
-    const Vector<GLuint>& uniform_indices,
-    GLenum pname) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-GLuint WebGLRenderingContextWebGPUBase::getUniformBlockIndex(
-    WebGLProgram* program,
-    const String& uniform_block_name) {
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-ScriptValue WebGLRenderingContextWebGPUBase::getActiveUniformBlockParameter(
-    ScriptState* script_state,
-    WebGLProgram* program,
-    GLuint uniform_block_index,
-    GLenum pname) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-String WebGLRenderingContextWebGPUBase::getActiveUniformBlockName(
-    WebGLProgram* program,
-    GLuint uniform_block_index) {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-void WebGLRenderingContextWebGPUBase::uniformBlockBinding(
-    WebGLProgram* program,
-    GLuint uniform_block_index,
-    GLuint uniform_block_binding) {
-  NOTIMPLEMENTED();
-}
-
-WebGLVertexArrayObject* WebGLRenderingContextWebGPUBase::createVertexArray() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-void WebGLRenderingContextWebGPUBase::deleteVertexArray(
-    WebGLVertexArrayObject* vertex_array) {
-  NOTIMPLEMENTED();
-}
-
-bool WebGLRenderingContextWebGPUBase::isVertexArray(
-    WebGLVertexArrayObject* vertex_array) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-void WebGLRenderingContextWebGPUBase::bindVertexArray(
-    WebGLVertexArrayObject* vertex_array) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::readPixels(GLint x,
-                                                 GLint y,
-                                                 GLsizei width,
-                                                 GLsizei height,
-                                                 GLenum format,
-                                                 GLenum type,
-                                                 int64_t offset) {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::readPixels(
-    GLint x,
-    GLint y,
-    GLsizei width,
-    GLsizei height,
-    GLenum format,
-    GLenum type,
-    MaybeShared<DOMArrayBufferView> pixels,
-    int64_t offset) {
-  NOTIMPLEMENTED();
-}
-
-// **************************************************************************
-// End of WebGL2RenderingContextBase's IDL methods
-// **************************************************************************
-
-// ****************************************************************************
-// Start of CanvasRenderingContext implementation
-// ****************************************************************************
-SkAlphaType WebGLRenderingContextWebGPUBase::GetAlphaType() const {
-  NOTIMPLEMENTED();
-  return SkAlphaType::kUnknown_SkAlphaType;
-}
-
-viz::SharedImageFormat WebGLRenderingContextWebGPUBase::GetSharedImageFormat()
-    const {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-gfx::ColorSpace WebGLRenderingContextWebGPUBase::GetColorSpace() const {
-  NOTIMPLEMENTED();
-  return {};
-}
-
-bool WebGLRenderingContextWebGPUBase::isContextLost() const {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-scoped_refptr<StaticBitmapImage> WebGLRenderingContextWebGPUBase::GetImage(
-    FlushReason) {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-void WebGLRenderingContextWebGPUBase::SetHdrMetadata(
-    const gfx::HDRMetadata& hdr_metadata) {
-  NOTIMPLEMENTED();
-}
-
-bool WebGLRenderingContextWebGPUBase::IsComposited() const {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-bool WebGLRenderingContextWebGPUBase::IsPaintable() const {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-bool WebGLRenderingContextWebGPUBase::UsingSwapChain() const {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-void WebGLRenderingContextWebGPUBase::PageVisibilityChanged() {
-  NOTIMPLEMENTED();
-}
-
-bool WebGLRenderingContextWebGPUBase::PaintRenderingResultsToCanvas(
-    SourceDrawingBuffer) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-bool WebGLRenderingContextWebGPUBase::CopyRenderingResultsToVideoFrame(
-    WebGraphicsContext3DVideoFramePool*,
-    SourceDrawingBuffer,
-    const gfx::ColorSpace&,
-    VideoFrameCopyCompletedCallback) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-cc::Layer* WebGLRenderingContextWebGPUBase::CcLayer() const {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-void WebGLRenderingContextWebGPUBase::Stop() {
-  NOTIMPLEMENTED();
-}
-
-void WebGLRenderingContextWebGPUBase::FinalizeFrame(FlushReason) {
-  NOTIMPLEMENTED();
-}
-
-bool WebGLRenderingContextWebGPUBase::PushFrame() {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-// ****************************************************************************
-// End of CanvasRenderingContext implementation
-// ****************************************************************************
-
-void WebGLRenderingContextWebGPUBase::Trace(Visitor* visitor) const {
-  WebGLContextObjectSupport::Trace(visitor);
-  CanvasRenderingContext::Trace(visitor);
-}
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.h
deleted file mode 100644
index 10df703f..0000000
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.h
+++ /dev/null
@@ -1,1285 +0,0 @@
-// Copyright 2025 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_RENDERING_CONTEXT_WEBGPU_BASE_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_RENDERING_CONTEXT_WEBGPU_BASE_H_
-
-#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_predefined_color_space.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_webgl_context_attributes.h"
-#include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h"
-#include "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-class ExceptionState;
-class HTMLImageElement;
-class HTMLVideoElement;
-class ImageBitmap;
-class ImageData;
-class ScriptState;
-class V8PredefinedColorSpace;
-class V8UnionHTMLCanvasElementOrOffscreenCanvas;
-class VideoFrame;
-class WebGLActiveInfo;
-class WebGLBuffer;
-class WebGLFramebuffer;
-class WebGLProgram;
-class WebGLQuery;
-class WebGLRenderbuffer;
-class WebGLSampler;
-class WebGLShader;
-class WebGLShaderPrecisionFormat;
-class WebGLSync;
-class WebGLTexture;
-class WebGLTransformFeedback;
-class WebGLUniformLocation;
-class WebGLVertexArrayObject;
-
-class MODULES_EXPORT WebGLRenderingContextWebGPUBase
-    : public WebGLContextObjectSupport,
-      public CanvasRenderingContext {
- public:
-  WebGLRenderingContextWebGPUBase(
-      CanvasRenderingContextHost* host,
-      const CanvasContextCreationAttributesCore& requested_attributes,
-      CanvasRenderingAPI api);
-  ~WebGLRenderingContextWebGPUBase() override;
-
-  WebGLRenderingContextWebGPUBase(const WebGLRenderingContextWebGPUBase&) =
-      delete;
-  WebGLRenderingContextWebGPUBase& operator=(
-      const WebGLRenderingContextWebGPUBase&) = delete;
-
-  // **************************************************************************
-  // Start of WebGLRenderingContextBase's IDL methods
-  // **************************************************************************
-  V8UnionHTMLCanvasElementOrOffscreenCanvas* getHTMLOrOffscreenCanvas() const;
-
-  int drawingBufferWidth() const;
-  int drawingBufferHeight() const;
-  GLenum drawingBufferFormat() const;
-  V8PredefinedColorSpace drawingBufferColorSpace() const;
-  void setDrawingBufferColorSpace(const V8PredefinedColorSpace& color_space,
-                                  ExceptionState&);
-  V8PredefinedColorSpace unpackColorSpace() const;
-  void setUnpackColorSpace(const V8PredefinedColorSpace& color_space,
-                           ExceptionState&);
-
-  void activeTexture(GLenum texture);
-  void attachShader(WebGLProgram*, WebGLShader*);
-
-  void bindAttribLocation(WebGLProgram*, GLuint index, const String& name);
-  void bindBuffer(GLenum target, WebGLBuffer* buffer);
-  void bindFramebuffer(GLenum target, WebGLFramebuffer*);
-  void bindRenderbuffer(GLenum target, WebGLRenderbuffer*);
-  void bindTexture(GLenum target, WebGLTexture*);
-  void blendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
-  void blendEquation(GLenum mode);
-  void blendEquationSeparate(GLenum mode_rgb, GLenum mode_alpha);
-  void blendFunc(GLenum sfactor, GLenum dfactor);
-  void blendFuncSeparate(GLenum src_rgb,
-                         GLenum dst_rgb,
-                         GLenum src_alpha,
-                         GLenum dst_alpha);
-
-  void bufferData(GLenum target, int64_t size, GLenum usage);
-  void bufferData(GLenum target, DOMArrayBufferBase* data, GLenum usage);
-  void bufferData(GLenum target,
-                  MaybeShared<DOMArrayBufferView> data,
-                  GLenum usage);
-  void bufferSubData(GLenum target,
-                     int64_t offset,
-                     base::span<const uint8_t> data);
-
-  GLenum checkFramebufferStatus(GLenum target);
-  void clear(GLbitfield mask);
-  void clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
-  void clearDepth(GLfloat);
-  void clearStencil(GLint);
-  void colorMask(GLboolean red,
-                 GLboolean green,
-                 GLboolean blue,
-                 GLboolean alpha);
-  void compileShader(WebGLShader*);
-
-  void compressedTexImage2D(GLenum target,
-                            GLint level,
-                            GLenum internalformat,
-                            GLsizei width,
-                            GLsizei height,
-                            GLint border,
-                            MaybeShared<DOMArrayBufferView> data);
-  void compressedTexSubImage2D(GLenum target,
-                               GLint level,
-                               GLint xoffset,
-                               GLint yoffset,
-                               GLsizei width,
-                               GLsizei height,
-                               GLenum format,
-                               MaybeShared<DOMArrayBufferView> data);
-  void copyTexImage2D(GLenum target,
-                      GLint level,
-                      GLenum internalformat,
-                      GLint x,
-                      GLint y,
-                      GLsizei width,
-                      GLsizei height,
-                      GLint border);
-  void copyTexSubImage2D(GLenum target,
-                         GLint level,
-                         GLint xoffset,
-                         GLint yoffset,
-                         GLint x,
-                         GLint y,
-                         GLsizei width,
-                         GLsizei height);
-
-  WebGLBuffer* createBuffer();
-  WebGLFramebuffer* createFramebuffer();
-  WebGLProgram* createProgram();
-  WebGLRenderbuffer* createRenderbuffer();
-  WebGLShader* createShader(GLenum type);
-  WebGLTexture* createTexture();
-
-  void cullFace(GLenum mode);
-
-  void deleteBuffer(WebGLBuffer*);
-  void deleteFramebuffer(WebGLFramebuffer*);
-  void deleteProgram(WebGLProgram*);
-  void deleteRenderbuffer(WebGLRenderbuffer*);
-  void deleteShader(WebGLShader*);
-  void deleteTexture(WebGLTexture*);
-
-  void depthFunc(GLenum);
-  void depthMask(GLboolean);
-  void depthRange(GLfloat z_near, GLfloat z_far);
-  void detachShader(WebGLProgram*, WebGLShader*);
-  void disable(GLenum cap);
-  void disableVertexAttribArray(GLuint index);
-  void drawArrays(GLenum mode, GLint first, GLsizei count);
-  void drawElements(GLenum mode, GLsizei count, GLenum type, int64_t offset);
-
-  void enable(GLenum cap);
-  void enableVertexAttribArray(GLuint index);
-  void finish();
-  void flush();
-  void framebufferRenderbuffer(GLenum target,
-                               GLenum attachment,
-                               GLenum renderbuffertarget,
-                               WebGLRenderbuffer*);
-  void framebufferTexture2D(GLenum target,
-                            GLenum attachment,
-                            GLenum textarget,
-                            WebGLTexture*,
-                            GLint level);
-  void frontFace(GLenum mode);
-  void generateMipmap(GLenum target);
-
-  WebGLActiveInfo* getActiveAttrib(WebGLProgram*, GLuint index);
-  WebGLActiveInfo* getActiveUniform(WebGLProgram*, GLuint index);
-  std::optional<HeapVector<Member<WebGLShader>>> getAttachedShaders(
-      WebGLProgram*);
-  GLint getAttribLocation(WebGLProgram*, const String& name);
-  ScriptValue getBufferParameter(ScriptState*, GLenum target, GLenum pname);
-  WebGLContextAttributes* getContextAttributes() const;
-  GLenum getError();
-  ScriptObject getExtension(ScriptState*, const String& name);
-  ScriptValue getFramebufferAttachmentParameter(ScriptState*,
-                                                GLenum target,
-                                                GLenum attachment,
-                                                GLenum pname);
-  ScriptValue getParameter(ScriptState*, GLenum pname);
-  ScriptValue getProgramParameter(ScriptState*, WebGLProgram*, GLenum pname);
-  String getProgramInfoLog(WebGLProgram*);
-  ScriptValue getRenderbufferParameter(ScriptState*,
-                                       GLenum target,
-                                       GLenum pname);
-  ScriptValue getShaderParameter(ScriptState*, WebGLShader*, GLenum pname);
-  String getShaderInfoLog(WebGLShader*);
-  WebGLShaderPrecisionFormat* getShaderPrecisionFormat(GLenum shader_type,
-                                                       GLenum precision_type);
-  String getShaderSource(WebGLShader*);
-  std::optional<Vector<String>> getSupportedExtensions();
-  ScriptValue getTexParameter(ScriptState*, GLenum target, GLenum pname);
-  ScriptValue getUniform(ScriptState*,
-                         WebGLProgram*,
-                         const WebGLUniformLocation*);
-  WebGLUniformLocation* getUniformLocation(WebGLProgram*, const String&);
-  ScriptValue getVertexAttrib(ScriptState*, GLuint index, GLenum pname);
-  int64_t getVertexAttribOffset(GLuint index, GLenum pname);
-
-  void hint(GLenum target, GLenum mode);
-  bool isBuffer(WebGLBuffer*);
-  bool isEnabled(GLenum cap);
-  bool isFramebuffer(WebGLFramebuffer*);
-  bool isProgram(WebGLProgram*);
-  bool isRenderbuffer(WebGLRenderbuffer*);
-  bool isShader(WebGLShader*);
-  bool isTexture(WebGLTexture*);
-
-  void lineWidth(GLfloat);
-  void linkProgram(WebGLProgram*);
-  void pixelStorei(GLenum pname, GLint param);
-  void polygonOffset(GLfloat factor, GLfloat units);
-
-  void readPixels(GLint x,
-                  GLint y,
-                  GLsizei width,
-                  GLsizei height,
-                  GLenum format,
-                  GLenum type,
-                  MaybeShared<DOMArrayBufferView> pixels);
-
-  void renderbufferStorage(GLenum target,
-                           GLenum internalformat,
-                           GLsizei width,
-                           GLsizei height);
-
-  void sampleCoverage(GLfloat value, GLboolean invert);
-  void scissor(GLint x, GLint y, GLsizei width, GLsizei height);
-  void shaderSource(WebGLShader*, const String&);
-  void stencilFunc(GLenum func, GLint ref, GLuint mask);
-  void stencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
-  void stencilMask(GLuint);
-  void stencilMaskSeparate(GLenum face, GLuint mask);
-  void stencilOp(GLenum fail, GLenum zfail, GLenum zpass);
-  void stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
-
-  void texParameterf(GLenum target, GLenum pname, GLfloat param);
-  void texParameteri(GLenum target, GLenum pname, GLint param);
-
-  void texImage2D(GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  MaybeShared<DOMArrayBufferView>);
-  void texImage2D(GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLenum format,
-                  GLenum type,
-                  ImageData*);
-  void texImage2D(ScriptState*,
-                  GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLenum format,
-                  GLenum type,
-                  HTMLImageElement*,
-                  ExceptionState&);
-  void texImage2D(ScriptState*,
-                  GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLenum format,
-                  GLenum type,
-                  CanvasRenderingContextHost*,
-                  ExceptionState&);
-  void texImage2D(ScriptState*,
-                  GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLenum format,
-                  GLenum type,
-                  HTMLVideoElement*,
-                  ExceptionState&);
-  void texImage2D(ScriptState*,
-                  GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLenum format,
-                  GLenum type,
-                  VideoFrame*,
-                  ExceptionState&);
-  void texImage2D(GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLenum format,
-                  GLenum type,
-                  ImageBitmap*,
-                  ExceptionState&);
-
-  void texSubImage2D(GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLenum format,
-                     GLenum type,
-                     MaybeShared<DOMArrayBufferView>);
-  void texSubImage2D(GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLenum format,
-                     GLenum type,
-                     ImageData*);
-  void texSubImage2D(ScriptState*,
-                     GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLenum format,
-                     GLenum type,
-                     HTMLImageElement*,
-                     ExceptionState&);
-  void texSubImage2D(ScriptState*,
-                     GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLenum format,
-                     GLenum type,
-                     CanvasRenderingContextHost*,
-                     ExceptionState&);
-  void texSubImage2D(ScriptState*,
-                     GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLenum format,
-                     GLenum type,
-                     HTMLVideoElement*,
-                     ExceptionState&);
-  void texSubImage2D(ScriptState*,
-                     GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLenum format,
-                     GLenum type,
-                     VideoFrame*,
-                     ExceptionState&);
-  void texSubImage2D(GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLenum format,
-                     GLenum type,
-                     ImageBitmap*,
-                     ExceptionState&);
-
-  void uniform1f(const WebGLUniformLocation*, GLfloat x);
-  void uniform1fv(const WebGLUniformLocation*, base::span<const GLfloat>);
-  void uniform1i(const WebGLUniformLocation*, GLint x);
-  void uniform1iv(const WebGLUniformLocation*, base::span<const GLint>);
-  void uniform2f(const WebGLUniformLocation*, GLfloat x, GLfloat y);
-  void uniform2fv(const WebGLUniformLocation*, base::span<const GLfloat>);
-  void uniform2i(const WebGLUniformLocation*, GLint x, GLint y);
-  void uniform2iv(const WebGLUniformLocation*, base::span<const GLint>);
-  void uniform3f(const WebGLUniformLocation*, GLfloat x, GLfloat y, GLfloat z);
-  void uniform3fv(const WebGLUniformLocation*, base::span<const GLfloat>);
-  void uniform3i(const WebGLUniformLocation*, GLint x, GLint y, GLint z);
-  void uniform3iv(const WebGLUniformLocation*, base::span<const GLint>);
-  void uniform4f(const WebGLUniformLocation*,
-                 GLfloat x,
-                 GLfloat y,
-                 GLfloat z,
-                 GLfloat w);
-  void uniform4fv(const WebGLUniformLocation*, base::span<const GLfloat>);
-  void uniform4i(const WebGLUniformLocation*,
-                 GLint x,
-                 GLint y,
-                 GLint z,
-                 GLint w);
-  void uniform4iv(const WebGLUniformLocation*, base::span<const GLint>);
-
-  void uniformMatrix2fv(const WebGLUniformLocation*,
-                        GLboolean transpose,
-                        base::span<const GLfloat> value);
-  void uniformMatrix3fv(const WebGLUniformLocation*,
-                        GLboolean transpose,
-                        base::span<const GLfloat> value);
-  void uniformMatrix4fv(const WebGLUniformLocation*,
-                        GLboolean transpose,
-                        base::span<const GLfloat> value);
-
-  void useProgram(WebGLProgram*);
-  void validateProgram(WebGLProgram*);
-
-  void vertexAttrib1f(GLuint index, GLfloat x);
-  void vertexAttrib1fv(GLuint index, base::span<const GLfloat> values);
-  void vertexAttrib2f(GLuint index, GLfloat x, GLfloat y);
-  void vertexAttrib2fv(GLuint index, base::span<const GLfloat> values);
-  void vertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z);
-  void vertexAttrib3fv(GLuint index, base::span<const GLfloat> values);
-  void vertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
-  void vertexAttrib4fv(GLuint index, base::span<const GLfloat> values);
-  void vertexAttribPointer(GLuint index,
-                           GLint size,
-                           GLenum type,
-                           GLboolean normalized,
-                           GLsizei stride,
-                           int64_t offset);
-
-  void viewport(GLint x, GLint y, GLsizei width, GLsizei height);
-
-  void drawingBufferStorage(GLenum sizedformat, GLsizei width, GLsizei height);
-
-  void commit();
-
-  ScriptPromise<IDLUndefined> makeXRCompatible(ScriptState*, ExceptionState&);
-  // **************************************************************************
-  // End of WebGLRenderingContextBase's IDL methods
-  // **************************************************************************
-
-  // **************************************************************************
-  // Start of WebGL2RenderingContextBase's IDL methods
-  // **************************************************************************
-
-  /* Buffer objects */
-  void bufferData(GLenum target,
-                  MaybeShared<DOMArrayBufferView> srcData,
-                  GLenum usage,
-                  int64_t srcOffset,
-                  GLuint length);
-  void bufferSubData(GLenum target,
-                     int64_t offset,
-                     MaybeShared<DOMArrayBufferView> srcData,
-                     int64_t srcOffset,
-                     GLuint length);
-  void copyBufferSubData(GLenum readTarget,
-                         GLenum writeTarget,
-                         int64_t readOffset,
-                         int64_t writeOffset,
-                         int64_t size);
-  void getBufferSubData(GLenum target,
-                        int64_t srcByteOffset,
-                        MaybeShared<DOMArrayBufferView> dstData,
-                        int64_t dstOffset,
-                        GLuint length);
-
-  /* Framebuffer objects */
-  void blitFramebuffer(GLint src_x0,
-                       GLint src_y0,
-                       GLint src_x1,
-                       GLint src_y1,
-                       GLint dst_x0,
-                       GLint dst_y0,
-                       GLint dst_x1,
-                       GLint dst_y1,
-                       GLbitfield mask,
-                       GLenum filter);
-  void framebufferTextureLayer(GLenum target,
-                               GLenum attachment,
-                               WebGLTexture* texture,
-                               GLint level,
-                               GLint layer);
-  ScriptValue getInternalformatParameter(ScriptState* script_state,
-                                         GLenum target,
-                                         GLenum internalformat,
-                                         GLenum pname);
-  void invalidateFramebuffer(GLenum target, const Vector<GLenum>& attachments);
-  void invalidateSubFramebuffer(GLenum target,
-                                const Vector<GLenum>& attachments,
-                                GLint x,
-                                GLint y,
-                                GLsizei width,
-                                GLsizei height);
-  void readBuffer(GLenum mode);
-
-  /* Renderbuffer objects */
-  void renderbufferStorageMultisample(GLenum target,
-                                      GLsizei samples,
-                                      GLenum internalformat,
-                                      GLsizei width,
-                                      GLsizei height);
-
-  /* Texture objects */
-  void texImage2D(GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  int64_t offset);
-  void texImage2D(GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  ImageData* pixels);
-  void texImage2D(ScriptState* script_state,
-                  GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  HTMLImageElement* image,
-                  ExceptionState& exception_state);
-  // Handles both OffscreenCanvas and HTMLCanvasElement
-  void texImage2D(ScriptState* script_state,
-                  GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  CanvasRenderingContextHost* canvas,
-                  ExceptionState& exception_state);
-  void texImage2D(ScriptState* script_state,
-                  GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  HTMLVideoElement* video,
-                  ExceptionState& exception_state);
-  void texImage2D(ScriptState* script_state,
-                  GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  VideoFrame* frame,
-                  ExceptionState& exception_state);
-  void texImage2D(GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  ImageBitmap* bitmap,
-                  ExceptionState& exception_state);
-  void texImage2D(GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  MaybeShared<DOMArrayBufferView> data,
-                  int64_t src_offset);
-
-  void texElement2D(ScriptState* script_state,
-                    GLenum target,
-                    GLint level,
-                    GLint internalformat,
-                    GLenum format,
-                    GLenum type,
-                    Element* element,
-                    ExceptionState& exception_state);
-
-  void texSubImage2D(GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLenum format,
-                     GLenum type,
-                     int64_t offset);
-  void texSubImage2D(GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLenum format,
-                     GLenum type,
-                     ImageData* pixels);
-  void texSubImage2D(ScriptState* script_state,
-                     GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLenum format,
-                     GLenum type,
-                     HTMLImageElement* image,
-                     ExceptionState& exception_state);
-  // Handles both OffscreenCanvas and HTMLCanvasElement
-  void texSubImage2D(ScriptState* script_state,
-                     GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLenum format,
-                     GLenum type,
-                     CanvasRenderingContextHost* canvas,
-                     ExceptionState& exception_state);
-  void texSubImage2D(ScriptState* script_state,
-                     GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLenum format,
-                     GLenum type,
-                     HTMLVideoElement* video,
-                     ExceptionState& exception_state);
-  void texSubImage2D(ScriptState* script_state,
-                     GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLenum format,
-                     GLenum type,
-                     VideoFrame* frame,
-                     ExceptionState& exception_state);
-  void texSubImage2D(GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLenum format,
-                     GLenum type,
-                     ImageBitmap* bitmap,
-                     ExceptionState& exception_state);
-  void texSubImage2D(GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLenum format,
-                     GLenum type,
-                     MaybeShared<DOMArrayBufferView> pixels,
-                     int64_t src_offset);
-
-  void texStorage2D(GLenum target,
-                    GLsizei levels,
-                    GLenum internalformat,
-                    GLsizei width,
-                    GLsizei height);
-  void texStorage3D(GLenum target,
-                    GLsizei levels,
-                    GLenum internalformat,
-                    GLsizei width,
-                    GLsizei height,
-                    GLsizei depth);
-  void texImage3D(GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLsizei depth,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  int64_t offset);
-  void texImage3D(GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLsizei depth,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  ImageData* pixels);
-  void texImage3D(ScriptState* script_state,
-                  GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLsizei depth,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  HTMLImageElement* image,
-                  ExceptionState& exception_state);
-  // Handles both OffscreenCanvas and HTMLCanvasElement
-  void texImage3D(ScriptState* script_state,
-                  GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLsizei depth,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  CanvasRenderingContextHost* canvas,
-                  ExceptionState& exception_state);
-  void texImage3D(ScriptState* script_state,
-                  GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLsizei depth,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  HTMLVideoElement* video,
-                  ExceptionState& exception_state);
-  void texImage3D(ScriptState* script_state,
-                  GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLsizei depth,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  VideoFrame* frame,
-                  ExceptionState& exception_state);
-  void texImage3D(GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLsizei depth,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  ImageBitmap* bitmap,
-                  ExceptionState& exception_state);
-  void texImage3D(GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLsizei depth,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  MaybeShared<DOMArrayBufferView> pixels);
-  void texImage3D(GLenum target,
-                  GLint level,
-                  GLint internalformat,
-                  GLsizei width,
-                  GLsizei height,
-                  GLsizei depth,
-                  GLint border,
-                  GLenum format,
-                  GLenum type,
-                  MaybeShared<DOMArrayBufferView> pixels,
-                  GLuint src_offset);
-  void texSubImage3D(GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLint zoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLsizei depth,
-                     GLenum format,
-                     GLenum type,
-                     int64_t offset);
-  void texSubImage3D(GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLint zoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLsizei depth,
-                     GLenum format,
-                     GLenum type,
-                     ImageData* pixels);
-  void texSubImage3D(ScriptState* script_state,
-                     GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLint zoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLsizei depth,
-                     GLenum format,
-                     GLenum type,
-                     HTMLImageElement* image,
-                     ExceptionState& exception_state);
-  // Handles both OffscreenCanvas and HTMLCanvasElement
-  void texSubImage3D(ScriptState* script_state,
-                     GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLint zoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLsizei depth,
-                     GLenum format,
-                     GLenum type,
-                     CanvasRenderingContextHost* context_host,
-                     ExceptionState& exception_state);
-  void texSubImage3D(ScriptState* script_state,
-                     GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLint zoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLsizei depth,
-                     GLenum format,
-                     GLenum type,
-                     HTMLVideoElement* video,
-                     ExceptionState& exception_state);
-  void texSubImage3D(ScriptState* script_state,
-                     GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLint zoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLsizei depth,
-                     GLenum format,
-                     GLenum type,
-                     VideoFrame* frame,
-                     ExceptionState& exception_state);
-  void texSubImage3D(GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLint zoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLsizei depth,
-                     GLenum format,
-                     GLenum type,
-                     ImageBitmap* bitmap,
-                     ExceptionState& exception_state);
-  void texSubImage3D(GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLint zoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLsizei depth,
-                     GLenum format,
-                     GLenum type,
-                     MaybeShared<DOMArrayBufferView> pixels);
-  void texSubImage3D(GLenum target,
-                     GLint level,
-                     GLint xoffset,
-                     GLint yoffset,
-                     GLint zoffset,
-                     GLsizei width,
-                     GLsizei height,
-                     GLsizei depth,
-                     GLenum format,
-                     GLenum type,
-                     MaybeShared<DOMArrayBufferView> pixels,
-                     GLuint src_offset);
-
-  void copyTexSubImage3D(GLenum target,
-                         GLint level,
-                         GLint xoffset,
-                         GLint yoffset,
-                         GLint zoffset,
-                         GLint x,
-                         GLint y,
-                         GLsizei width,
-                         GLsizei height);
-
-  void compressedTexImage2D(GLenum target,
-                            GLint level,
-                            GLenum internalformat,
-                            GLsizei width,
-                            GLsizei height,
-                            GLint border,
-                            MaybeShared<DOMArrayBufferView> data,
-                            GLuint src_offset,
-                            GLuint src_length_override);
-  void compressedTexSubImage2D(GLenum target,
-                               GLint level,
-                               GLint xoffset,
-                               GLint yoffset,
-                               GLsizei width,
-                               GLsizei height,
-                               GLenum format,
-                               MaybeShared<DOMArrayBufferView> data,
-                               GLuint src_offset,
-                               GLuint src_length_override);
-  void compressedTexImage3D(GLenum target,
-                            GLint level,
-                            GLenum internalformat,
-                            GLsizei width,
-                            GLsizei height,
-                            GLsizei depth,
-                            GLint border,
-                            MaybeShared<DOMArrayBufferView> data,
-                            GLuint src_offset,
-                            GLuint src_length_override);
-  void compressedTexSubImage3D(GLenum target,
-                               GLint level,
-                               GLint xoffset,
-                               GLint yoffset,
-                               GLint zoffset,
-                               GLsizei width,
-                               GLsizei height,
-                               GLsizei depth,
-                               GLenum format,
-                               MaybeShared<DOMArrayBufferView> data,
-                               GLuint src_offset,
-                               GLuint src_length_override);
-  void compressedTexImage2D(GLenum target,
-                            GLint level,
-                            GLenum internalformat,
-                            GLsizei width,
-                            GLsizei height,
-                            GLint border,
-                            GLsizei image_size,
-                            int64_t offset);
-  void compressedTexSubImage2D(GLenum target,
-                               GLint level,
-                               GLint xoffset,
-                               GLint yoffset,
-                               GLsizei width,
-                               GLsizei height,
-                               GLenum format,
-                               GLsizei image_size,
-                               int64_t offset);
-  void compressedTexImage3D(GLenum target,
-                            GLint level,
-                            GLenum internalformat,
-                            GLsizei width,
-                            GLsizei height,
-                            GLsizei depth,
-                            GLint border,
-                            GLsizei image_size,
-                            int64_t offset);
-  void compressedTexSubImage3D(GLenum target,
-                               GLint level,
-                               GLint xoffset,
-                               GLint yoffset,
-                               GLint zoffset,
-                               GLsizei width,
-                               GLsizei height,
-                               GLsizei depth,
-                               GLenum format,
-                               GLsizei image_size,
-                               int64_t offset);
-
-  /* Programs and shaders */
-  GLint getFragDataLocation(WebGLProgram* program, const String& name);
-
-  /* Uniforms and attributes */
-  void uniform1ui(const WebGLUniformLocation* location, GLuint v0);
-  void uniform2ui(const WebGLUniformLocation* location, GLuint v0, GLuint v1);
-  void uniform3ui(const WebGLUniformLocation* location,
-                  GLuint v0,
-                  GLuint v1,
-                  GLuint v2);
-  void uniform4ui(const WebGLUniformLocation* location,
-                  GLuint v0,
-                  GLuint v1,
-                  GLuint v2,
-                  GLuint v3);
-  void uniform1fv(const WebGLUniformLocation* location,
-                  base::span<const GLfloat> v,
-                  GLuint src_offset,
-                  GLuint src_length);
-  void uniform2fv(const WebGLUniformLocation* location,
-                  base::span<const GLfloat> v,
-                  GLuint src_offset,
-                  GLuint src_length);
-  void uniform3fv(const WebGLUniformLocation* location,
-                  base::span<const GLfloat> v,
-                  GLuint src_offset,
-                  GLuint src_length);
-  void uniform4fv(const WebGLUniformLocation* location,
-                  base::span<const GLfloat> v,
-                  GLuint src_offset,
-                  GLuint src_length);
-  void uniform1iv(const WebGLUniformLocation* location,
-                  base::span<const GLint> v,
-                  GLuint src_offset,
-                  GLuint src_length);
-  void uniform2iv(const WebGLUniformLocation* location,
-                  base::span<const GLint> v,
-                  GLuint src_offset,
-                  GLuint src_length);
-  void uniform3iv(const WebGLUniformLocation* location,
-                  base::span<const GLint> v,
-                  GLuint src_offset,
-                  GLuint src_length);
-  void uniform4iv(const WebGLUniformLocation* location,
-                  base::span<const GLint> v,
-                  GLuint src_offset,
-                  GLuint src_length);
-  void uniform1uiv(const WebGLUniformLocation* location,
-                   base::span<const GLuint> v,
-                   GLuint src_offset,
-                   GLuint src_length);
-  void uniform2uiv(const WebGLUniformLocation* location,
-                   base::span<const GLuint> v,
-                   GLuint src_offset,
-                   GLuint src_length);
-  void uniform3uiv(const WebGLUniformLocation* location,
-                   base::span<const GLuint> v,
-                   GLuint src_offset,
-                   GLuint src_length);
-  void uniform4uiv(const WebGLUniformLocation* location,
-                   base::span<const GLuint> v,
-                   GLuint src_offset,
-                   GLuint src_length);
-  void uniformMatrix2fv(const WebGLUniformLocation* location,
-                        GLboolean transpose,
-                        base::span<const GLfloat> v,
-                        GLuint src_offset,
-                        GLuint src_length);
-  void uniformMatrix3fv(const WebGLUniformLocation* location,
-                        GLboolean transpose,
-                        base::span<const GLfloat> v,
-                        GLuint src_offset,
-                        GLuint src_length);
-  void uniformMatrix4fv(const WebGLUniformLocation* location,
-                        GLboolean transpose,
-                        base::span<const GLfloat> v,
-                        GLuint src_offset,
-                        GLuint src_length);
-  void uniformMatrix2x3fv(const WebGLUniformLocation* location,
-                          GLboolean transpose,
-                          base::span<const GLfloat> v,
-                          GLuint src_offset,
-                          GLuint src_length);
-  void uniformMatrix3x2fv(const WebGLUniformLocation* location,
-                          GLboolean transpose,
-                          base::span<const GLfloat> v,
-                          GLuint src_offset,
-                          GLuint src_length);
-  void uniformMatrix2x4fv(const WebGLUniformLocation* location,
-                          GLboolean transpose,
-                          base::span<const GLfloat> v,
-                          GLuint src_offset,
-                          GLuint src_length);
-  void uniformMatrix4x2fv(const WebGLUniformLocation* location,
-                          GLboolean transpose,
-                          base::span<const GLfloat> v,
-                          GLuint src_offset,
-                          GLuint src_length);
-  void uniformMatrix3x4fv(const WebGLUniformLocation* location,
-                          GLboolean transpose,
-                          base::span<const GLfloat> v,
-                          GLuint src_offset,
-                          GLuint src_length);
-  void uniformMatrix4x3fv(const WebGLUniformLocation* location,
-                          GLboolean transpose,
-                          base::span<const GLfloat> v,
-                          GLuint src_offset,
-                          GLuint src_length);
-
-  void vertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w);
-  void vertexAttribI4iv(GLuint index, base::span<const GLint> v);
-  void vertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
-  void vertexAttribI4uiv(GLuint index, base::span<const GLuint> v);
-  void vertexAttribIPointer(GLuint index,
-                            GLint size,
-                            GLenum type,
-                            GLsizei stride,
-                            int64_t offset);
-
-  /* Writing to the drawing buffer */
-  void vertexAttribDivisor(GLuint index, GLuint divisor);
-  void drawArraysInstanced(GLenum mode,
-                           GLint first,
-                           GLsizei count,
-                           GLsizei instance_count);
-  void drawElementsInstanced(GLenum mode,
-                             GLsizei count,
-                             GLenum type,
-                             int64_t offset,
-                             GLsizei instance_count);
-  void drawRangeElements(GLenum mode,
-                         GLuint start,
-                         GLuint end,
-                         GLsizei count,
-                         GLenum type,
-                         int64_t offset);
-
-  /* Multiple Render Targets */
-  void drawBuffers(const Vector<GLenum>& buffers);
-  void clearBufferiv(GLenum buffer,
-                     GLint drawbuffer,
-                     base::span<const GLint> value,
-                     GLuint src_offset);
-  void clearBufferuiv(GLenum buffer,
-                      GLint drawbuffer,
-                      base::span<const GLuint> value,
-                      GLuint src_offset);
-  void clearBufferfv(GLenum buffer,
-                     GLint drawbuffer,
-                     base::span<const GLfloat> value,
-                     GLuint src_offset);
-  void clearBufferfi(GLenum buffer,
-                     GLint drawbuffer,
-                     GLfloat depth,
-                     GLint stencil);
-
-  /* Query Objects */
-  WebGLQuery* createQuery();
-  void deleteQuery(WebGLQuery* query);
-  bool isQuery(WebGLQuery* query);
-  void beginQuery(GLenum target, WebGLQuery* query);
-  void endQuery(GLenum target);
-  ScriptValue getQuery(ScriptState* script_state, GLenum target, GLenum pname);
-  ScriptValue getQueryParameter(ScriptState* script_state,
-                                WebGLQuery* query,
-                                GLenum pname);
-
-  /* Sampler Objects */
-  WebGLSampler* createSampler();
-  void deleteSampler(WebGLSampler* sampler);
-  bool isSampler(WebGLSampler* sampler);
-  void bindSampler(GLuint unit, WebGLSampler* sampler);
-  void samplerParameteri(WebGLSampler* sampler, GLenum pname, GLint param);
-  void samplerParameterf(WebGLSampler* sampler, GLenum pname, GLfloat param);
-  ScriptValue getSamplerParameter(ScriptState* script_state,
-                                  WebGLSampler* sampler,
-                                  GLenum pname);
-
-  /* Sync objects */
-  WebGLSync* fenceSync(GLenum condition, GLbitfield flags);
-  bool isSync(WebGLSync* sync);
-  void deleteSync(WebGLSync* sync);
-  GLenum clientWaitSync(WebGLSync* sync, GLbitfield flags, GLuint64 timeout);
-  void waitSync(WebGLSync* sync, GLbitfield flags, GLint64 timeout);
-
-  ScriptValue getSyncParameter(ScriptState* script_state,
-                               WebGLSync* sync,
-                               GLenum pname);
-
-  /* Transform Feedback */
-  WebGLTransformFeedback* createTransformFeedback();
-  void deleteTransformFeedback(WebGLTransformFeedback* feedback);
-  bool isTransformFeedback(WebGLTransformFeedback* feedback);
-  void bindTransformFeedback(GLenum target, WebGLTransformFeedback* feedback);
-  void beginTransformFeedback(GLenum primitive_mode);
-  void endTransformFeedback();
-  void transformFeedbackVaryings(WebGLProgram* program,
-                                 const Vector<String>& varyings,
-                                 GLenum buffer_mode);
-  WebGLActiveInfo* getTransformFeedbackVarying(WebGLProgram* program,
-                                               GLuint index);
-  void pauseTransformFeedback();
-  void resumeTransformFeedback();
-
-  /* Uniform Buffer Objects and Transform Feedback Buffers */
-  void bindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer);
-  void bindBufferRange(GLenum target,
-                       GLuint index,
-                       WebGLBuffer* buffer,
-                       int64_t offset,
-                       int64_t size);
-  ScriptValue getIndexedParameter(ScriptState* script_state,
-                                  GLenum target,
-                                  GLuint index);
-  std::optional<Vector<GLuint>> getUniformIndices(
-      WebGLProgram* program,
-      const Vector<String>& uniform_names);
-  ScriptValue getActiveUniforms(ScriptState* script_state,
-                                WebGLProgram* program,
-                                const Vector<GLuint>& uniform_indices,
-                                GLenum pname);
-  GLuint getUniformBlockIndex(WebGLProgram* program,
-                              const String& uniform_block_name);
-  ScriptValue getActiveUniformBlockParameter(ScriptState* script_state,
-                                             WebGLProgram* program,
-                                             GLuint uniform_block_index,
-                                             GLenum pname);
-  String getActiveUniformBlockName(WebGLProgram* program,
-                                   GLuint uniform_block_index);
-  void uniformBlockBinding(WebGLProgram* program,
-                           GLuint uniform_block_index,
-                           GLuint uniform_block_binding);
-
-  /* Vertex Array Objects */
-  WebGLVertexArrayObject* createVertexArray();
-  void deleteVertexArray(WebGLVertexArrayObject* vertex_array);
-  bool isVertexArray(WebGLVertexArrayObject* vertex_array);
-  void bindVertexArray(WebGLVertexArrayObject* vertex_array);
-
-  /* Reading */
-  void readPixels(GLint x,
-                  GLint y,
-                  GLsizei width,
-                  GLsizei height,
-                  GLenum format,
-                  GLenum type,
-                  int64_t offset);
-  void readPixels(GLint x,
-                  GLint y,
-                  GLsizei width,
-                  GLsizei height,
-                  GLenum format,
-                  GLenum type,
-                  MaybeShared<DOMArrayBufferView> pixels,
-                  int64_t offset);
-
-  // **************************************************************************
-  // End of WebGL2RenderingContextBase's IDL methods
-  // **************************************************************************
-
-  // **************************************************************************
-  // Start of CanvasRenderingContext implementation
-  // **************************************************************************
-  SkAlphaType GetAlphaType() const override;
-  viz::SharedImageFormat GetSharedImageFormat() const override;
-  gfx::ColorSpace GetColorSpace() const override;
-  bool isContextLost() const override;
-  scoped_refptr<StaticBitmapImage> GetImage(FlushReason) override;
-  void SetHdrMetadata(const gfx::HDRMetadata& hdr_metadata) override;
-
-  bool IsComposited() const override;
-  bool IsPaintable() const override;
-  bool UsingSwapChain() const override;
-  void PageVisibilityChanged() override;
-  bool PaintRenderingResultsToCanvas(SourceDrawingBuffer) override;
-  bool CopyRenderingResultsToVideoFrame(
-      WebGraphicsContext3DVideoFramePool*,
-      SourceDrawingBuffer,
-      const gfx::ColorSpace&,
-      VideoFrameCopyCompletedCallback) override;
-
-  cc::Layer* CcLayer() const override;
-  void Stop() override;
-  void FinalizeFrame(FlushReason) override;
-  bool PushFrame() override;
-
-  // **************************************************************************
-  // End of CanvasRenderingContext implementation
-  // **************************************************************************
-
-  void Trace(Visitor*) const override;
-
- private:
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_RENDERING_CONTEXT_WEBGPU_BASE_H_
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_host.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_host.cc
index 574f923..2bdb75d 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_host.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_host.cc
@@ -23,9 +23,7 @@
 
 CanvasResourceHost::CanvasResourceHost(gfx::Size size) : size_(size) {}
 
-CanvasResourceHost::~CanvasResourceHost() {
-  ResetLayer();
-}
+CanvasResourceHost::~CanvasResourceHost() = default;
 
 std::unique_ptr<CanvasResourceProvider>
 CanvasResourceHost::ReplaceResourceProvider(
@@ -86,29 +84,6 @@
   return ShouldTryToUseGpuRaster() ? RasterMode::kGPU : RasterMode::kCPU;
 }
 
-void CanvasResourceHost::ResetLayer() {
-  if (cc_layer_) {
-    // Orphaning the layer is required to trigger the recreation of a new
-    // layer in the case where destruction is caused by a canvas resize. Test:
-    // virtual/gpu/fast/canvas/canvas-resize-after-paint-without-layout.html
-    cc_layer_->RemoveFromParent();
-    cc_layer_->ClearClient();
-    cc_layer_ = nullptr;
-  }
-}
-
-void CanvasResourceHost::ClearLayerTexture() {
-  if (cc_layer_) {
-    cc_layer_->ClearTexture();
-  }
-}
-
-void CanvasResourceHost::SetNeedsPushProperties() {
-  if (cc_layer_) {
-    cc_layer_->SetNeedsSetTransferableResource();
-  }
-}
-
 void CanvasResourceHost::FlushRecording(FlushReason reason) {
   if (resource_provider_) {
     resource_provider_->FlushCanvas(reason);
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_host.h b/third_party/blink/renderer/platform/graphics/canvas_resource_host.h
index 7701e37..0eab9dd 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_host.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_host.h
@@ -89,9 +89,11 @@
 
   // Actual RasterMode used for rendering 2d primitives.
   RasterMode GetRasterMode() const;
-  void ResetLayer();
-  void ClearLayerTexture();
-  void SetNeedsPushProperties();
+
+  // Called when the CC texture layer that this instance is holding (if any)
+  // should be cleared. Subclasses that can hold a CC texture layer should
+  // override this method.
+  virtual void ClearLayerTexture() {}
 
   virtual void SetTransferToGPUTextureWasInvoked() {}
   virtual bool TransferToGPUTextureWasInvoked() { return false; }
@@ -99,11 +101,6 @@
  protected:
   virtual CanvasResourceProvider* GetOrCreateCanvasResourceProviderImpl() = 0;
 
-  // TODO(399587138): Move this field to be held by HTMLCanvasElement and
-  // eventually by CanvasRenderingContext2D, as it's only instantiated by the
-  // latter.
-  scoped_refptr<cc::TextureLayer> cc_layer_;
-
  private:
   std::unique_ptr<CanvasResourceProvider> resource_provider_;
   RasterModeHint preferred_2d_raster_mode_ = RasterModeHint::kPreferCPU;
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 617cf7d9e..3b2aa129 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -4783,6 +4783,11 @@
       depends_on: ["FastSelectionSync", "TextareaLineEndingsAsBr"],
     },
     {
+      // crbug.com/341564372
+      name: "TextareaSplitText",
+      status: "experimental",
+    },
+    {
       // killswitch for fix in M137
       name: "TextareaStableResizing",
       status: "stable",
diff --git a/third_party/blink/renderer/platform/wtf/text/strcat.cc b/third_party/blink/renderer/platform/wtf/text/strcat.cc
index bfc1006b..edfc2d0d6 100644
--- a/third_party/blink/renderer/platform/wtf/text/strcat.cc
+++ b/third_party/blink/renderer/platform/wtf/text/strcat.cc
@@ -11,14 +11,24 @@
   bool is_8bit = true;
   for (const auto& view : pieces) {
     size += view.length();
-    is_8bit = is_8bit && view.Is8Bit();
+    if (is_8bit && !view.Is8Bit()) {
+      // Like StringBuilder, we check one-length 16bit strings.
+      is_8bit = view.length() == 1 && view[0] < 0x0100;
+    }
   }
 
   if (is_8bit) {
     base::span<LChar> buffer;
     auto impl = StringImpl::CreateUninitialized(size, buffer);
     for (const auto& view : pieces) {
-      buffer.take_first(view.length()).copy_from(view.Span8());
+      base::span<LChar> sub_buffer = buffer.take_first(view.length());
+      if (view.Is8Bit()) {
+        sub_buffer.copy_from(view.Span8());
+      } else {
+        DCHECK_EQ(sub_buffer.size(), 1u);
+        DCHECK_LT(view[0], 0x0100);
+        sub_buffer[0] = view[0];
+      }
     }
     return impl;
   }
diff --git a/third_party/blink/renderer/platform/wtf/text/strcat_test.cc b/third_party/blink/renderer/platform/wtf/text/strcat_test.cc
index 6eddef12..1fcb6f4 100644
--- a/third_party/blink/renderer/platform/wtf/text/strcat_test.cc
+++ b/third_party/blink/renderer/platform/wtf/text/strcat_test.cc
@@ -31,4 +31,12 @@
   EXPECT_FALSE(result.Is8Bit());
 }
 
+TEST(StrCatTest, MixedBitsResulting8it) {
+  const String src16(u"a");
+  ASSERT_FALSE(src16.Is8Bit());
+  String result = StrCat({"foo \"", src16, "\" bar."});
+  EXPECT_EQ("foo \"a\" bar.", result);
+  EXPECT_TRUE(result.Is8Bit());
+}
+
 }  // namespace WTF
diff --git a/third_party/blink/web_tests/editing/input/edit-context.html b/third_party/blink/web_tests/editing/input/edit-context.html
index eca41ba5..0dbf095 100644
--- a/third_party/blink/web_tests/editing/input/edit-context.html
+++ b/third_party/blink/web_tests/editing/input/edit-context.html
@@ -759,6 +759,83 @@
 
   test.remove();
 }, 'Testing UseCounter for textformatupdate event.');
+
+test(function(){
+  const kEditContextUpdateTextRangePrecedesOrOverlapsSelection = 5582;
+  const kEditContextUpdateTextRangePrecedesCompositionRange = 5583;
+  const kEditContextUpdateTextRangeOverlapsCompositionRange = 5584;
+  internals.clearUseCounter(document, kEditContextUpdateTextRangePrecedesOrOverlapsSelection);
+  internals.clearUseCounter(document, kEditContextUpdateTextRangePrecedesCompositionRange);
+  internals.clearUseCounter(document, kEditContextUpdateTextRangeOverlapsCompositionRange);
+
+  const text = "ABCD";
+  const editContext = new EditContext({text: text, selectionStart: 1, selectionEnd: 1});
+  const test = document.createElement("div");
+  test.textContent = text;
+  document.body.appendChild(test);
+  test.editContext = editContext;
+  test.focus();
+
+  assert_false(internals.isUseCounted(document, kEditContextUpdateTextRangePrecedesOrOverlapsSelection));
+
+  // UpdateText range is outside the selection range.
+  editContext.updateText(4, 4, "1");
+  assert_false(internals.isUseCounted(document, kEditContextUpdateTextRangePrecedesOrOverlapsSelection));
+
+  // UpdateText range is less than selection range.
+  editContext.updateText(0, 0, "2");
+  assert_true(internals.isUseCounted(document, kEditContextUpdateTextRangePrecedesOrOverlapsSelection));
+
+  editContext.updateSelection(1, 1);
+  textInputController.setComposition("foo");
+  assert_false(internals.isUseCounted(document, kEditContextUpdateTextRangePrecedesCompositionRange));
+  assert_false(internals.isUseCounted(document, kEditContextUpdateTextRangeOverlapsCompositionRange));
+
+  // UpdeText range is outside the composition range.
+  editContext.updateText(5, 5, "3");
+  assert_false(internals.isUseCounted(document, kEditContextUpdateTextRangePrecedesCompositionRange));
+  assert_false(internals.isUseCounted(document, kEditContextUpdateTextRangeOverlapsCompositionRange));
+
+  // UpdateText range is less than composition range but does not overlap.
+  editContext.updateText(0, 0, "4");
+  assert_true(internals.isUseCounted(document, kEditContextUpdateTextRangePrecedesCompositionRange));
+  assert_false(internals.isUseCounted(document, kEditContextUpdateTextRangeOverlapsCompositionRange));
+
+  // UpdateText range overlaps with composition range.
+  editContext.updateText(0, 3, "5");
+  assert_true(internals.isUseCounted(document, kEditContextUpdateTextRangeOverlapsCompositionRange));
+
+  test.remove();
+}, 'Testing UseCounter for updateText based on update range and selection/composition range.');
+
+test(function(){
+  const kEditContextUpdateSelectionDuringActiveComposition = 5585;
+  internals.clearUseCounter(document, kEditContextUpdateSelectionDuringActiveComposition);
+
+  const text = "ABCD";
+  const editContext = new EditContext({text: text, selectionStart: 0, selectionEnd: 0});
+  const test = document.createElement("div");
+  test.textContent = text;
+  document.body.appendChild(test);
+  test.editContext = editContext;
+  test.focus();
+
+  // Tracks when selection is updated to new value while a composition is active.
+  assert_false(internals.isUseCounted(document, kEditContextUpdateSelectionDuringActiveComposition));
+  editContext.updateSelection(1, 1);
+  assert_false(internals.isUseCounted(document, kEditContextUpdateSelectionDuringActiveComposition));
+
+  textInputController.setComposition("foo");
+  assert_equals(editContext.selectionStart, 4);
+  assert_equals(editContext.selectionEnd, 4);
+  editContext.updateSelection(4, 4);
+  assert_false(internals.isUseCounted(document, kEditContextUpdateSelectionDuringActiveComposition));
+
+  editContext.updateSelection(2, 2);
+  assert_true(internals.isUseCounted(document, kEditContextUpdateSelectionDuringActiveComposition));
+
+  test.remove();
+}, 'Testing UseCounter for updateSelection during an active composition.');
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/accname/name/comp_name_from_content.html b/third_party/blink/web_tests/external/wpt/accname/name/comp_name_from_content.html
index 6626eecb..cd108a1 100644
--- a/third_party/blink/web_tests/external/wpt/accname/name/comp_name_from_content.html
+++ b/third_party/blink/web_tests/external/wpt/accname/name/comp_name_from_content.html
@@ -24,6 +24,10 @@
 
     */
 
+    .alt-counter::before {
+      counter-set: cnt 5051;
+      content: "" / counter(cnt);
+    }
     .simple-before::before {
       content: " before "; /* [sic] leading and trailing space */
       margin:0 0.1em;
@@ -103,6 +107,12 @@
 <a href="#" data-expectedlabel="label" data-testname="link name from content" class="ex">label</a><br>
 <br>
 
+<h1>alt counter with ::before</h1>
+<button data-expectedlabel="5051 label" data-testname="button with alt counter on ::before" class="ex alt-counter">label</button><br>
+<h3 data-expectedlabel="5051 label" data-testname="heading with alt counter on ::before" class="ex alt-counter">label</h3>
+<a href="#" data-expectedlabel="5051 label" data-testname="link with alt counter on ::before" class="ex alt-counter">label</a><br>
+<br>
+
 <h1>simple with ::before</h1>
 <button data-expectedlabel="before label" data-testname="button name from content with ::before" class="ex simple-before">label</button><br>
 <h3 data-expectedlabel="before label" data-testname="heading name from content with ::before" class="ex simple-before">label</h3>
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/resources/basic-service-worker.js b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/resources/basic-service-worker.js
index 59d7d8b..749cd5f 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/resources/basic-service-worker.js
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/resources/basic-service-worker.js
@@ -1,4 +1,24 @@
-const swOption = new URL(location.href).searchParams.get('sw');
+let swOption = new URL(location.href).searchParams.get('sw');
+
+if (swOption === 'fetch-handler-navigation-preload') {
+  self.addEventListener('activate', event => {
+    if (self.registration.navigationPreload) {
+      event.waitUntil(self.registration.navigationPreload.enable());
+    }
+  });
+}
+
+if (swOption === 'race-fetch-handler' ||
+  swOption === 'race-fetch-handler-to-fallback' ||
+  swOption === 'race-fetch-handler-modify-url') {
+  swOption = swOption.substring('race-'.length);
+  self.addEventListener('install', event => {
+    event.addRoutes([{
+      condition: { urlPattern: { pathname: '/**/counting-executor.py' } },
+      source: 'race-network-and-fetch-handler'
+    }]);
+  });
+}
 
 const interceptedRequests = [];
 
@@ -21,14 +41,15 @@
     event.request.headers.forEach((value, key) => {
       headers[key] = value;
     });
-    interceptedRequests.push({
+    const interceptedRequest = {
       request: {
         url: event.request.url,
         headers: headers,
       },
       clientId: event.clientId,
       resultingClientId: event.resultingClientId
-    });
+    };
+    interceptedRequests.push(interceptedRequest);
 
     if (swOption === 'fetch-handler') {
       event.respondWith(fetch(event.request));
@@ -49,6 +70,26 @@
     } else if (swOption === 'fetch-handler-modify-referrer') {
       event.respondWith(fetch(event.request,
           {referrer: new URL('/intercepted', location.href).href}));
+    } else if (swOption === 'fetch-handler-navigation-preload') {
+      event.respondWith((async () => {
+        try {
+          if (event.preloadResponse === 'undefined') {
+            interceptedRequest.preloadResponse = 'undefined';
+            return fetch(event.request);
+          }
+          const response = await event.preloadResponse;
+          if (response) {
+            interceptedRequest.preloadResponse = 'resolved';
+            return response;
+          } else {
+            interceptedRequest.preloadResponse = 'resolved to undefined';
+            return fetch(event.request);
+          }
+        } catch(e) {
+          interceptedRequest.preloadResponse = 'rejected';
+          throw e;
+        }
+      })());
     } else {
       // Do nothing to fallback to the network.
     }
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/resources/executor.sub.html b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/resources/executor.sub.html
index 975a3e5..bb2d58d 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/resources/executor.sub.html
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/resources/executor.sub.html
@@ -33,6 +33,8 @@
   "referer": "{{header_or_default(Referer, NONEXISTENT)}}",
   "sec-fetch-dest": "{{header_or_default(Sec-Fetch-Dest, NONEXISTENT)}}",
   "sec-fetch-mode": "{{header_or_default(Sec-Fetch-Mode, NONEXISTENT)}}",
+  "service-worker-navigation-preload":
+      "{{header_or_default(Service-Worker-Navigation-Preload, NONEXISTENT)}}",
   // Convert to the raw string to avoid backslashes from being processed as
   // escape sequences.
   // TODO(crbug.com/404573971): Remove `header_or_default` to reflect
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/resources/utils.sub.js b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/resources/utils.sub.js
index adb15d4e..dd577c0 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/resources/utils.sub.js
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/resources/utils.sub.js
@@ -260,6 +260,13 @@
   }
 }
 
+function assert_served_by_navigation_preload(requestHeaders) {
+  assert_equals(
+    requestHeaders['service-worker-navigation-preload'],
+    'true',
+    'Service-Worker-Navigation-Preload');
+}
+
 // Use nvs_header query parameter to ask the wpt server
 // to populate No-Vary-Search response header.
 function addNoVarySearchHeaderUsingQueryParam(url, value){
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html
index 5b2a4d0..44937ea 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html
@@ -12,8 +12,12 @@
 <meta name="variant" content="?origin=same-site&sw=fetch-handler-to-fallback">
 <meta name="variant" content="?origin=same-site&sw=fetch-handler-modify-url">
 <meta name="variant" content="?origin=same-site&sw=fetch-handler-modify-referrer">
+<meta name="variant" content="?origin=same-site&sw=fetch-handler-navigation-preload">
 <meta name="variant" content="?origin=same-site&sw=no-fetch-handler">
 <meta name="variant" content="?origin=same-site&sw=no-controller">
+<meta name="variant" content="?origin=same-site&sw=race-fetch-handler">
+<meta name="variant" content="?origin=same-site&sw=race-fetch-handler-to-fallback">
+<meta name="variant" content="?origin=same-site&sw=race-fetch-handler-modify-url">
 
 <meta name="variant" content="?origin=same-site&sw=fetch-handler&clientId">
 <meta name="variant" content="?origin=same-site&sw=fetch-handler-to-fallback&clientId">
@@ -38,7 +42,19 @@
 // TODO(https://crbug.com/404573972): Rename "same-site" tests to
 // "same-origin", and add same-site cross-origin tests.
 const originOption = new URL(location.href).searchParams.get('origin');
-const swOption = new URL(location.href).searchParams.get('sw');
+const originalSwOption = new URL(location.href).searchParams.get('sw');
+
+// Used when checking the resulting behavior.
+// In the following race-network cases, race network requests work in parallel
+// with fetch handlers and the checked observed behavior are the same with
+// non-race-network cases.
+let swOption = originalSwOption;
+if (originalSwOption === 'race-fetch-handler') {
+  swOption = 'fetch-handler';
+}
+if (originalSwOption === 'race-fetch-handler-to-fallback') {
+  swOption = 'fetch-handler-to-fallback';
+}
 
 promise_test(async t => {
   const hostname = originOption === 'cross-site' ? '{{hosts[alt][www]}}'
@@ -46,7 +62,7 @@
   const win = await spawnWindow(t, { protocol: 'https', hostname: hostname });
   const nextUrl = win.getExecutorURL({ executor: 'counting-executor.py', protocol: 'https', page: 2 });
 
-  const swUrl = new URL('../../resources/basic-service-worker.js?sw=' + swOption, location.href).href;
+  const swUrl = new URL('../../resources/basic-service-worker.js?sw=' + originalSwOption, location.href).href;
 
   // Register a SW not controlling any pages below, just to confirm such
   // unrelated SWs in the same-origin doesn't affect the behavior.
@@ -120,8 +136,28 @@
       assert_intercept_prefetch(interceptedRequests[0], nextUrl);
     }
   } else if (originOption === 'same-site' &&
+      swOption === 'fetch-handler-navigation-preload') {
+    // Check the behavior of `FetchEvent.preloadResponse` for prefetching
+    // requests.
+    // Here we allow >1 intercepted requests to check `preloadResponse`
+    // behavior even if e.g. prefetched response isn't served and there is
+    // second intercepted request (=non-prefetch navigation request).
+    assert_greater_than_equal(interceptedRequests.length, 1);
+    // The first intercepted request is a prefetch request.
+    assert_intercept_prefetch(interceptedRequests[0], nextUrl);
+    assert_equals(interceptedRequests[0].preloadResponse, 'resolved',
+        'preloadResponse should be resolved');
+
+    assert_served_by_navigation_preload(headers);
+    assert_prefetched(headers, "Prefetched result should be served.");
+    assert_equals(requestCount.prefetch, 1,
+        'a prefetch request should be sent to the server.');
+    assert_equals(requestCount.nonPrefetch, 0,
+        'non-prefetch requests should not be sent to the server.');
+  } else if (originOption === 'same-site' &&
              (swOption === 'fetch-handler-modify-url' ||
-              swOption === 'fetch-handler-modify-referrer')) {
+              swOption === 'fetch-handler-modify-referrer' ||
+              swOption === 'race-fetch-handler-modify-url')) {
     // When the ServiceWorker modifies the prefetch request
     // (`fetch-handler-modify-*` cases below), still prefetch can work and be
     // served, but Sec-Purpose header is dropped
@@ -129,11 +165,17 @@
     assert_prefetched_without_sec_purpose(headers,
         "Prefetched result should be served without Sec-Purpose.");
     // `requestCount` checks the Sec-Purpose header so the prefetch request
-    // without Sec-Prefetch is counted as nonPrefetch here.
+    // without Sec-Purpose is counted as nonPrefetch here.
     assert_equals(requestCount.nonPrefetch, 1,
         'a prefetch request without Sec-Purpose should be sent to the server.');
-    assert_equals(requestCount.prefetch, 0,
-        'Other requests with Sec-Prefetch should not be sent to the server.');
+    if (swOption === 'race-fetch-handler-modify-url') {
+      // This racing network request is not used.
+      assert_equals(requestCount.prefetch, 1,
+        'Race network request should be sent to the server with Sec-Purpose.');
+    } else {
+      assert_equals(requestCount.prefetch, 0,
+        'Other requests with Sec-Purpose should not be sent to the server.');
+    }
 
     // Check the modified URL/referrer to check if the prefetched and
     // ServiceWorker-modified response is actually served.
@@ -167,5 +209,5 @@
     }
   }
 
-}, "Prefetch with ServiceWorker (" + swOption + ")");
+}, "Prefetch with ServiceWorker (" + originalSwOption + ")");
 </script>
diff --git a/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-navigation-preload-expected.txt b/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-navigation-preload-expected.txt
new file mode 100644
index 0000000..769cedd
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-navigation-preload-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] Prefetch with ServiceWorker (fetch-handler-navigation-preload)
+  assert_equals: preloadResponse should be resolved expected (string) "resolved" but got (undefined) undefined
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-expected.txt b/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-expected.txt
new file mode 100644
index 0000000..6139553d
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] Prefetch with ServiceWorker (race-fetch-handler)
+  assert_in_array: Prefetched result should be served. value undefined not in array ["prefetch", "prefetch;anonymous-client-ip"]
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-modify-url-expected.txt b/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-modify-url-expected.txt
new file mode 100644
index 0000000..c3d3dfa0
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-modify-url-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] Prefetch with ServiceWorker (race-fetch-handler-modify-url)
+  assert_equals: Race network request should be sent to the server with Sec-Purpose. expected 1 but got 0
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-to-fallback-expected.txt b/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-to-fallback-expected.txt
new file mode 100644
index 0000000..8412ef4
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-to-fallback-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] Prefetch with ServiceWorker (race-fetch-handler-to-fallback)
+  assert_in_array: Prefetched result should be served. value undefined not in array ["prefetch", "prefetch;anonymous-client-ip"]
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-navigation-preload-expected.txt b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-navigation-preload-expected.txt
new file mode 100644
index 0000000..813ec99
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-navigation-preload-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] Prefetch with ServiceWorker (fetch-handler-navigation-preload)
+  assert_in_array: Prefetch request should be intercepted. value undefined not in array ["prefetch", "prefetch;anonymous-client-ip"]
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-expected.txt b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-expected.txt
new file mode 100644
index 0000000..6139553d
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] Prefetch with ServiceWorker (race-fetch-handler)
+  assert_in_array: Prefetched result should be served. value undefined not in array ["prefetch", "prefetch;anonymous-client-ip"]
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-modify-url-expected.txt b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-modify-url-expected.txt
new file mode 100644
index 0000000..2df9cc8
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-modify-url-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] Prefetch with ServiceWorker (race-fetch-handler-modify-url)
+  assert_equals: a prefetch request without Sec-Purpose should be sent to the server. expected 1 but got 2
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-to-fallback-expected.txt b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-to-fallback-expected.txt
new file mode 100644
index 0000000..8412ef4
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=race-fetch-handler-to-fallback-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] Prefetch with ServiceWorker (race-fetch-handler-to-fallback)
+  assert_in_array: Prefetched result should be served. value undefined not in array ["prefetch", "prefetch;anonymous-client-ip"]
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-multimodal.https.window.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-multimodal.https.window.js
index 4685d50..40f2625 100644
--- a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-multimodal.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-multimodal.https.window.js
@@ -106,3 +106,18 @@
       [kImagePrompt, {type: 'audio', content: await audio_data.arrayBuffer()}]);
   assert_regexp_match(result, /<audio>/);
 }, 'Prompt with BufferSource - ArrayBuffer');
+
+promise_test(async t => {
+  await ensureLanguageModel();
+
+  const newImage = new Image();
+  newImage.src = kValidImagePath;
+  const session =
+      await LanguageModel.create({expectedInputs: [{type: 'image'}]});
+
+  // TODO(crbug.com/409615288): This should throw a TypeError according to the
+  // spec.
+  promise_rejects_dom(
+      t, 'SyntaxError',
+      session.prompt([kImagePrompt, {type: 'text', content: newImage}]));
+}, 'Prompt with type:"text" and image content should reject');
diff --git a/third_party/crossbench b/third_party/crossbench
index 85adce1..6fc73bc 160000
--- a/third_party/crossbench
+++ b/third_party/crossbench
@@ -1 +1 @@
-Subproject commit 85adce1424ed4df795f8c810fc1a8ee22bffe3fa
+Subproject commit 6fc73bc2e9fcd16c236c3728eddd1532aa9c76b9
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index 99d8217..0d8b60f 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit 99d8217d44d317d2b0f378eff8c33fd302310561
+Subproject commit 0d8b60f08590e970da0c2980ac3a0f5ec2929bc2
diff --git a/third_party/mediapipe/BUILD.gn b/third_party/mediapipe/BUILD.gn
index 4f69999..2e70c10 100644
--- a/third_party/mediapipe/BUILD.gn
+++ b/third_party/mediapipe/BUILD.gn
@@ -114,6 +114,7 @@
     "src/mediapipe/calculators/audio/time_series_framer_calculator.proto",
     "src/mediapipe/calculators/audio/two_tap_fir_filter_calculator.proto",
     "src/mediapipe/calculators/core/flow_limiter_calculator.proto",
+    "src/mediapipe/calculators/core/immediate_mux_calculator.proto",
     "src/mediapipe/calculators/core/split_vector_calculator.proto",
     "src/mediapipe/calculators/internal/callback_packet_calculator.proto",
     "src/mediapipe/calculators/tensor/bert_preprocessor_calculator.proto",
diff --git a/third_party/mediapipe/README.chromium b/third_party/mediapipe/README.chromium
index 8a73af4e..f8f8b2b 100644
--- a/third_party/mediapipe/README.chromium
+++ b/third_party/mediapipe/README.chromium
@@ -1,9 +1,9 @@
 Name: MediaPipe
 Short Name: mediapipe
 URL: https://github.com/google/mediapipe
-Version: ac3ef4ced4560f9e91e3dc4d1acce8a5775e4565
-Revision: 905eade19971467bca916bbb80da6936a994095f
-Date: 2025-02-14
+Version: 5910fe878cc2921b5cba4f6e6efcf6d2fc46263b
+Revision: 5910fe878cc2921b5cba4f6e6efcf6d2fc46263b
+Date: 2025-05-19
 License: Apache-2.0, X11-Lucent
 License File: LICENSE
 Security Critical: Yes
diff --git a/third_party/mediapipe/patches/remove-absl-flag-in-inference_calculator_utils.patch b/third_party/mediapipe/patches/remove-absl-flag-in-inference_calculator_utils.patch
index 396a3ce..a32283f4 100644
--- a/third_party/mediapipe/patches/remove-absl-flag-in-inference_calculator_utils.patch
+++ b/third_party/mediapipe/patches/remove-absl-flag-in-inference_calculator_utils.patch
@@ -11,13 +11,13 @@
  2 files changed, 1 insertion(+), 9 deletions(-)
 
 diff --git a/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_utils.cc b/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_utils.cc
-index 8d7761f6ab73e..cedd5216c84c6 100644
+index 52c6c8be2206c..d5ee27ba149de 100644
 --- a/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_utils.cc
 +++ b/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_utils.cc
 @@ -20,7 +20,6 @@
  #include <string>
  #include <vector>
-
+ 
 -#include "absl/flags/flag.h"
  #include "absl/log/absl_log.h"
  #include "absl/status/status.h"
@@ -25,7 +25,7 @@
 @@ -39,10 +38,6 @@
  #include "tensorflow/lite/portable_type_to_tflitetype.h"
  #include "tensorflow/lite/string_util.h"
-
+ 
 -ABSL_FLAG(int, xnnpack_default_num_threads, 0,
 -          "Default number of xnnpack threads to use. If unset, determines a "
 -          "good default number based on the platform.");
@@ -35,7 +35,7 @@
  #endif  // !__EMSCRIPTEN__ || __EMSCRIPTEN_PTHREADS__
 @@ -51,7 +46,7 @@ namespace mediapipe {
  namespace {
-
+ 
  int GetXnnpackDefaultNumThreads() {
 -  int default_from_flag = absl::GetFlag(FLAGS_xnnpack_default_num_threads);
 +  int default_from_flag = 0;
@@ -43,26 +43,23 @@
      return default_from_flag;
    }
 diff --git a/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_utils.h b/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_utils.h
-index 917700d8e3a11..aa045dd3d037e 100644
+index 93454ed9f7d94..0eff2b854801d 100644
 --- a/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_utils.h
 +++ b/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_utils.h
-@@ -18,7 +18,6 @@
- #include <cstddef>
+@@ -19,7 +19,6 @@
  #include <cstdint>
-
+ #include <string>
+ 
 -#include "absl/flags/declare.h"
  #include "absl/status/status.h"
  #include "absl/status/statusor.h"
  #include "mediapipe/calculators/tensor/inference_calculator.pb.h"
-@@ -28,8 +27,6 @@
+@@ -29,8 +28,6 @@
  #include "tensorflow/lite/interpreter.h"
  #include "tensorflow/lite/util.h"
-
+ 
 -ABSL_DECLARE_FLAG(int, xnnpack_default_num_threads);
 -
  namespace mediapipe {
-
+ 
  // Returns number of threads to configure XNNPACK delegate with.
---
-2.48.0.rc2.279.g1de40edade-goog
-
diff --git a/third_party/mediapipe/patches/type-map-fix-unused-variable-warning.patch b/third_party/mediapipe/patches/type-map-fix-unused-variable-warning.patch
deleted file mode 100644
index 516ac3f..0000000
--- a/third_party/mediapipe/patches/type-map-fix-unused-variable-warning.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From 2c3b206fd7bde1b86c65c440008afd382f040d3f Mon Sep 17 00:00:00 2001
-From: Piotr Bialecki <bialpio@chromium.org>
-Date: Fri, 14 Feb 2025 14:52:58 -0800
-Subject: [PATCH] Fix unused variable compiler warning in type_map.h
-
----
- third_party/mediapipe/src/mediapipe/framework/type_map.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/third_party/mediapipe/src/mediapipe/framework/type_map.h b/third_party/mediapipe/src/mediapipe/framework/type_map.h
-index f03f48ce7851c..123668766bd98 100644
---- a/third_party/mediapipe/src/mediapipe/framework/type_map.h
-+++ b/third_party/mediapipe/src/mediapipe/framework/type_map.h
-@@ -148,7 +148,7 @@ class StaticMap {
-    public:
-     ValueInserter(const char* file_and_line, const KeyType& key,
-                   const MediaPipeTypeData& value) {
--      MapName* static_map = GetMap();
-+      StaticMap* static_map = GetMap();
-       absl::MutexLock l(&(static_map->map_lock_));
- 
-       typename MapType::iterator it = static_map->internal_map_.find(key);
--- 
-2.47.1.windows.2
-
diff --git a/third_party/mediapipe/src/WORKSPACE b/third_party/mediapipe/src/WORKSPACE
index 6d25561..711e16b 100644
--- a/third_party/mediapipe/src/WORKSPACE
+++ b/third_party/mediapipe/src/WORKSPACE
@@ -52,7 +52,20 @@
     url = "https://github.com/bazelbuild/rules_android_ndk/archive/d5c9d46a471e8fcd80e7ec5521b78bb2df48f4e0.zip",
 )
 
-load("@rules_android_ndk//:rules.bzl", "android_ndk_repository")
+http_archive(
+    name = "rules_shell",
+    sha256 = "bc61ef94facc78e20a645726f64756e5e285a045037c7a61f65af2941f4c25e1",
+    strip_prefix = "rules_shell-0.4.1",
+    url = "https://github.com/bazelbuild/rules_shell/releases/download/v0.4.1/rules_shell-v0.4.1.tar.gz",
+)
+
+load("@rules_shell//shell:repositories.bzl", "rules_shell_dependencies", "rules_shell_toolchains")
+
+rules_shell_dependencies()
+
+rules_shell_toolchains()
+
+load("@rules_android_ndk//:rules.bzl", "android_ndk_repository")  # @unused
 
 http_archive(
     name = "build_bazel_rules_apple",
@@ -228,13 +241,13 @@
     ],
 )
 
-# XNNPACK on 2024-11-18
+# XNNPACK from 2025-04-02
 http_archive(
     name = "XNNPACK",
     # `curl -L <url> | shasum -a 256`
-    sha256 = "af30fe2b301330a7e19cd422acf22991de3c1f5d91dda58e9ee67544d608fa51",
-    strip_prefix = "XNNPACK-dc1549a7141c7a9496ae160bb27b8700f0f6e1f1",
-    url = "https://github.com/google/XNNPACK/archive/dc1549a7141c7a9496ae160bb27b8700f0f6e1f1.zip",
+    sha256 = "72549a5af09ee22204904fc93d35d2a19351e32a46f26c4838dda005824e3576",
+    strip_prefix = "XNNPACK-5ff876e4f88f4bec7a3ec853c366a33c8f797fb5",
+    url = "https://github.com/google/XNNPACK/archive/5ff876e4f88f4bec7a3ec853c366a33c8f797fb5.zip",
 )
 
 # 2020-07-09
@@ -265,13 +278,13 @@
     ],
 )
 
-# KleidiAI is needed to get the best possible performance out of XNNPack
+# KleidiAI is needed to get the best possible performance out of XNNPack, from 2025-04-02
 http_archive(
     name = "KleidiAI",
-    sha256 = "ad37707084a6d4ff41be10cbe8540c75bea057ba79d0de6c367c1bfac6ba0852",
-    strip_prefix = "kleidiai-40a926833857fb64786e02f97703e42b1537cb57",
+    sha256 = "ca8b8ee0c3dd2284c1eae3ac07f7064ce92317ac7c3cfcd1d511662e0594cdb8",
+    strip_prefix = "kleidiai-fb4caf0937a45002861cc12788b6018bfb89ae58",
     urls = [
-        "https://gitlab.arm.com/kleidi/kleidiai/-/archive/40a926833857fb64786e02f97703e42b1537cb57/kleidiai-40a926833857fb64786e02f97703e42b1537cb57.zip"
+        "https://github.com/ARM-software/kleidiai/archive/fb4caf0937a45002861cc12788b6018bfb89ae58.zip",
     ],
 )
 
@@ -284,6 +297,15 @@
     ],
 )
 
+# pthreadpool is a dependency of XNNPACK, from 2025-04-02
+http_archive(
+    name = "pthreadpool",
+    # `curl -L <url> | shasum -a 256`
+    sha256 = "745e56516d6a58d183eb33d9017732d87cff43ce9f78908906f9faa52633e421",
+    strip_prefix = "pthreadpool-b92447772365661680f486e39a91dfe6675adafc",
+    urls = ["https://github.com/google/pthreadpool/archive/b92447772365661680f486e39a91dfe6675adafc.zip"],
+)
+
 # TF on 2024-09-24
 _TENSORFLOW_GIT_COMMIT = "5329ec8dd396487982ef3e743f98c0195af39a6b"
 
@@ -386,14 +408,6 @@
 
 bazel_features_deps()
 
-# TODO: This is an are indirect dependency. We should factor it out.
-http_archive(
-    name = "pthreadpool",
-    sha256 = "a4cf06de57bfdf8d7b537c61f1c3071bce74e57524fe053e0bbd2332feca7f95",
-    strip_prefix = "pthreadpool-4fe0e1e183925bf8cfa6aae24237e724a96479b8",
-    urls = ["https://github.com/Maratyszcza/pthreadpool/archive/4fe0e1e183925bf8cfa6aae24237e724a96479b8.zip"],
-)
-
 load(
     "@build_bazel_rules_apple//apple:repositories.bzl",
     "apple_rules_dependencies",
@@ -469,9 +483,9 @@
     # TODO: Fix this in AudioTools directly
     patches = ["@//third_party:com_google_audio_tools_fixes.diff"],
     repo_mapping = {"@com_github_glog_glog": "@com_github_glog_glog_no_gflags"},
-    sha256 = "0856be6971c636d62c9eaaf8fca3c8aa85b9be55ac5cf124d05d1dfe4a77eaf1",
-    strip_prefix = "multichannel-audio-tools-9aebbcabc1b5ed3827755f44339d8a0d572e16ec",
-    urls = ["https://github.com/google/multichannel-audio-tools/archive/9aebbcabc1b5ed3827755f44339d8a0d572e16ec.zip"],
+    sha256 = "7d7227cc6bb1f8917a9c9013e8f3578ec681c49e20fe2fc38ba90965394de60c",
+    strip_prefix = "multichannel-audio-tools-bbf15de4b7cd825d650296d21917afc07e8fe18b",
+    urls = ["https://github.com/google/multichannel-audio-tools/archive/bbf15de4b7cd825d650296d21917afc07e8fe18b.tar.gz"],
 )
 
 http_archive(
@@ -817,14 +831,14 @@
 
 http_archive(
     name = "skia",
-    sha256 = "038d4a21f9c72d71ab49e3a7d7677b39585329465d093a4260b6c73d2f3984d6",
-    strip_prefix = "skia-ac75382cb971d2f5465b4608a74561ecb68599c5",
-    urls = ["https://github.com/google/skia/archive/ac75382cb971d2f5465b4608a74561ecb68599c5.zip"],
+    sha256 = "2fe28173428f8eebf2aa8a665bad32136086cc065f50c7154678a96250d1cde1",
+    strip_prefix = "skia-226ae9d866748a2e68b6dbf114b37129c380a298",
+    urls = ["https://github.com/google/skia/archive/226ae9d866748a2e68b6dbf114b37129c380a298.zip"],
 )
 
 http_archive(
     name = "skia_user_config",
-    sha256 = "038d4a21f9c72d71ab49e3a7d7677b39585329465d093a4260b6c73d2f3984d6",
-    strip_prefix = "skia-ac75382cb971d2f5465b4608a74561ecb68599c5/include/config",
-    urls = ["https://github.com/google/skia/archive/ac75382cb971d2f5465b4608a74561ecb68599c5.zip"],
+    sha256 = "2fe28173428f8eebf2aa8a665bad32136086cc065f50c7154678a96250d1cde1",
+    strip_prefix = "skia-226ae9d866748a2e68b6dbf114b37129c380a298/include/config",
+    urls = ["https://github.com/google/skia/archive/226ae9d866748a2e68b6dbf114b37129c380a298.zip"],
 )
diff --git a/third_party/mediapipe/src/mediapipe/calculators/audio/spectrogram_calculator.cc b/third_party/mediapipe/src/mediapipe/calculators/audio/spectrogram_calculator.cc
index 1a7c594..04e884af 100644
--- a/third_party/mediapipe/src/mediapipe/calculators/audio/spectrogram_calculator.cc
+++ b/third_party/mediapipe/src/mediapipe/calculators/audio/spectrogram_calculator.cc
@@ -69,6 +69,10 @@
 // rounded to the nearest integer number of samples. Consequently, all output
 // frames will be based on the same number of input samples, and each
 // analysis frame will advance from its predecessor by the same time step.
+//
+// If output_layout is set to SPECTROGRAM_CHANNELS_IN_ROWS, the output will be a
+// matrix with each row being one channel of the spectrogram regardless of the
+// number of channels that need to be output.
 class SpectrogramCalculator : public CalculatorBase {
  public:
   static absl::Status GetContract(CalculatorContract* cc) {
@@ -94,7 +98,9 @@
 
     SpectrogramCalculatorOptions spectrogram_options =
         cc->Options<SpectrogramCalculatorOptions>();
-    if (!spectrogram_options.allow_multichannel_input()) {
+    if (!spectrogram_options.allow_multichannel_input() ||
+        spectrogram_options.output_layout() ==
+            SpectrogramCalculatorOptions::SPECTROGRAM_CHANNELS_IN_ROWS) {
       if (spectrogram_options.output_type() ==
           SpectrogramCalculatorOptions::COMPLEX) {
         cc->Outputs().Index(0).Set<Eigen::MatrixXcf>(
@@ -158,6 +164,12 @@
                  Timestamp::kTimestampUnitsPerSecond / input_sample_rate_);
   }
 
+  TimestampDiff TimeStampDurationForSamples(int64_t num_samples) {
+    return TimestampDiff(
+        round(num_samples * Timestamp::kTimestampUnitsPerSecond /
+              input_sample_rate_));
+  }
+
   int frame_step_samples() const {
     return frame_duration_samples_ - frame_overlap_samples_;
   }
@@ -208,6 +220,8 @@
   float input_scale_;
   // Fixed scale factor applied to output values (regardless of type).
   double output_scale_;
+  // Specifies the output layout.
+  SpectrogramCalculatorOptions::OutputLayout output_layout_;
 
   static const float kLnSquaredMagnitudeToDb;
 };
@@ -288,6 +302,7 @@
   pad_final_packet_ = spectrogram_options.pad_final_packet();
   output_type_ = spectrogram_options.output_type();
   allow_multichannel_input_ = spectrogram_options.allow_multichannel_input();
+  output_layout_ = spectrogram_options.output_layout();
 
   input_scale_ = spectrogram_options.input_scale();
   output_scale_ = spectrogram_options.output_scale();
@@ -347,7 +362,9 @@
   // output_header.num_samples.
   output_header->clear_packet_rate();
   output_header->clear_num_samples();
-  if (!spectrogram_options.allow_multichannel_input()) {
+  if (!spectrogram_options.allow_multichannel_input() ||
+      output_layout_ ==
+          SpectrogramCalculatorOptions::SPECTROGRAM_CHANNELS_IN_ROWS) {
     cc->Outputs().Index(0).SetHeader(Adopt(output_header.release()));
   } else {
     std::unique_ptr<MultiStreamTimeSeriesHeader> multichannel_output_header(
@@ -444,13 +461,31 @@
   if (!spectrogram_matrices->empty()) {
     RET_CHECK_EQ(spectrogram_matrices->size(), input_stream.rows())
         << "Inconsistent number of spectrogram channels.";
-    if (allow_multichannel_input_) {
-      cc->Outputs().Index(0).Add(spectrogram_matrices.release(),
-                                 CurrentOutputTimestamp(cc));
+
+    if (output_layout_ ==
+        SpectrogramCalculatorOptions::SPECTROGRAM_CHANNELS_IN_ROWS) {
+      int num_frames = spectrogram_matrices->at(0).cols();
+      int num_parameters = spectrogram_matrices->at(0).rows();
+      for (int i = 0; i < num_frames; ++i) {
+        std::unique_ptr<OutputMatrixType> output_matrix(
+            new OutputMatrixType(num_input_channels_, num_parameters));
+        for (int j = 0; j < num_input_channels_; ++j) {
+          output_matrix->row(j) = spectrogram_matrices->at(j).col(i);
+        }
+        auto timestamp = CurrentOutputTimestamp(cc) +
+                         TimeStampDurationForSamples(i * frame_step_samples());
+
+        cc->Outputs().Index(0).Add(output_matrix.release(), timestamp);
+      }
     } else {
-      cc->Outputs().Index(0).Add(
-          new OutputMatrixType(spectrogram_matrices->at(0)),
-          CurrentOutputTimestamp(cc));
+      if (allow_multichannel_input_) {
+        cc->Outputs().Index(0).Add(spectrogram_matrices.release(),
+                                   CurrentOutputTimestamp(cc));
+      } else {
+        cc->Outputs().Index(0).Add(
+            new OutputMatrixType(spectrogram_matrices->at(0)),
+            CurrentOutputTimestamp(cc));
+      }
     }
     cumulative_completed_frames_ += output_vectors.size();
     last_completed_frames_ = output_vectors.size();
diff --git a/third_party/mediapipe/src/mediapipe/calculators/audio/spectrogram_calculator.proto b/third_party/mediapipe/src/mediapipe/calculators/audio/spectrogram_calculator.proto
index 56abee36..9625f3de 100644
--- a/third_party/mediapipe/src/mediapipe/calculators/audio/spectrogram_calculator.proto
+++ b/third_party/mediapipe/src/mediapipe/calculators/audio/spectrogram_calculator.proto
@@ -104,4 +104,18 @@
     RESET = 1;
   }
   optional SampleBufferMode sample_buffer_mode = 11 [default = NONE];
+
+  enum OutputLayout {
+    OUTPUT_LAYOUT_UNSPECIFIED = 0;
+    // Output is a matrix or a vector of matrices. Within the matrix, each
+    // column represents the spectrogram for a frame. If the input has multiple
+    // channels, the output will be a vector of matrices, each matrix
+    // corresponding to a channel.
+    SPECTROGRAM_FRAMES_IN_COLUMNS = 1;
+    // Output is a one matrix per packet. Within the matrix, each row represents
+    // a channel.
+    SPECTROGRAM_CHANNELS_IN_ROWS = 2;
+  }
+  optional OutputLayout output_layout = 13
+      [default = SPECTROGRAM_FRAMES_IN_COLUMNS];
 }
diff --git a/third_party/mediapipe/src/mediapipe/calculators/core/BUILD b/third_party/mediapipe/src/mediapipe/calculators/core/BUILD
index 072d098..ec5a126 100644
--- a/third_party/mediapipe/src/mediapipe/calculators/core/BUILD
+++ b/third_party/mediapipe/src/mediapipe/calculators/core/BUILD
@@ -680,14 +680,20 @@
     alwayslink = 1,
 )
 
+mediapipe_proto_library(
+    name = "immediate_mux_calculator_proto",
+    srcs = ["immediate_mux_calculator.proto"],
+)
+
 cc_library(
     name = "immediate_mux_calculator",
     srcs = ["immediate_mux_calculator.cc"],
     deps = [
+        ":immediate_mux_calculator_cc_proto",
         "//mediapipe/framework:calculator_framework",
         "//mediapipe/framework/port:ret_check",
-        "//mediapipe/framework/port:status",
         "@com_google_absl//absl/log:absl_log",
+        "@com_google_absl//absl/status",
     ],
     alwayslink = 1,
 )
@@ -812,16 +818,17 @@
         ":round_robin_demux_calculator",
         "//mediapipe/framework:calculator_cc_proto",
         "//mediapipe/framework:calculator_framework",
+        "//mediapipe/framework:executor",
         "//mediapipe/framework:test_calculators",
         "//mediapipe/framework/port:gtest_main",
-        "//mediapipe/framework/port:integral_types",
         "//mediapipe/framework/port:logging",
-        "//mediapipe/framework/port:status",
         "//mediapipe/framework/port:threadpool",
         "//mediapipe/framework/stream_handler:immediate_input_stream_handler",
         "//mediapipe/framework/tool:sink",
+        "@com_google_absl//absl/status",
         "@com_google_absl//absl/strings",
         "@com_google_absl//absl/synchronization",
+        "@com_google_protobuf//:protobuf",
     ],
 )
 
@@ -960,6 +967,7 @@
         "//mediapipe/framework/formats:classification_cc_proto",
         "//mediapipe/framework/formats:detection_cc_proto",
         "//mediapipe/framework/formats:image",
+        "//mediapipe/framework/formats:image_frame",
         "//mediapipe/framework/formats:landmark_cc_proto",
         "//mediapipe/framework/formats:matrix",
         "//mediapipe/framework/formats:rect_cc_proto",
@@ -986,11 +994,11 @@
         ":split_vector_calculator_cc_proto",
         "//mediapipe/framework:calculator_framework",
         "//mediapipe/framework:calculator_runner",
-        "//mediapipe/framework/deps:file_path",
+        "//mediapipe/framework/formats:image_frame",
         "//mediapipe/framework/port:gtest_main",
-        "//mediapipe/framework/port:integral_types",
         "//mediapipe/framework/port:parse_text_proto",
         "//mediapipe/framework/tool:validate_type",
+        "@com_google_absl//absl/memory",
         "@org_tensorflow//tensorflow/lite:framework",
         "@org_tensorflow//tensorflow/lite/kernels:builtin_ops",
     ],
diff --git a/third_party/mediapipe/src/mediapipe/calculators/core/constant_side_packet_calculator.cc b/third_party/mediapipe/src/mediapipe/calculators/core/constant_side_packet_calculator.cc
index 4bc1e30..e2924e0 100644
--- a/third_party/mediapipe/src/mediapipe/calculators/core/constant_side_packet_calculator.cc
+++ b/third_party/mediapipe/src/mediapipe/calculators/core/constant_side_packet_calculator.cc
@@ -96,6 +96,8 @@
         packet.Set<TimeSeriesHeader>();
       } else if (packet_options.has_int64_value()) {
         packet.Set<int64_t>();
+      } else if (packet_options.has_float_vector_value()) {
+        packet.Set<std::vector<float>>();
       } else {
         return absl::InvalidArgumentError(
             "None of supported values were specified in options.");
@@ -145,6 +147,14 @@
             packet_options.time_series_header_value()));
       } else if (packet_options.has_int64_value()) {
         packet.Set(MakePacket<int64_t>(packet_options.int64_value()));
+      } else if (packet_options.has_float_vector_value()) {
+        std::vector<float> float_vector_values;
+        for (const auto& value :
+             packet_options.float_vector_value().float_value()) {
+          float_vector_values.push_back(value);
+        }
+        packet.Set(
+            MakePacket<std::vector<float>>(std::move(float_vector_values)));
       } else {
         return absl::InvalidArgumentError(
             "None of supported values were specified in options.");
diff --git a/third_party/mediapipe/src/mediapipe/calculators/core/constant_side_packet_calculator.proto b/third_party/mediapipe/src/mediapipe/calculators/core/constant_side_packet_calculator.proto
index dea91be0..44b38064 100644
--- a/third_party/mediapipe/src/mediapipe/calculators/core/constant_side_packet_calculator.proto
+++ b/third_party/mediapipe/src/mediapipe/calculators/core/constant_side_packet_calculator.proto
@@ -30,6 +30,11 @@
   message StringVector {
     repeated string string_value = 1;
   }
+
+  message FloatVector {
+    repeated float float_value = 1 [packed = true];
+  }
+
   message ConstantSidePacket {
     oneof value {
       int32 int_value = 1;
@@ -44,6 +49,7 @@
       TimeSeriesHeader time_series_header_value = 10;
       MatrixData matrix_data_value = 12;
       StringVector string_vector_value = 13;
+      FloatVector float_vector_value = 14;
     }
   }
 
diff --git a/third_party/mediapipe/src/mediapipe/calculators/core/immediate_mux_calculator.cc b/third_party/mediapipe/src/mediapipe/calculators/core/immediate_mux_calculator.cc
index 05de05e4..fa1791cf 100644
--- a/third_party/mediapipe/src/mediapipe/calculators/core/immediate_mux_calculator.cc
+++ b/third_party/mediapipe/src/mediapipe/calculators/core/immediate_mux_calculator.cc
@@ -12,44 +12,55 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <algorithm>
+
 #include "absl/log/absl_log.h"
+#include "absl/status/status.h"
+#include "mediapipe/calculators/core/immediate_mux_calculator.pb.h"
 #include "mediapipe/framework/calculator_framework.h"
 #include "mediapipe/framework/port/ret_check.h"
-#include "mediapipe/framework/port/status.h"
 
 namespace mediapipe {
 
-// This Calculator multiplexes several input streams into a single
-// output stream, dropping input packets with timestamps older than the
-// last output packet.  In case two packets arrive with the same timestamp,
-// the packet with the lower stream index will be output and the rest will
-// be dropped.
+// This Calculator multiplexes several input streams into a single output
+// stream, dropping input packets with timestamps older than the last output
+// packet. In case two packets arrive with the same timestamp, the packet with
+// the lower stream index will be output and the rest will be dropped.
 //
-// This Calculator optionally produces a finish inidicator as its second
-// output stream.  One indicator packet is produced for each input packet
-// received.
+// This Calculator optionally produces a finish indicator as its second output
+// stream.  One indicator packet is produced for each input packet received.
 //
 // This Calculator can be used with an ImmediateInputStreamHandler or with the
 // default ISH.
 //
-// This Calculator is designed to work with a Demux calculator such as
-// the RoundRobinDemuxCalculator.  Therefore, packets from different
-// input streams are normally not expected to have the same timestamp.
+// This Calculator is designed to work with a Demux calculator such as the
+// RoundRobinDemuxCalculator.  Therefore, packets from different input streams
+// are normally not expected to have the same timestamp.
 //
 // NOTE: this calculator can drop packets non-deterministically, depending on
 // how fast the input streams are fed. In most cases, MuxCalculator should be
 // preferred. In particular, dropping packets can interfere with rate limiting
 // mechanisms.
+//
+// The user can set the `process_timestamp_bounds` option to true to maintain a
+// more stable behavior with timestamp bound updates, that the calculator will
+// propagate the timestamp bound update inputs downstream and increase the
+// input timestamp bound correspondingly, and drop later packets with smaller
+// input timestamps.
 class ImmediateMuxCalculator : public CalculatorBase {
  public:
-  // This calculator combines any set of input streams into a single
-  // output stream.  All input stream types must match the output stream type.
+  // This calculator combines any set of input streams into a single output
+  // stream.  All input stream types must match the output stream type.
   static absl::Status GetContract(CalculatorContract* cc);
 
-  // Passes any input packet to the output stream immediately, unless the
-  // packet timestamp is lower than a previously passed packet.
+  // Passes any input packet to the output stream immediately, unless the packet
+  // timestamp is lower than a previously passed packet.
   absl::Status Process(CalculatorContext* cc) override;
   absl::Status Open(CalculatorContext* cc) override;
+
+ private:
+  bool process_timestamp_bounds_ = false;
+  Timestamp current_timestamp_bound_ = Timestamp::PreStream();
 };
 REGISTER_CALCULATOR(ImmediateMuxCalculator);
 
@@ -63,32 +74,66 @@
   for (int i = 0; i < cc->Inputs().NumEntries(); ++i) {
     cc->Inputs().Index(i).SetSameAs(&cc->Outputs().Index(0));
   }
+  const auto& options = cc->Options<mediapipe::ImmediateMuxCalculatorOptions>();
+  if (options.process_timestamp_bounds()) {
+    cc->SetProcessTimestampBounds(true);
+  }
   return absl::OkStatus();
 }
 
 absl::Status ImmediateMuxCalculator::Open(CalculatorContext* cc) {
-  cc->SetOffset(TimestampDiff(0));
+  const auto& options = cc->Options<mediapipe::ImmediateMuxCalculatorOptions>();
+  process_timestamp_bounds_ = options.process_timestamp_bounds();
+  if (!process_timestamp_bounds_) {
+    cc->SetOffset(TimestampDiff(0));
+  }
   return absl::OkStatus();
 }
 
 absl::Status ImmediateMuxCalculator::Process(CalculatorContext* cc) {
-  // Pass along the first packet, unless it has been superseded.
+  bool is_timestamp_bound_update = true;
+  // Pass along the first packet if it's timestamp exceeds the current timestamp
+  // bound. Otherwise, drop the packet.
   for (int i = 0; i < cc->Inputs().NumEntries(); ++i) {
     const Packet& packet = cc->Inputs().Index(i).Value();
     if (!packet.IsEmpty()) {
-      if (packet.Timestamp() >= cc->Outputs().Index(0).NextTimestampBound()) {
+      is_timestamp_bound_update = false;
+      if (packet.Timestamp() >= current_timestamp_bound_) {
         cc->Outputs().Index(0).AddPacket(packet);
+        current_timestamp_bound_ = packet.Timestamp().NextAllowedInStream();
       } else {
         ABSL_LOG_FIRST_N(WARNING, 5)
             << "Dropping a packet with timestamp " << packet.Timestamp();
       }
-      if (cc->Outputs().NumEntries() >= 2) {
+      if (cc->Outputs().NumEntries() >= 2 &&
+          !cc->Outputs().Index(1).IsClosed()) {
         Timestamp output_timestamp = std::max(
             cc->InputTimestamp(), cc->Outputs().Index(1).NextTimestampBound());
         cc->Outputs().Index(1).Add(new bool(true), output_timestamp);
       }
     }
   }
+
+  // Optionally propagate timestamp bound updates if enabled.
+  // If the calculator is configured with ImmediateInputStreamHandler, and has
+  // more than one input streams, it is possible that a later packet has a
+  // timestamp bound update call with timestamp smaller than
+  // current_timestamp_bound_. In this case, the update should not occur.
+  if (process_timestamp_bounds_ && is_timestamp_bound_update &&
+      cc->InputTimestamp() >= current_timestamp_bound_) {
+    if (!cc->InputTimestamp().HasNextAllowedInStream()) {
+      // The calculator receives a close input stream call.
+      // Close all output streams.
+      for (int i = 0; i < cc->Outputs().NumEntries(); ++i) {
+        cc->Outputs().Index(i).Close();
+      }
+    } else {
+      current_timestamp_bound_ = cc->InputTimestamp().NextAllowedInStream();
+      for (int i = 0; i < cc->Outputs().NumEntries(); ++i) {
+        cc->Outputs().Index(i).SetNextTimestampBound(current_timestamp_bound_);
+      }
+    }
+  }
   return absl::OkStatus();
 }
 
diff --git a/third_party/mediapipe/src/mediapipe/calculators/core/immediate_mux_calculator.proto b/third_party/mediapipe/src/mediapipe/calculators/core/immediate_mux_calculator.proto
new file mode 100644
index 0000000..0cf12f1
--- /dev/null
+++ b/third_party/mediapipe/src/mediapipe/calculators/core/immediate_mux_calculator.proto
@@ -0,0 +1,36 @@
+// Copyright 2025 The MediaPipe Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package mediapipe;
+
+message ImmediateMuxCalculatorOptions {
+  // Whether to process timestamp bound.
+  //
+  // process_timestamp_bounds = false maintains legacy behavior, where the
+  // calculator will not process timestamp bounds updates for one of the input
+  // streams if input streams > 1 and ImmediateInputStreamHandler is used. e.g.
+  // if input stream 0 receives timestamp bound update to 100, and then input
+  // stream 1 receives a real packet at 90, the packet at 90 will still be sent
+  // out. However, it's not recommended to update timestamp bounds in this case,
+  // since it can lead to undeterministic behavior.
+  //
+  // With process_timestamp_bounds = true, the calculator will maintain a more
+  // stable behavior with timestamp bound updates: It will propagate the
+  // timestamp bound update inputs downstream and increase the input timestamp
+  // bound correspondingly, and drop later packets with smaller input
+  // timestamps.
+  optional bool process_timestamp_bounds = 1;
+}
diff --git a/third_party/mediapipe/src/mediapipe/calculators/core/packet_resampler_calculator.cc b/third_party/mediapipe/src/mediapipe/calculators/core/packet_resampler_calculator.cc
index 06bfa0b..dd604a04 100644
--- a/third_party/mediapipe/src/mediapipe/calculators/core/packet_resampler_calculator.cc
+++ b/third_party/mediapipe/src/mediapipe/calculators/core/packet_resampler_calculator.cc
@@ -182,6 +182,13 @@
       return absl::OkStatus();
     }
   }
+  if (!header_sent_ && cc->Outputs().UsesTags() &&
+      cc->Outputs().HasTag(kVideoHeaderTag)) {
+    cc->Outputs()
+        .Tag(kVideoHeaderTag)
+        .Add(new VideoHeader(video_header_), Timestamp::PreStream());
+    header_sent_ = true;
+  }
 
   MP_RETURN_IF_ERROR(strategy_->Process(cc));
 
@@ -671,12 +678,6 @@
           base_timestamp_ +
           TimestampDiffFromSeconds(first_index / calculator_->frame_rate_);
     }
-    if (cc->Outputs().UsesTags() && cc->Outputs().HasTag(kVideoHeaderTag)) {
-      cc->Outputs()
-          .Tag(kVideoHeaderTag)
-          .Add(new VideoHeader(calculator_->video_header_),
-               Timestamp::PreStream());
-    }
   }
   const Timestamp received_timestamp = cc->InputTimestamp();
   const int64_t received_timestamp_idx =
diff --git a/third_party/mediapipe/src/mediapipe/calculators/core/packet_resampler_calculator.h b/third_party/mediapipe/src/mediapipe/calculators/core/packet_resampler_calculator.h
index 5635d1f..680f45b 100644
--- a/third_party/mediapipe/src/mediapipe/calculators/core/packet_resampler_calculator.h
+++ b/third_party/mediapipe/src/mediapipe/calculators/core/packet_resampler_calculator.h
@@ -193,6 +193,8 @@
   // between start_time and end_time.
   bool round_limits_;
 
+  bool header_sent_ = false;
+
   // Allow strategies access to all internal calculator state.
   //
   // The calculator and strategies are intimiately tied together so this should
diff --git a/third_party/mediapipe/src/mediapipe/calculators/core/split_vector_calculator.cc b/third_party/mediapipe/src/mediapipe/calculators/core/split_vector_calculator.cc
index 67fc38c..ee5186f 100644
--- a/third_party/mediapipe/src/mediapipe/calculators/core/split_vector_calculator.cc
+++ b/third_party/mediapipe/src/mediapipe/calculators/core/split_vector_calculator.cc
@@ -14,11 +14,14 @@
 
 #include "mediapipe/calculators/core/split_vector_calculator.h"
 
-#include <vector>
+#include <array>
+#include <cstdint>
 
+#include "mediapipe/framework/calculator_framework.h"
 #include "mediapipe/framework/formats/classification.pb.h"
 #include "mediapipe/framework/formats/detection.pb.h"
 #include "mediapipe/framework/formats/image.h"
+#include "mediapipe/framework/formats/image_frame.h"
 #include "mediapipe/framework/formats/landmark.pb.h"
 #include "mediapipe/framework/formats/matrix.h"
 #include "mediapipe/framework/formats/rect.pb.h"
@@ -91,6 +94,10 @@
     SplitImageVectorCalculator;
 REGISTER_CALCULATOR(SplitImageVectorCalculator);
 
+typedef SplitVectorCalculator<mediapipe::ImageFrame, true>
+    MovableSplitImageFrameVectorCalculator;
+REGISTER_CALCULATOR(MovableSplitImageFrameVectorCalculator);
+
 typedef SplitVectorCalculator<std::array<float, 16>, false>
     SplitAffineMatrixVectorCalculator;
 REGISTER_CALCULATOR(SplitAffineMatrixVectorCalculator);
diff --git a/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_gl.cc b/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_gl.cc
index be4f1cb..6adb3e4 100644
--- a/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_gl.cc
+++ b/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_gl.cc
@@ -82,8 +82,38 @@
     std::shared_ptr<GlContext> init_gl_context_;
     TfLiteDelegatePtr delegate_;
     std::unique_ptr<tflite::Interpreter> interpreter_;
-    std::vector<std::unique_ptr<Tensor>> gpu_buffers_in_;
-    std::vector<std::unique_ptr<Tensor>> gpu_buffers_out_;
+
+    class ReadWriteGlBuffer {
+     public:
+      explicit ReadWriteGlBuffer(std::vector<int> dims)
+          : tensor_(Tensor::ElementType::kFloat32,
+                    Tensor::Shape{std::move(dims)}),
+            // Getting the write view and destroying it immediately
+            // intentionally - the underlying GL buffer will be reused across
+            // multiple runs in multiple read/write manner directly - not
+            // through Tensor, so synchronization provided by Tensor is not
+            // required.
+            // NOTE: tensor is an implementation detail here which is used as a
+            // convenient method to create GlBuffer.
+            name_(tensor_.GetOpenGlBufferWriteView().name()) {}
+
+      ReadWriteGlBuffer(const ReadWriteGlBuffer&) = delete;
+      ReadWriteGlBuffer& operator=(const ReadWriteGlBuffer&) = delete;
+      ReadWriteGlBuffer(ReadWriteGlBuffer&&) = default;
+      ReadWriteGlBuffer& operator=(ReadWriteGlBuffer&&) = default;
+
+      GLuint name() const { return name_; }
+      int bytes() const { return tensor_.bytes(); }
+      const Tensor::Shape& shape() const { return tensor_.shape(); }
+
+     private:
+      Tensor tensor_;
+      GLuint name_;
+    };
+
+    std::vector<ReadWriteGlBuffer> gpu_buffers_in_;
+    std::vector<ReadWriteGlBuffer> gpu_buffers_out_;
+
     size_t output_size_ = 0;
     InputOutputTensorNames input_output_tensor_names_;
   };
@@ -196,13 +226,10 @@
         "Input tensor at index [%d] doesn't specify dimensions.",
         input_indices[i]);
 
-    gpu_buffers_in_.emplace_back(absl::make_unique<Tensor>(
-        Tensor::ElementType::kFloat32,
-        Tensor::Shape{std::vector<int>{
-            tensor->dims->data, tensor->dims->data + tensor->dims->size}}));
+    gpu_buffers_in_.emplace_back(std::vector<int>{
+        tensor->dims->data, tensor->dims->data + tensor->dims->size});
     RET_CHECK_EQ(TfLiteGpuDelegateBindBufferToTensor(
-                     delegate_.get(),
-                     gpu_buffers_in_.back()->GetOpenGlBufferWriteView().name(),
+                     delegate_.get(), gpu_buffers_in_.back().name(),
                      interpreter_->inputs()[i]),
                  kTfLiteOk);
   }
@@ -216,15 +243,12 @@
     RET_CHECK(tensor->dims->size > 0) << absl::StrFormat(
         "Output tensor at index [%d] doesn't specify dimensions.",
         output_indices[i]);
-    gpu_buffers_out_.emplace_back(absl::make_unique<Tensor>(
-        Tensor::ElementType::kFloat32,
-        Tensor::Shape{std::vector<int>{
-            tensor->dims->data, tensor->dims->data + tensor->dims->size}}));
-    RET_CHECK_EQ(TfLiteGpuDelegateBindBufferToTensor(
-                     delegate_.get(),
-                     gpu_buffers_out_.back()->GetOpenGlBufferWriteView().name(),
-                     output_indices[i]),
-                 kTfLiteOk);
+    gpu_buffers_out_.emplace_back(std::vector<int>{
+        tensor->dims->data, tensor->dims->data + tensor->dims->size});
+    RET_CHECK_EQ(
+        TfLiteGpuDelegateBindBufferToTensor(
+            delegate_.get(), gpu_buffers_out_.back().name(), output_indices[i]),
+        kTfLiteOk);
   }
 
   // Must call this last.
@@ -239,10 +263,9 @@
     std::vector<Tensor>& output_tensors) {
   // Explicitly copy input.
   for (int i = 0; i < input_tensors.size(); ++i) {
-    glBindBuffer(GL_COPY_READ_BUFFER,
-                 input_tensors[i].GetOpenGlBufferReadView().name());
-    glBindBuffer(GL_COPY_WRITE_BUFFER,
-                 gpu_buffers_in_[i]->GetOpenGlBufferWriteView().name());
+    auto read_view = input_tensors[i].GetOpenGlBufferReadView();
+    glBindBuffer(GL_COPY_READ_BUFFER, read_view.name());
+    glBindBuffer(GL_COPY_WRITE_BUFFER, gpu_buffers_in_[i].name());
     glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0,
                         input_tensors[i].bytes());
   }
@@ -255,15 +278,14 @@
 
   output_tensors.reserve(output_size_);
   for (int i = 0; i < output_size_; ++i) {
-    const auto& t = gpu_buffers_out_[i];
+    const auto& out_buffer = gpu_buffers_out_[i];
+    glBindBuffer(GL_COPY_READ_BUFFER, out_buffer.name());
     output_tensors.emplace_back(Tensor::ElementType::kFloat32,
-                                gpu_buffers_out_[i]->shape());
-    auto read_view = t->GetOpenGlBufferReadView();
-    glBindBuffer(GL_COPY_READ_BUFFER, read_view.name());
+                                out_buffer.shape());
     auto write_view = output_tensors.back().GetOpenGlBufferWriteView();
     glBindBuffer(GL_COPY_WRITE_BUFFER, write_view.name());
     glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0,
-                        t->bytes());
+                        out_buffer.bytes());
   }
   return absl::OkStatus();
 }
diff --git a/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_utils.cc b/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_utils.cc
index cedd521..d5ee27ba 100644
--- a/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_utils.cc
+++ b/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_utils.cc
@@ -164,26 +164,15 @@
 template <typename T>
 absl::Status CopyTfLiteTensorToTensor(const TfLiteTensor& tflite_tensor,
                                       Tensor& output_tensor) {
+  MP_RETURN_IF_ERROR(TensorDimsAndTypeEqual(output_tensor, tflite_tensor));
   auto output_tensor_view = output_tensor.GetCpuWriteView();
   T* output_tensor_buffer = output_tensor_view.buffer<T>();
   RET_CHECK(output_tensor_buffer) << "Output tensor buffer is null.";
   RET_CHECK_EQ(tflite_tensor.type, tflite::typeToTfLiteType<T>())
           .SetCode(absl::StatusCode::kInvalidArgument)
       << "TfLite tensor type and requested output type do not match.";
-  const Tensor::ElementType output_tensor_type = output_tensor.element_type();
-  RET_CHECK(output_tensor_type == tflite_tensor.type)
-          .SetCode(absl::StatusCode::kInvalidArgument)
-      << "Output and TfLiteTensor types do not match";
   const void* local_tensor_buffer = tflite_tensor.data.raw;
   RET_CHECK(local_tensor_buffer) << "TfLiteTensor tensor buffer is null.";
-  if (!TfLiteIntArrayEqualsArray(tflite_tensor.dims,
-                                 output_tensor.shape().dims.size(),
-                                 output_tensor.shape().dims.data())) {
-    return absl::InvalidArgumentError(
-        absl::StrCat("TfLiteTensor and Tensor shape do not match: ",
-                     GetTfLiteTensorDebugInfo(tflite_tensor), " vs. ",
-                     GetMpTensorDebugInfo(output_tensor)));
-  }
 
   std::memcpy(output_tensor_buffer, local_tensor_buffer, output_tensor.bytes());
   return absl::OkStatus();
@@ -415,4 +404,37 @@
                    TfLiteTypeGetName(reference_tflite_tensor.type)));
 }
 
+absl::Status TensorDimsAndTypeEqual(const Tensor& mp_tensor,
+                                    const TfLiteTensor& tflite_tensor) {
+  const Tensor::ElementType output_tensor_type = mp_tensor.element_type();
+  RET_CHECK(output_tensor_type == tflite_tensor.type)
+          .SetCode(absl::StatusCode::kInvalidArgument)
+      << absl::StrFormat(
+             "MediaPipe and TfLite tensor type do not match: MediaPipe tensor "
+             "type %s vs TfLite tensor type %s.",
+             GetTensorTypeString(output_tensor_type),
+             TfLiteTypeGetName(tflite_tensor.type));
+
+  // Scalar input in TensorFlow is described by an empty shape.
+  // In MediaPipe, we represent it as a shape with one element.
+  // For more details, see https://www.tensorflow.org/api_docs/python/tf/shape.
+  const bool is_scalar_input =
+      tflite_tensor.dims->size == 0 && mp_tensor.shape().num_elements() == 1;
+  if (!is_scalar_input && !TfLiteIntArrayEqualsArray(
+                              tflite_tensor.dims, mp_tensor.shape().dims.size(),
+                              mp_tensor.shape().dims.data())) {
+    return absl::InvalidArgumentError(
+        absl::StrCat("TfLiteTensor and Tensor shape do not match: ",
+                     GetTfLiteTensorDebugInfo(tflite_tensor), " vs. ",
+                     GetMpTensorDebugInfo(mp_tensor)));
+  }
+  RET_CHECK_EQ(mp_tensor.bytes(), tflite_tensor.bytes)
+          .SetCode(absl::StatusCode::kInvalidArgument)
+      << absl::StrFormat(
+             "MediaPipe and TfLite tensor bytes do not match: Mediapipe "
+             "tensor bytes %d vs TfLite tensor bytes %d.",
+             mp_tensor.bytes(), tflite_tensor.bytes);
+  return absl::OkStatus();
+}
+
 }  // namespace mediapipe
diff --git a/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_utils.h b/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_utils.h
index aa045dd3..0eff2b85 100644
--- a/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_utils.h
+++ b/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_calculator_utils.h
@@ -17,6 +17,7 @@
 
 #include <cstddef>
 #include <cstdint>
+#include <string>
 
 #include "absl/status/status.h"
 #include "absl/status/statusor.h"
@@ -80,6 +81,10 @@
     const TfLiteTensor& reference_tflite_tensor,
     MemoryManager* memory_manager = nullptr, int alignment = 0);
 
+// Checks that MP and TfLite tensor size and type matches.
+absl::Status TensorDimsAndTypeEqual(const Tensor& mp_tensor,
+                                    const TfLiteTensor& tflite_tensor);
+
 }  // namespace mediapipe
 
 #endif  // MEDIAPIPE_CALCULATORS_TENSOR_INFERENCE_CALCULATOR_UTILS_H_
diff --git a/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_interpreter_delegate_runner.cc b/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_interpreter_delegate_runner.cc
index 313d345..2469928 100644
--- a/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_interpreter_delegate_runner.cc
+++ b/third_party/mediapipe/src/mediapipe/calculators/tensor/inference_interpreter_delegate_runner.cc
@@ -118,8 +118,8 @@
       std::unique_ptr<InferenceFeedbackManager> feedback_manager,
       bool enable_zero_copy_tensor_io)
       : model_(std::move(model)),
-        interpreter_(std::move(interpreter)),
         delegate_(std::move(delegate)),
+        interpreter_(std::move(interpreter)),
         input_output_tensor_names_(std::move(input_output_tensor_names)),
         feedback_manager_(std::move(feedback_manager)),
         enable_zero_copy_tensor_io_(enable_zero_copy_tensor_io) {}
@@ -133,8 +133,8 @@
 
  private:
   api2::Packet<TfLiteModelPtr> model_;
-  std::unique_ptr<Interpreter> interpreter_;
   TfLiteDelegatePtr delegate_;
+  std::unique_ptr<Interpreter> interpreter_;
   InputOutputTensorNames input_output_tensor_names_;
   std::unique_ptr<InferenceFeedbackManager> feedback_manager_;
   bool enable_zero_copy_tensor_io_ = false;
diff --git a/third_party/mediapipe/src/mediapipe/calculators/tensorflow/tensor_to_matrix_calculator.cc b/third_party/mediapipe/src/mediapipe/calculators/tensorflow/tensor_to_matrix_calculator.cc
index ed234b3..c04b690 100644
--- a/third_party/mediapipe/src/mediapipe/calculators/tensorflow/tensor_to_matrix_calculator.cc
+++ b/third_party/mediapipe/src/mediapipe/calculators/tensorflow/tensor_to_matrix_calculator.cc
@@ -67,8 +67,10 @@
 // -- 1-D or 2-D Tensor
 // Output:
 // -- Matrix with the same values as the Tensor
-// If input tensor is 1 dimensional, the output Matrix is of (1xn) shape.
-// If input tensor is 2 dimensional (batched), the output Matrix is (mxn) shape.
+// If input tensor is 1 dimensional, the output Matrix is of (nx1) shape.
+// It is a 1-D column vector, with n rows and 1 column.
+// If input tensor is 2 dimensional (mxn), the output Matrix is (nxm) shape.
+// It has n rows and m columns.
 //
 // Example Config
 // node: {
diff --git a/third_party/mediapipe/src/mediapipe/calculators/tflite/tflite_inference_calculator.cc b/third_party/mediapipe/src/mediapipe/calculators/tflite/tflite_inference_calculator.cc
index 4ff0e46c..7dcd3f21 100644
--- a/third_party/mediapipe/src/mediapipe/calculators/tflite/tflite_inference_calculator.cc
+++ b/third_party/mediapipe/src/mediapipe/calculators/tflite/tflite_inference_calculator.cc
@@ -275,8 +275,8 @@
   }
 
   Packet model_packet_;
-  std::unique_ptr<tflite::Interpreter> interpreter_;
   TfLiteDelegatePtr delegate_;
+  std::unique_ptr<tflite::Interpreter> interpreter_;
 
 #if MEDIAPIPE_TFLITE_GL_INFERENCE
   mediapipe::GlCalculatorHelper gpu_helper_;
diff --git a/third_party/mediapipe/src/mediapipe/calculators/util/landmarks_smoothing_calculator.proto b/third_party/mediapipe/src/mediapipe/calculators/util/landmarks_smoothing_calculator.proto
index 017facb..cd47d66b 100644
--- a/third_party/mediapipe/src/mediapipe/calculators/util/landmarks_smoothing_calculator.proto
+++ b/third_party/mediapipe/src/mediapipe/calculators/util/landmarks_smoothing_calculator.proto
@@ -64,8 +64,8 @@
     // balance between jittering and lag.
     optional float beta = 3 [default = 0.0];
 
-    // Cutoff frequency for derivate. It is set to 1Hz in the original
-    // algorithm, but can be tuned to further smooth the speed (i.e. derivate)
+    // Cutoff frequency for derivative. It is set to 1Hz in the original
+    // algorithm, but can be tuned to further smooth the speed (i.e. derivative)
     // on the object.
     optional float derivate_cutoff = 4 [default = 1.0];
 
diff --git a/third_party/mediapipe/src/mediapipe/framework/BUILD b/third_party/mediapipe/src/mediapipe/framework/BUILD
index 9067b6d..ce5fd04 100644
--- a/third_party/mediapipe/src/mediapipe/framework/BUILD
+++ b/third_party/mediapipe/src/mediapipe/framework/BUILD
@@ -376,6 +376,7 @@
         "//mediapipe/framework/tool:validate",
         "//mediapipe/framework/tool:validate_name",
         "//mediapipe/gpu:gpu_service",
+        "//mediapipe/gpu:gpu_shared_data_internal",
         "//mediapipe/gpu:graph_support",
         "//mediapipe/util:cpu_util",
         "@com_google_absl//absl/base:core_headers",
@@ -402,6 +403,7 @@
     deps = [
         ":graph_service",
         ":packet",
+        "//mediapipe/framework/port:ret_check",
         "@com_google_absl//absl/log:absl_check",
         "@com_google_absl//absl/status",
     ],
@@ -956,6 +958,8 @@
         "//mediapipe/framework/tool:tag_map",
         "@com_google_absl//absl/base:core_headers",
         "@com_google_absl//absl/log:absl_check",
+        "@com_google_absl//absl/status",
+        "@com_google_absl//absl/strings",
         "@com_google_absl//absl/synchronization",
     ],
 )
@@ -972,9 +976,10 @@
         ":packet_type",
         ":port",
         ":timestamp",
-        "//mediapipe/framework/port:source_location",
         "//mediapipe/framework/port:status",
+        "@com_google_absl//absl/base:core_headers",
         "@com_google_absl//absl/log:absl_check",
+        "@com_google_absl//absl/log:absl_log",
         "@com_google_absl//absl/synchronization",
     ],
 )
@@ -1471,7 +1476,6 @@
         "//mediapipe/framework/tool:source",
         "@com_google_absl//absl/log:absl_check",
         "@com_google_absl//absl/log:absl_log",
-        "@com_google_absl//absl/memory",
     ],
 )
 
diff --git a/third_party/mediapipe/src/mediapipe/framework/api2/builder.h b/third_party/mediapipe/src/mediapipe/framework/api2/builder.h
index b2d7feb..f129989 100644
--- a/third_party/mediapipe/src/mediapipe/framework/api2/builder.h
+++ b/third_party/mediapipe/src/mediapipe/framework/api2/builder.h
@@ -98,6 +98,7 @@
 struct SourceBase;
 struct DestinationBase {
   SourceBase* source = nullptr;
+  bool back_edge = false;
 };
 struct SourceBase {
   std::vector<DestinationBase*> dests_;
@@ -144,11 +145,15 @@
 template <bool IsSide, typename T = internal::Generic>
 class SourceImpl;
 
+template <bool IsSide, typename T = internal::Generic>
+class DestinationImpl;
+
 // These classes wrap references to the underlying source/destination
 // endpoints, adding type information and the user-visible API.
-template <bool IsSide, typename T = internal::Generic>
-class DestinationImpl {
+template <typename T>
+class DestinationImpl</*IsSide=*/false, T> {
  public:
+  static constexpr bool kIsSide = false;
   using Base = DestinationBase;
 
   explicit DestinationImpl(std::vector<std::unique_ptr<Base>>* vec)
@@ -157,8 +162,54 @@
 
   template <typename U,
             std::enable_if_t<internal_builder::AllowCast<T, U>{}, int> = 0>
-  DestinationImpl<IsSide, U> Cast() {
-    return DestinationImpl<IsSide, U>(&base_);
+  DestinationImpl<kIsSide, U> Cast() {
+    return DestinationImpl<kIsSide, U>(&base_);
+  }
+
+  // Whether the input stream is a back edge.
+  //
+  // By default, MediaPipe requires graphs to be acyclic and treats cycles in a
+  // graph as errors. To allow MediaPipe to accept a cyclic graph, use/make
+  // corresponding inputs as back edges. A cyclic graph usually has an obvious
+  // forward direction, and a back edge goes in the opposite direction. For a
+  // formal definition of a back edge, please see
+  // https://en.wikipedia.org/wiki/Depth-first_search.
+  //
+  // Equivalent of having "input_stream_info" for an input stream in the config:
+  //   node {
+  //     ...
+  //     input_stream: "TAG:0:stream"
+  //     input_stream_info {
+  //       tag: "TAG:0"
+  //       back_edge: true
+  //     }
+  //   }
+  DestinationImpl<kIsSide, T>& AsBackEdge() {
+    base_.back_edge = true;
+    return *this;
+  }
+
+ private:
+  DestinationBase& base_;
+
+  template <bool Source_IsSide, typename Source_T>
+  friend class SourceImpl;
+};
+
+template <typename T>
+class DestinationImpl</*IsSide=*/true, T> {
+ public:
+  static constexpr bool kIsSide = true;
+  using Base = DestinationBase;
+
+  explicit DestinationImpl(std::vector<std::unique_ptr<Base>>* vec)
+      : DestinationImpl(&GetWithAutoGrow(vec, 0)) {}
+  explicit DestinationImpl(DestinationBase* base) : base_(*base) {}
+
+  template <typename U,
+            std::enable_if_t<internal_builder::AllowCast<T, U>{}, int> = 0>
+  DestinationImpl<kIsSide, U> Cast() {
+    return DestinationImpl<kIsSide, U>(&base_);
   }
 
  private:
@@ -519,6 +570,8 @@
     return *output_stream_handler_;
   }
 
+  void SetSourceLayer(int source_layer) { source_layer_ = source_layer; }
+
  protected:
   // GetOptionsInternal resolutes the overload greedily, which finds the first
   // match then succeed (template specialization tries all matches, thus could
@@ -562,6 +615,8 @@
   std::optional<InputStreamHandler> input_stream_handler_;
   std::optional<OutputStreamHandler> output_stream_handler_;
 
+  std::optional<int> source_layer_;
+
   friend class Graph;
 };
 
@@ -912,7 +967,15 @@
     return absl::OkStatus();
   }
 
-  std::string TaggedName(const TagIndexLocation& loc, absl::string_view name) {
+  static std::string TagIndex(const TagIndexLocation& loc) {
+    if (loc.count <= 1) {
+      return loc.tag;
+    }
+    return absl::StrCat(loc.tag, ":", loc.index);
+  }
+
+  static std::string TaggedName(const TagIndexLocation& loc,
+                                absl::string_view name) {
     if (loc.tag.empty()) {
       // ParseTagIndexName does not allow using explicit indices without tags,
       // while ParseTagIndex does.
@@ -938,6 +1001,11 @@
               << (loc.tag.empty() ? "(empty)" : loc.tag) << " at index "
               << loc.index;
           config->add_input_stream(TaggedName(loc, endpoint.source->name_));
+          if (endpoint.back_edge) {
+            auto* info = config->add_input_stream_info();
+            info->set_back_edge(true);
+            info->set_tag_index(TagIndex(loc));
+          }
           return absl::OkStatus();
         }));
     MP_RETURN_IF_ERROR(node.out_streams_.Visit(
@@ -988,6 +1056,9 @@
             *node.output_stream_handler_->options_;
       }
     }
+    if (node.source_layer_.has_value()) {
+      config->set_source_layer(node.source_layer_.value());
+    }
     return {};
   }
 
@@ -1027,7 +1098,11 @@
               << type_ << ": Missing source for graph output stream with tag "
               << (loc.tag.empty() ? "(empty)" : loc.tag) << " at index "
               << loc.index;
+          RET_CHECK(!endpoint.back_edge)
+              << "Graph output: " << (loc.tag.empty() ? "(empty)" : loc.tag)
+              << " at index " << loc.index << " cannot be a back edge";
           config->add_output_stream(TaggedName(loc, endpoint.source->name_));
+
           return absl::OkStatus();
         }));
     MP_RETURN_IF_ERROR(graph_boundary_.out_streams_.Visit(
diff --git a/third_party/mediapipe/src/mediapipe/framework/api2/port.h b/third_party/mediapipe/src/mediapipe/framework/api2/port.h
index 534b490..d76aa3d2 100644
--- a/third_party/mediapipe/src/mediapipe/framework/api2/port.h
+++ b/third_party/mediapipe/src/mediapipe/framework/api2/port.h
@@ -87,7 +87,7 @@
 
 template <auto& kP>
 struct SameType {
-  static constexpr const decltype(kP) & kPort = kP;
+  static constexpr const decltype(kP)& kPort = kP;
 };
 
 class PacketTypeAccess;
diff --git a/third_party/mediapipe/src/mediapipe/framework/api2/stream/BUILD b/third_party/mediapipe/src/mediapipe/framework/api2/stream/BUILD
index 127393d..9950abc 100644
--- a/third_party/mediapipe/src/mediapipe/framework/api2/stream/BUILD
+++ b/third_party/mediapipe/src/mediapipe/framework/api2/stream/BUILD
@@ -343,7 +343,6 @@
         "//mediapipe/calculators/util:multi_world_landmarks_smoothing_calculator",
         "//mediapipe/calculators/util:visibility_smoothing_calculator",
         "//mediapipe/calculators/util:visibility_smoothing_calculator_cc_proto",
-        "//mediapipe/framework:calculator_framework",
         "//mediapipe/framework/api2:builder",
         "//mediapipe/framework/formats:landmark_cc_proto",
         "//mediapipe/framework/formats:rect_cc_proto",
diff --git a/third_party/mediapipe/src/mediapipe/framework/calculator_graph.cc b/third_party/mediapipe/src/mediapipe/framework/calculator_graph.cc
index 1492525..798d889e 100644
--- a/third_party/mediapipe/src/mediapipe/framework/calculator_graph.cc
+++ b/third_party/mediapipe/src/mediapipe/framework/calculator_graph.cc
@@ -82,6 +82,10 @@
 #include "mediapipe/gpu/graph_support.h"
 #include "mediapipe/util/cpu_util.h"
 
+#if !MEDIAPIPE_DISABLE_GPU
+#include "mediapipe/gpu/gpu_shared_data_internal.h"
+#endif  // !MEDIAPIPE_DISABLE_GPU
+
 namespace mediapipe {
 
 namespace {
@@ -138,7 +142,6 @@
 // Adopt all services from the CalculatorContext / parent graph.
 CalculatorGraph::CalculatorGraph(CalculatorContext* cc)
     : counter_factory_(std::make_unique<BasicCounterFactory>()),
-      service_manager_(cc != nullptr ? cc->GetGraphServiceManager() : nullptr),
       profiler_(std::make_shared<ProfilingContext>()),
       scheduler_(this) {
   if (cc != nullptr) {
@@ -146,6 +149,29 @@
     // collisions between newly created and inherited graphs.
     // TODO b/368015341- Use factory method to avoid CHECK in constructor.
     ABSL_CHECK_OK(DisallowServiceDefaultInitialization());
+
+    // Adopt all services from the parent graph except for GpuResources.
+    const auto parent_service_manager = cc->GetGraphServiceManager();
+    const auto parent_service_packets =
+        parent_service_manager->ServicePackets();
+    GraphServiceManager::ServiceMap service_packets;
+    for (const auto& [key, packet] : parent_service_packets) {
+#if !MEDIAPIPE_DISABLE_GPU
+      if (key == kGpuService.key) {
+        // To avoid deadlocks when sharing the same GPU thread between
+        // multiple graphs, we create a new GpuResources instance for each
+        // sub-graph with a dedicated GL context / thread.
+        auto resources = mediapipe::GpuResources::Create(
+            *packet.Get<std::shared_ptr<mediapipe::GpuResources>>());
+        ABSL_CHECK_OK(resources);
+        service_packets[key] =
+            MakePacket<std::shared_ptr<mediapipe::GpuResources>>(*resources);
+        continue;
+      }
+#endif  // !MEDIAPIPE_DISABLE_GPU
+      service_packets[key] = packet;
+    }
+    service_manager_.SetServicePackets(service_packets);
   }
   SetVLogOverrides();
 }
diff --git a/third_party/mediapipe/src/mediapipe/framework/calculator_node.cc b/third_party/mediapipe/src/mediapipe/framework/calculator_node.cc
index 2a7d56c..5dd1a98 100644
--- a/third_party/mediapipe/src/mediapipe/framework/calculator_node.cc
+++ b/third_party/mediapipe/src/mediapipe/framework/calculator_node.cc
@@ -14,11 +14,13 @@
 
 #include "mediapipe/framework/calculator_node.h"
 
+#include <cstdint>
+#include <map>
 #include <memory>
+#include <optional>
 #include <set>
 #include <string>
 #include <tuple>
-#include <unordered_map>
 #include <utility>
 #include <vector>
 
@@ -28,7 +30,6 @@
 #include "absl/memory/memory.h"
 #include "absl/status/status.h"
 #include "absl/strings/str_cat.h"
-#include "absl/strings/str_join.h"
 #include "absl/strings/str_split.h"
 #include "absl/strings/string_view.h"
 #include "absl/strings/substitute.h"
@@ -46,7 +47,6 @@
 #include "mediapipe/framework/packet.h"
 #include "mediapipe/framework/packet_set.h"
 #include "mediapipe/framework/packet_type.h"
-#include "mediapipe/framework/port.h"
 #include "mediapipe/framework/port/logging.h"
 #include "mediapipe/framework/port/proto_ns.h"
 #include "mediapipe/framework/port/ret_check.h"
@@ -56,7 +56,6 @@
 #include "mediapipe/framework/tool/name_util.h"
 #include "mediapipe/framework/tool/status_util.h"
 #include "mediapipe/framework/tool/tag_map.h"
-#include "mediapipe/framework/tool/validate_name.h"
 
 namespace mediapipe {
 
@@ -230,26 +229,35 @@
 }
 
 CalculatorRuntimeInfo CalculatorNode::GetStreamMonitoringInfo() const {
-  CalculatorRuntimeInfo calulator_info;
-  calulator_info.set_calculator_name(DebugName());
+  CalculatorRuntimeInfo calculator_info;
+  calculator_info.set_calculator_name(DebugName());
   {
     absl::MutexLock lock(&runtime_info_mutex_);
-    calulator_info.set_last_process_start_unix_us(
+    calculator_info.set_last_process_start_unix_us(
         absl::ToUnixMicros(last_process_start_ts_));
-    calulator_info.set_last_process_finish_unix_us(
+    calculator_info.set_last_process_finish_unix_us(
         absl::ToUnixMicros(last_process_finish_ts_));
   }
-  const auto monitoring_info = input_stream_handler_->GetMonitoringInfo();
+  const auto input_stream_info = input_stream_handler_->GetMonitoringInfo();
   for (const auto& [stream_name, queue_size, num_packets_added,
-                    minimum_timestamp_or_bound] : monitoring_info) {
-    auto* stream_info = calulator_info.add_input_stream_infos();
+                    minimum_timestamp_or_bound] : input_stream_info) {
+    auto* stream_info = calculator_info.add_input_stream_infos();
     stream_info->set_stream_name(stream_name);
     stream_info->set_queue_size(queue_size);
     stream_info->set_number_of_packets_added(num_packets_added);
     stream_info->set_minimum_timestamp_or_bound(
         minimum_timestamp_or_bound.Value());
   }
-  return calulator_info;
+  const auto output_stream_info = output_stream_handler_->GetMonitoringInfo();
+  for (const auto& [stream_name, num_packets_added,
+                    minimum_timestamp_or_bound] : output_stream_info) {
+    auto* stream_info = calculator_info.add_output_stream_infos();
+    stream_info->set_stream_name(stream_name);
+    stream_info->set_number_of_packets_added(num_packets_added);
+    stream_info->set_minimum_timestamp_or_bound(
+        minimum_timestamp_or_bound.Value());
+  }
+  return calculator_info;
 }
 
 absl::Status CalculatorNode::InitializeOutputSidePackets(
@@ -893,8 +901,7 @@
     // This is not a source Calculator.
     InputStreamShardSet* const inputs = &calculator_context->Inputs();
     OutputStreamShardSet* const outputs = &calculator_context->Outputs();
-    absl::Status result =
-        absl::InternalError("Calculator context has no input packets.");
+    std::optional<absl::Status> result;
 
     int num_invocations = calculator_context_manager_.NumberOfContextTimestamps(
         *calculator_context);
@@ -932,15 +939,16 @@
         // of the graph. This is different from an error in that it will
         // ensure that all sources will be closed and that packets in input
         // streams will be processed before the graph is terminated.
-        if (!result.ok() && result != tool::StatusStop()) {
-          return mediapipe::StatusBuilder(result, MEDIAPIPE_LOC).SetPrepend()
+        if (result.has_value() && !result->ok() &&
+            result != tool::StatusStop()) {
+          return mediapipe::StatusBuilder(*result, MEDIAPIPE_LOC).SetPrepend()
                  << absl::Substitute(
                         "Calculator::Process() for node \"$0\" failed: ",
                         DebugName());
         }
         output_stream_handler_->PostProcess(input_timestamp);
         if (result == tool::StatusStop()) {
-          return result;
+          return *result;
         }
       } else if (input_timestamp == Timestamp::Done()) {
         // Some or all the input streams are closed and there are not enough
@@ -957,7 +965,11 @@
             << input_timestamp;
       }
     }
-    return result;
+    if (result.has_value()) {
+      return *result;
+    } else {
+      return absl::InternalError("Calculator context has no input packets.");
+    }
   }
 }
 
diff --git a/third_party/mediapipe/src/mediapipe/framework/debug/BUILD b/third_party/mediapipe/src/mediapipe/framework/debug/BUILD
new file mode 100644
index 0000000..06191af
--- /dev/null
+++ b/third_party/mediapipe/src/mediapipe/framework/debug/BUILD
@@ -0,0 +1,60 @@
+# Copyright 2025 The MediaPipe Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"])
+
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+    name = "logging",
+    srcs = ["logging.cc"],
+    hdrs = ["logging.h"],
+    deps = [
+        "//mediapipe/framework/formats:image_frame",
+        "//mediapipe/framework/formats:image_frame_opencv",
+        "//mediapipe/framework/formats:tensor",
+        "//mediapipe/framework/port:opencv_core",
+        "//mediapipe/framework/port:opencv_imgproc",
+        "@com_google_absl//absl/functional:any_invocable",
+        "@com_google_absl//absl/log",
+        "@com_google_absl//absl/log:absl_log",
+        "@com_google_absl//absl/log:check",
+        "@com_google_absl//absl/status",
+        "@com_google_absl//absl/strings",
+        "@com_google_absl//absl/strings:str_format",
+        "@com_google_absl//absl/strings:string_view",
+        "@halide//:runtime",
+    ],
+)
+
+cc_test(
+    name = "logging_test",
+    srcs = ["logging_test.cc"],
+    data = ["testdata/sergey.png"],
+    deps = [
+        ":logging",
+        "//mediapipe/framework/deps:file_path",
+        "//mediapipe/framework/formats:image_frame",
+        "//mediapipe/framework/formats:tensor",
+        "//mediapipe/framework/port:gtest_main",
+        "//mediapipe/framework/port:opencv_core",
+        "//mediapipe/framework/tool:test_util",
+        "@com_google_absl//absl/base:log_severity",
+        "@com_google_absl//absl/log:absl_check",
+        "@com_google_absl//absl/log:scoped_mock_log",
+        "@com_google_absl//absl/strings",
+        "@com_google_absl//absl/strings:string_view",
+        "@halide//:runtime",
+    ],
+)
diff --git a/third_party/mediapipe/src/mediapipe/framework/debug/logging.cc b/third_party/mediapipe/src/mediapipe/framework/debug/logging.cc
new file mode 100644
index 0000000..c035aa89
--- /dev/null
+++ b/third_party/mediapipe/src/mediapipe/framework/debug/logging.cc
@@ -0,0 +1,385 @@
+// Copyright 2025 The MediaPipe Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "mediapipe/framework/debug/logging.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <limits>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include "HalideBuffer.h"
+#include "absl/functional/any_invocable.h"
+#include "absl/log/absl_log.h"
+#include "absl/log/check.h"
+#include "absl/log/log.h"
+#include "absl/status/status.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/string_view.h"
+#include "mediapipe/framework/formats/image_frame.h"
+#include "mediapipe/framework/formats/image_frame_opencv.h"
+#include "mediapipe/framework/formats/tensor.h"
+#include "mediapipe/framework/port/opencv_core_inc.h"
+#include "mediapipe/framework/port/opencv_imgproc_inc.h"
+
+namespace mediapipe::debug {
+namespace {
+
+// Returns true if the terminal supports true color.
+bool IsTrueColorTerm() {
+  const char* colorterm = std::getenv("COLORTERM");
+  return colorterm != nullptr && strcmp(colorterm, "truecolor") == 0;
+}
+
+// Print images of at most 120 x 120 characters. If images are larger, they are
+// downscaled (AREA sampling).
+constexpr int kMaxCharsX = 120;
+constexpr int kMaxCharsY = 120;
+
+// Table for nice ASCII Art.
+constexpr char kGrayTable[] = " .:-=+*#%@";
+
+// Maps a value between 0 and 1 to a character in kGrayTable.
+char MapToAscii(float value) {
+  value = std::clamp(value, 0.0f, 1.0f);
+  int int_val = static_cast<int>(strlen(kGrayTable) * value);
+  return kGrayTable[std::min<int>(int_val, strlen(kGrayTable) - 1)];
+}
+
+template <typename T>
+double GetNormalizedValue(const uint8_t* ptr, int idx) {
+  constexpr double min = std::numeric_limits<T>::lowest();
+  constexpr double max = std::numeric_limits<T>::max();
+  return (reinterpret_cast<const T*>(ptr)[idx] - min) / (max - min);
+}
+
+absl::StatusOr<std::function<double(const uint8_t*, int)>>
+GetMatElementAccessor(const cv::Mat& mat) {
+  switch (mat.depth()) {
+    case CV_8U:
+      return [](const uint8_t* mat_ptr, int idx) -> double {
+        return GetNormalizedValue<uint8_t>(mat_ptr, idx);
+      };
+    case CV_8S:
+      return [](const uint8_t* mat_ptr, int idx) -> double {
+        return GetNormalizedValue<int8_t>(mat_ptr, idx);
+      };
+    case CV_16U:
+      return [](const uint8_t* mat_ptr, int idx) -> double {
+        return GetNormalizedValue<uint16_t>(mat_ptr, idx);
+      };
+    case CV_16S:
+      return [](const uint8_t* mat_ptr, int idx) -> double {
+        return GetNormalizedValue<int16_t>(mat_ptr, idx);
+      };
+    case CV_32S:
+      return [](const uint8_t* mat_ptr, int idx) -> double {
+        return GetNormalizedValue<int32_t>(mat_ptr, idx);
+      };
+    case CV_32F:
+      return [](const uint8_t* mat_ptr, int idx) -> double {
+        return reinterpret_cast<const float*>(mat_ptr)[idx];
+      };
+    case CV_64F:
+      return [](const uint8_t* mat_ptr, int idx) -> double {
+        return reinterpret_cast<const double*>(mat_ptr)[idx];
+      };
+    default:
+      return absl::UnimplementedError(
+          absl::StrCat("Unhandled mat depth ", mat.depth()));
+  }
+}
+
+std::tuple<int, int, int> GetRGB(
+    const std::function<double(const uint8_t*, int)>& accessor,
+    const uint8_t* ptr, int x, int y, int num_channels) {
+  if (!ptr) {
+    return std::make_tuple(0, 0, 0);
+  }
+
+  double r, g, b;
+  if (num_channels == 1) {
+    r = g = b = accessor(ptr, x);
+  }
+
+  if (num_channels == 2) {
+    r = accessor(ptr, x * 2 + 0);
+    g = accessor(ptr, x * 2 + 1);
+    b = 0.0;
+  }
+
+  if (num_channels == 3) {
+    r = accessor(ptr, x * 3 + 0);
+    g = accessor(ptr, x * 3 + 1);
+    b = accessor(ptr, x * 3 + 2);
+  }
+
+  if (num_channels == 4) {
+    r = accessor(ptr, x * 4 + 0);
+    g = accessor(ptr, x * 4 + 1);
+    b = accessor(ptr, x * 4 + 2);
+    double a = accessor(ptr, x * 4 + 3);
+
+    // Make a checkerboard.
+    bool is_odd = (x / 2 + y / 2) & 1;
+    double checker = is_odd ? 0.25 : 0.75;
+    r = r * a + checker * (1.0 - a);
+    g = g * a + checker * (1.0 - a);
+    b = b * a + checker * (1.0 - a);
+  }
+
+  return std::make_tuple(static_cast<int>(r * 255.0),
+                         static_cast<int>(g * 255.0),
+                         static_cast<int>(b * 255.0));
+}
+
+using ChannelMapper = absl::AnyInvocable<float(
+    const float* channel_vec, int num_input_channels, int output_channel)>;
+
+void LogMatImpl(const cv::Mat& mat, absl::string_view name) {
+  int width = mat.cols;
+  int height = mat.rows;
+  int num_channels = mat.channels();
+
+  bool is_true_color_term = IsTrueColorTerm();
+
+  // Use half as many rows than cols since ASCII chars are higher than wide.
+  int small_width = std::min(kMaxCharsX, width);
+  int divisor = is_true_color_term ? 1 : 2;
+  int small_height = std::max(small_width * height / (divisor * width), 1);
+  if (small_height > kMaxCharsY) {
+    small_height = kMaxCharsY;
+    small_width = small_height * width * divisor / height;
+  }
+  cv::Mat small_mat;
+  if (small_width != width || small_height != height) {
+    cv::resize(mat, small_mat, cv::Size(small_width, small_height),
+               cv::INTER_AREA);
+  } else {
+    small_mat = mat;
+  }
+
+  // The accessor function returns a value between 0 and 1 for any data type.
+  auto accessor_or = GetMatElementAccessor(small_mat);
+  if (!accessor_or.ok()) {
+    ABSL_LOG(WARNING) << "  <cannot print: " << accessor_or.status().message()
+                      << ">";
+    return;
+  }
+  auto accessor = *accessor_or;
+
+  // Draw the image with a nice frame.
+  std::string horizontal_bar;
+  horizontal_bar.reserve(small_width * 2);
+  for (int x = 0; x < small_width; ++x) {
+    horizontal_bar += "\u2550";
+  }
+  ABSL_LOG(INFO) << "\u2554" << horizontal_bar << "\u2557 " << name;
+  std::string row;
+  if (is_true_color_term) {
+    // Use half-blocks (\u2584) and truecolor escape codes.
+    for (int y = 0; y < small_height; y += 2) {
+      const uint8_t* top = small_mat.ptr<uint8_t>(y);
+      const uint8_t* bottom =
+          y + 1 < small_height ? small_mat.ptr<uint8_t>(y + 1) : nullptr;
+      for (int x = 0; x < small_width; ++x) {
+        int rt, gt, bt, rb, gb, bb;
+        std::tie(rt, gt, bt) = GetRGB(accessor, top, x, y, num_channels);
+        std::tie(rb, gb, bb) = GetRGB(accessor, bottom, x, y + 1, num_channels);
+        row += absl::StrFormat("\033[48;2;%d;%d;%dm\033[38;2;%d;%d;%dm\u2584",
+                               rt, gt, bt, rb, gb, bb);
+      }
+      row += "\033[0m";
+      // Use name as postfix for easy log grepping.
+      ABSL_LOG(INFO) << "\u2551" << row << "\u2551 " << name;
+      row.clear();
+    }
+  } else {
+    // Use ASCII art.
+    for (int y = 0; y < small_height; ++y) {
+      const uint8_t* mat_ptr = small_mat.ptr<uint8_t>(y);
+      for (int x = 0; x < small_width; ++x) {
+        double value = 0.0f;
+        for (int c = 0; c < num_channels; ++c) {
+          value += accessor(mat_ptr, x * num_channels + c);
+        }
+        row.push_back(MapToAscii(value / num_channels));
+      }
+      // Use name as postfix for easy log grepping.
+      ABSL_LOG(INFO) << "\u2551" << row << "\u2551 " << name;
+      row.clear();
+    }
+  }
+  ABSL_LOG(INFO) << "\u255a" << horizontal_bar << "\u255d " << name;
+}
+
+void LogTensorImpl(const Tensor& tensor, float min_range, float max_range,
+                   int num_output_channels, ChannelMapper mapper,
+                   absl::string_view name) {
+  if (tensor.element_type() != Tensor::ElementType::kFloat32) {
+    ABSL_LOG(WARNING) << "  <cannot log tensor of type "
+                      << static_cast<int>(tensor.element_type())
+                      << ", required: float>";
+    return;
+  }
+
+  int height = tensor.shape().dims[1];
+  int width = tensor.shape().dims[2];
+  int num_channels = tensor.shape().dims[3];
+
+  if (tensor.shape().dims[0] == 0 || width == 0 || height == 0 ||
+      num_channels == 0) {
+    ABSL_LOG(INFO) << "  <empty>";
+    return;
+  }
+
+  cv::Mat mat(height, width, CV_MAKETYPE(CV_8U, num_output_channels));
+
+  Tensor::CpuReadView read_view = tensor.GetCpuReadView();
+  float scale = 255.0f / (max_range - min_range);
+  const float* tensor_ptr = read_view.buffer<float>();
+  for (int y = 0; y < height; ++y) {
+    uint8_t* row = mat.ptr<uint8_t>(y);
+    for (int x = 0; x < width; ++x) {
+      for (int c = 0; c < num_output_channels; ++c) {
+        const float* channel_vec = tensor_ptr + (y * width + x) * num_channels;
+        float value = mapper(channel_vec, num_channels, c);
+        row[x * num_output_channels + c] = static_cast<uint8_t>(
+            std::clamp((value - min_range) * scale, 0.0f, 255.0f));
+      }
+    }
+  }
+
+  LogMatImpl(mat, name);
+}
+
+}  // namespace
+
+void LogTensorChannel(const Tensor& tensor, int channel, absl::string_view name,
+                      float min_range, float max_range) {
+  ABSL_LOG(INFO) << name << "[" << tensor.shape().dims << "], channel "
+                 << channel << " =";
+
+  if (tensor.shape().dims.size() != 4 || tensor.shape().dims[0] != 1 ||
+      channel < 0 || channel >= tensor.shape().dims[3]) {
+    ABSL_LOG(WARNING) << "  <cannot log channel " << channel
+                      << " of tensor with shape " << tensor.shape().dims << ">";
+    return;
+  }
+
+  LogTensorImpl(
+      tensor, min_range, max_range, /*num_output_channels=*/1,
+      [channel](const float* channel_vec, int num_input_channels,
+                int output_channel) { return channel_vec[channel]; },
+      name);
+}
+
+void LogTensor(const Tensor& tensor, absl::string_view name, float min_range,
+               float max_range) {
+  if (tensor.shape().dims.size() != 4 || tensor.shape().dims[0] != 1) {
+    ABSL_LOG(INFO) << name << "[" << tensor.shape().dims << "] = ";
+    ABSL_LOG(WARNING) << "  <cannot log tensor with shape "
+                      << tensor.shape().dims << ", required: [1, h, w, c]>";
+    return;
+  }
+
+  int num_channels = tensor.shape().dims.back();
+  if (num_channels <= 3) {
+    // Log tensor as RGB or grayscale image.
+    ABSL_LOG(INFO) << name << "[" << tensor.shape().dims << "] = ";
+    LogTensorImpl(
+        tensor, min_range, max_range, num_channels,
+        [](const float* channel_vec, int num_input_channels,
+           int output_channel) { return channel_vec[output_channel]; },
+        name);
+  } else {
+    // Log tensor channel averages as grayscale image.
+    ABSL_LOG(INFO) << name << "[" << tensor.shape().dims
+                   << "], channel average = ";
+    LogTensorImpl(
+        tensor, min_range, max_range, 1,
+        [](const float* channel_vec, int num_input_channels,
+           int output_channel) {
+          float sum = 0.0f;
+          for (int c = 0; c < num_input_channels; ++c) {
+            sum += channel_vec[c];
+          }
+          return sum / num_input_channels;
+        },
+        name);
+  }
+}
+
+void LogImage(const ImageFrame& image, absl::string_view name) {
+  return LogMat(formats::MatView(&image), name);
+}
+
+// Logs the given mat as ASCII image.
+void LogMat(const cv::Mat& mat, absl::string_view name) {
+  int width = mat.cols;
+  int height = mat.rows;
+  int num_channels = mat.channels();
+
+  ABSL_LOG(INFO) << name << "[" << width << " " << height << " " << num_channels
+                 << "] =";
+
+  if (width == 0 || height == 0 || num_channels == 0) {
+    ABSL_LOG(INFO) << "  <empty>";
+    return;
+  }
+
+  LogMatImpl(mat, name);
+}
+
+void LogHalideBuffer(Halide::Runtime::Buffer<const uint8_t> buffer,
+                     absl::string_view name) {
+  std::vector<int> dims(buffer.dimensions());
+  for (int i = 0; i < buffer.dimensions(); ++i) {
+    dims[i] = buffer.extent(i);
+  }
+  ABSL_LOG(INFO) << name << "[" << dims << "] =";
+
+  if (buffer.dimensions() > 3) {
+    ABSL_LOG(WARNING) << "  <cannot log Halide buffer with "
+                      << buffer.dimensions() << " dimensions, required: <= 3>";
+    return;
+  }
+  if (buffer.dimensions() == 0) {
+    ABSL_LOG(INFO) << "  <empty>";
+    return;
+  }
+
+  // cv::Mat only supports mapping to interleaved buffers (channels must be
+  // consecutive).
+  bool is_interleaved = buffer.dimensions() < 3 || buffer.stride(2) == 1;
+  if (!is_interleaved) {
+    buffer = buffer.copy_to_interleaved();
+  }
+
+  const int sizes[] = {buffer.height(), buffer.width()};
+  const int type = CV_MAKETYPE(CV_8U, buffer.channels());
+  const size_t steps[] = {
+      static_cast<size_t>(buffer.dimensions() > 1 ? buffer.stride(1) : 1),
+      static_cast<size_t>(buffer.stride(0))};
+  cv::Mat mat(2, sizes, type, const_cast<unsigned char*>(buffer.data()), steps);
+  LogMatImpl(mat, name);
+}
+
+}  // namespace mediapipe::debug
diff --git a/third_party/mediapipe/src/mediapipe/framework/debug/logging.h b/third_party/mediapipe/src/mediapipe/framework/debug/logging.h
new file mode 100644
index 0000000..4747052
--- /dev/null
+++ b/third_party/mediapipe/src/mediapipe/framework/debug/logging.h
@@ -0,0 +1,59 @@
+// Copyright 2025 The MediaPipe Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef MEDIAPIPE_FRAMEWORK_DEBUG_LOGGING_H_
+#define MEDIAPIPE_FRAMEWORK_DEBUG_LOGGING_H_
+
+#include "HalideBuffer.h"
+#include "absl/strings/string_view.h"
+#include "mediapipe/framework/formats/image_frame.h"
+#include "mediapipe/framework/formats/tensor.h"
+#include "mediapipe/framework/port/opencv_core_inc.h"
+
+namespace mediapipe::debug {
+
+// Logs the given channel (=last dimension) of the float tensor as a color or
+// ASCII image, depending on terminal capabilities. The values are clamped to
+// [min_range, max_range].
+void LogTensorChannel(const mediapipe::Tensor& tensor, int channel,
+                      absl::string_view name = "tensor", float min_range = 0.0f,
+                      float max_range = 1.0f);
+
+// Logs the given float tensor as a color or ASCII image, depending on terminal
+// capabilities. Assumes a float tensor with dimensions [1, h, w, c]. The values
+// are clamped to [min_range, max_range]. A one-channel tensor is printed as a
+// grayscale image, two-channel and three-channel tensors are printed as a color
+// image, and a tensor with more channels is averaged over all channels and
+// printed as a grayscale image.
+void LogTensor(const mediapipe::Tensor& tensor,
+               absl::string_view name = "tensor", float min_range = 0.0f,
+               float max_range = 1.0f);
+
+// Logs the given image as a color or ASCII image, depending on terminal
+// capabilities.
+void LogImage(const mediapipe::ImageFrame& image,
+              absl::string_view name = "image");
+
+// Logs the given mat as a color or ASCII image, depending on terminal
+// capabilities.
+void LogMat(const cv::Mat& mat, absl::string_view name = "mat");
+
+// Logs the given Halide buffer as a color or ASCII image, depending on terminal
+// capabilities.
+void LogHalideBuffer(Halide::Runtime::Buffer<const uint8_t> buffer,
+                     absl::string_view name = "buffer");
+
+}  // namespace mediapipe::debug
+
+#endif  // MEDIAPIPE_FRAMEWORK_DEBUG_LOGGING_H_
diff --git a/third_party/mediapipe/src/mediapipe/framework/deps/safe_int.h b/third_party/mediapipe/src/mediapipe/framework/deps/safe_int.h
index ccaa7e1..e4a1faf3 100644
--- a/third_party/mediapipe/src/mediapipe/framework/deps/safe_int.h
+++ b/third_party/mediapipe/src/mediapipe/framework/deps/safe_int.h
@@ -63,30 +63,16 @@
 //   https://www.securecoding.cert.org/confluence/display/seccode/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow?showComments=false
 template <typename ErrorType>
 class SafeIntStrongIntValidator {
- private:
-  template <typename T>
-  static void SanityCheck() {
-    // Check that the underlying integral type provides a range that is
-    // compatible with two's complement.
-    if (std::numeric_limits<T>::is_signed) {
-      ABSL_CHECK_EQ(
-          -1, std::numeric_limits<T>::min() + std::numeric_limits<T>::max())
-          << "unexpected integral bounds";
-    }
-
-    // Check that division truncates towards 0 (implementation defined in
-    // C++'03, but standard in C++'11).
-    ABSL_CHECK_EQ(12, 127 / 10) << "division does not truncate towards 0";
-    ABSL_CHECK_EQ(-12, -127 / 10) << "division does not truncate towards 0";
-    ABSL_CHECK_EQ(-12, 127 / -10) << "division does not truncate towards 0";
-    ABSL_CHECK_EQ(12, -127 / -10) << "division does not truncate towards 0";
-  }
-
  public:
   template <typename T, typename U>
   static void ValidateInit(U arg) {
-    // Do some sanity checks before proceeding.
-    SanityCheck<T>();
+    // Check that the underlying integral type provides a range that is
+    // compatible with two's complement.
+    static_assert(
+        !std::numeric_limits<T>::is_signed ||
+            (std::numeric_limits<T>::min() + std::numeric_limits<T>::max() ==
+             -1),
+        "unexpected integral bounds");
 
     // If the argument is floating point, we can do a simple check to make
     // sure the value is in range.  It is undefined behavior to convert to int
diff --git a/third_party/mediapipe/src/mediapipe/framework/encode_binary_proto.bzl b/third_party/mediapipe/src/mediapipe/framework/encode_binary_proto.bzl
index 04a307f..4309aa5 100644
--- a/third_party/mediapipe/src/mediapipe/framework/encode_binary_proto.bzl
+++ b/third_party/mediapipe/src/mediapipe/framework/encode_binary_proto.bzl
@@ -147,7 +147,6 @@
         "deps": attr.label_list(
             providers = [
                 [ProtoInfo],
-                ["proto"],
             ],
         ),
         "input": attr.label(
@@ -224,7 +223,6 @@
         "deps": attr.label_list(
             providers = [
                 [ProtoInfo],
-                ["proto"],
             ],
         ),
     },
diff --git a/third_party/mediapipe/src/mediapipe/framework/formats/BUILD b/third_party/mediapipe/src/mediapipe/framework/formats/BUILD
index 596f72f..3f68665 100644
--- a/third_party/mediapipe/src/mediapipe/framework/formats/BUILD
+++ b/third_party/mediapipe/src/mediapipe/framework/formats/BUILD
@@ -129,8 +129,8 @@
     hdrs = ["ahwb_view.h"],
     deps = [
         ":hardware_buffer",
+        ":shared_fd",
         "//mediapipe/framework:port",
-        "//mediapipe/framework/formats:shared_fd",
         "//mediapipe/gpu:gpu_buffer_storage",
     ],
 )
@@ -158,6 +158,39 @@
 )
 
 cc_library(
+    name = "ahwb_gpu_releaser",
+    srcs = ["ahwb_gpu_releaser.cc"],
+    hdrs = ["ahwb_gpu_releaser.h"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":hardware_buffer",
+        ":tensor_ahwb_usage",
+        "//mediapipe/framework:port",
+        "//mediapipe/framework/port:ret_check",
+        "//mediapipe/gpu:gl_base_hdr",
+        "//mediapipe/gpu:gl_context",
+        "@com_google_absl//absl/status",
+        "@com_google_absl//absl/synchronization",
+    ],
+)
+
+# Real device is required to test GLES31+ and Ahwb:
+# bazel build -c dbg --config=android_arm64 --android_ndk_min_sdk_version=33 --config=force_full_protos //mediapipe/framework/formats:ahwb_gpu_releaser_test && \
+# adb push bazel-bin/mediapipe/framework/formats/ahwb_gpu_releaser_test /data/local/tmp && \
+# adb shell "/data/local/tmp/ahwb_gpu_releaser_test"
+cc_test(
+    name = "ahwb_gpu_releaser_test",
+    srcs = ["ahwb_gpu_releaser_test.cc"],
+    deps = [
+        ":tensor",
+        "//mediapipe/framework/port:gtest",
+        "//mediapipe/gpu:gl_context",
+        "//mediapipe/gpu:gpu_service",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_library(
     name = "hardware_buffer",
     srcs = ["hardware_buffer_android.cc"],
     hdrs = ["hardware_buffer.h"],
@@ -591,49 +624,67 @@
         "@com_google_absl//absl/strings",
         "@com_google_absl//absl/synchronization",
     ] + select({
-        "//mediapipe/gpu:disable_gpu": [],
         "//mediapipe/gpu/webgpu:use_webgpu": [
-            "//mediapipe/gpu:gl_base",
-            "//mediapipe/gpu:gl_context",
             "//mediapipe/gpu/webgpu:webgpu_service",
             "//mediapipe/gpu/webgpu:webgpu_utils",
         ],
-        "//conditions:default": [
-            "//mediapipe/gpu:gl_base",
-            "//mediapipe/gpu:gl_context",
-        ],
         "//mediapipe:android": [
+            ":ahwb_gpu_releaser",
             ":hardware_buffer",
             ":hardware_buffer_pool",
+            ":shared_fd",
             ":tensor_ahwb_usage",
             ":unique_fd",
-            "//mediapipe/gpu:gl_base",
-            "//mediapipe/gpu:gl_context",
+            "//mediapipe/util:sync_wait",
+            "@com_google_absl//absl/base:log_severity",
+            "@com_google_absl//absl/time",
         ],
         ":android_link_native_window": [
+            ":ahwb_gpu_releaser",
             ":hardware_buffer",
             ":hardware_buffer_pool",
             ":tensor_ahwb_usage",
             ":unique_fd",
+        ],
+        "//conditions:default": [],
+    }) + select({
+        "//mediapipe/gpu:disable_gpu": [],
+        "//conditions:default": [
             "//mediapipe/gpu:gl_base",
             "//mediapipe/gpu:gl_context",
         ],
     }),
 )
 
+cc_library(
+    name = "tensor_fd_finished_func",
+    srcs = ["tensor_fd_finished_func.cc"],
+    hdrs = ["tensor_fd_finished_func.h"],
+    deps = [
+        ":shared_fd",
+        ":unique_fd",
+        "//mediapipe/util:sync_wait",
+        "@com_google_absl//absl/log:absl_log",
+        "@com_google_absl//absl/time",
+    ],
+)
+
 cc_test(
     name = "tensor_test",
     srcs = ["tensor_test.cc"],
     tags = [
-        "noasan",
-        "not_run:arm",  # TODO: Remove noasan tag when SwiftShader supports sanitizers
+        "angle",
+        "not_run:arm",
+        "requires-gpu-nvidia",
     ],
     deps = [
         ":tensor",
+        "//mediapipe/framework:port",
         "//mediapipe/framework/port:gtest_main",
     ] + select({
         "//conditions:default": [
             "//mediapipe/gpu:gl_calculator_helper",
+            "//mediapipe/gpu:gl_context",
             "//mediapipe/gpu:gpu_buffer_format",
         ],
         "//mediapipe/gpu:disable_gpu": [],
@@ -679,6 +730,33 @@
     ],
 )
 
+cc_library(
+    name = "tensor_opencv",
+    srcs = ["tensor_opencv.cc"],
+    hdrs = ["tensor_opencv.h"],
+    deps = [
+        ":tensor",
+        "//mediapipe/framework/port:opencv_core",
+        "//mediapipe/framework/port:ret_check",
+        "//mediapipe/framework/port:status",
+        "@com_google_absl//absl/log:absl_check",
+        "@com_google_absl//absl/status",
+        "@com_google_absl//absl/status:statusor",
+        "@com_google_absl//absl/strings",
+    ],
+)
+
+cc_test(
+    name = "tensor_opencv_test",
+    srcs = ["tensor_opencv_test.cc"],
+    deps = [
+        ":tensor",
+        ":tensor_opencv",
+        "//mediapipe/framework/port:gtest_main",
+        "@com_google_absl//absl/status",
+    ],
+)
+
 cc_test(
     name = "tensor_ahwb_usage_test",
     srcs = ["tensor_ahwb_usage_test.cc"],
diff --git a/third_party/mediapipe/src/mediapipe/framework/formats/ahwb_gpu_releaser.cc b/third_party/mediapipe/src/mediapipe/framework/formats/ahwb_gpu_releaser.cc
new file mode 100644
index 0000000..da0ca758
--- /dev/null
+++ b/third_party/mediapipe/src/mediapipe/framework/formats/ahwb_gpu_releaser.cc
@@ -0,0 +1,99 @@
+#include "mediapipe/framework/formats/ahwb_gpu_releaser.h"
+
+#include "mediapipe/framework/port.h"  // IWYU pragma: keep
+
+#if MEDIAPIPE_TENSOR_USE_AHWB
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include "mediapipe/framework/port/ret_check.h"
+#include "mediapipe/gpu/gl_base.h"
+
+namespace mediapipe {
+
+namespace {
+
+PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR;
+
+bool IsGlSupported() {
+  static const bool extensions_allowed = [] {
+    eglDestroySyncKHR = reinterpret_cast<PFNEGLDESTROYSYNCKHRPROC>(
+        eglGetProcAddress("eglDestroySyncKHR"));
+    return eglDestroySyncKHR;
+  }();
+  return extensions_allowed;
+}
+}  // namespace
+
+AhwbGpuReleaser::AhwbGpuResources::~AhwbGpuResources() {
+  CompleteAndEraseUsages(ahwb_usages_);
+}
+
+absl::Status AhwbGpuReleaser::AddAndFreeUnusedResources(
+    std::unique_ptr<AhwbGpuResources> ahwb_gpu_resources) {
+  RET_CHECK(IsGlSupported()) << "AHWB GPU releaser requires OpenGL support.";
+  std::deque<std::unique_ptr<AhwbGpuResources>> to_release_local;
+  using std::swap;
+
+  // IsSignaled will grab other mutexes, so we don't want to call it while
+  // holding the deque mutex.
+  {
+    absl::MutexLock lock(&mutex_);
+    swap(to_release_local, to_release_);
+  }
+
+  // Using `new` to access a non-public constructor.
+  to_release_local.emplace_back(std::move(ahwb_gpu_resources));
+  for (auto it = to_release_local.begin(); it != to_release_local.end();) {
+    if ((*it)->IsSignalled()) {
+      it = to_release_local.erase(it);
+    } else {
+      ++it;
+    }
+  }
+
+  {
+    absl::MutexLock lock(&mutex_);
+    to_release_.insert(to_release_.end(),
+                       std::make_move_iterator(to_release_local.begin()),
+                       std::make_move_iterator(to_release_local.end()));
+    to_release_local.clear();
+  }
+  return absl::OkStatus();
+}
+
+bool AhwbGpuReleaser::AhwbGpuResources::IsSignalled() {
+  if (!GlContext::IsAnyContextCurrent()) {
+    ABSL_LOG(DFATAL) << "Must be called on GPU thread.";
+  }
+
+  if (ssbo_read_ != nullptr) {
+    GLenum status = glClientWaitSync(ssbo_read_, 0,
+                                     /* timeout ns = */ 0);
+    if (status != GL_CONDITION_SATISFIED && status != GL_ALREADY_SIGNALED) {
+      return false;
+    }
+    glDeleteSync(ssbo_read_);
+    ssbo_read_ = nullptr;
+  }
+
+  if (HasIncompleteUsages(ahwb_usages_)) {
+    return false;
+  }
+
+  if (fence_sync_ != EGL_NO_SYNC_KHR && IsGlSupported()) {
+    auto egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    if (egl_display != EGL_NO_DISPLAY) {
+      eglDestroySyncKHR(egl_display, fence_sync_);
+    }
+    fence_sync_ = EGL_NO_SYNC_KHR;
+  }
+  glDeleteBuffers(1, &opengl_buffer_);
+  opengl_buffer_ = GL_INVALID_INDEX;
+  return true;
+}
+
+}  // namespace mediapipe
+
+#endif  // MEDIAPIPE_TENSOR_USE_AHWB
diff --git a/third_party/mediapipe/src/mediapipe/framework/formats/ahwb_gpu_releaser.h b/third_party/mediapipe/src/mediapipe/framework/formats/ahwb_gpu_releaser.h
new file mode 100644
index 0000000..c593a01
--- /dev/null
+++ b/third_party/mediapipe/src/mediapipe/framework/formats/ahwb_gpu_releaser.h
@@ -0,0 +1,93 @@
+#ifndef MEDIAPIPE_FRAMEWORK_FORMATS_HARDWARE_BUFFER_DELAYED_RELEASER_H_
+#define MEDIAPIPE_FRAMEWORK_FORMATS_HARDWARE_BUFFER_DELAYED_RELEASER_H_
+
+#include "mediapipe/framework/port.h"
+
+#if MEDIAPIPE_TENSOR_USE_AHWB
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <deque>
+#include <list>
+#include <memory>
+#include <utility>
+
+#include "absl/status/status.h"
+#include "absl/synchronization/mutex.h"
+#include "mediapipe/framework/formats/hardware_buffer.h"
+#include "mediapipe/framework/formats/tensor_ahwb_usage.h"
+#include "mediapipe/gpu/gl_base.h"
+#include "mediapipe/gpu/gl_context.h"
+
+namespace mediapipe {
+
+// This class keeps tensor's resources while the tensor is in use on GPU or TPU
+// but is already released on CPU. When a regular OpenGL buffer is bound to the
+// GPU queue for execution and released on client side then the buffer is still
+// not released because is being used by GPU. OpenGL driver keeps traking of
+// that. When OpenGL buffer is build on top of AHWB then the traking is done
+// with the DeleyedRelease which, actually, keeps record of all AHWBs allocated
+// and releases each of them if already used. EGL/GL fences are used to check
+// the status of a buffer.
+class AhwbGpuReleaser {
+ public:
+  // Note: This method must be called on GPU thread.
+  absl::Status AddAndFreeUnusedResources(
+      std::shared_ptr<HardwareBuffer> ahwb, GLuint opengl_buffer,
+      EGLSyncKHR fence_sync, GLsync ssbo_read,
+      std::list<TensorAhwbUsage>&& ahwb_usages) {
+    return AddAndFreeUnusedResources(std::make_unique<AhwbGpuResources>(
+        std::move(ahwb), opengl_buffer, fence_sync, ssbo_read,
+        std::move(ahwb_usages)));
+  }
+
+ private:
+  class AhwbGpuResources {
+   public:
+    AhwbGpuResources(std::shared_ptr<HardwareBuffer> ahwb, GLuint opengl_buffer,
+                     EGLSyncKHR fence_sync, GLsync ssbo_read,
+                     std::list<TensorAhwbUsage>&& ahwb_usages)
+        : ahwb_(std::move(ahwb)),
+          opengl_buffer_(opengl_buffer),
+          fence_sync_(fence_sync),
+          ssbo_read_(ssbo_read),
+          ahwb_usages_(std::move(ahwb_usages)) {}
+
+    // Destructor syncs on ahwb_usages
+    ~AhwbGpuResources();
+
+    // This method must be called on GPU thread.
+    bool IsSignalled();
+
+    // Non-copyable
+    AhwbGpuResources(const AhwbGpuResources&) = delete;
+    AhwbGpuResources& operator=(const AhwbGpuResources&) = delete;
+
+   private:
+    std::shared_ptr<HardwareBuffer> ahwb_;
+    GLuint opengl_buffer_;
+    // TODO: use wrapper instead.
+    EGLSyncKHR fence_sync_;
+    // TODO: use wrapper instead.
+    GLsync ssbo_read_;
+    std::list<TensorAhwbUsage> ahwb_usages_;
+  };
+
+  absl::Status AddAndFreeUnusedResources(
+      std::unique_ptr<AhwbGpuResources> ahwb_gpu_resources);
+
+  absl::Mutex mutex_;
+  std::deque<std::unique_ptr<AhwbGpuResources>> to_release_
+      ABSL_GUARDED_BY(mutex_);
+};
+
+inline constexpr GlContext::Attachment<AhwbGpuReleaser> kAhwbGpuReleaser(
+    [](GlContext&) -> GlContext::Attachment<AhwbGpuReleaser>::Ptr {
+      return GlContext::Attachment<AhwbGpuReleaser>::MakePtr();
+    });
+
+}  // namespace mediapipe
+
+#endif  // MEDIAPIPE_TENSOR_USE_AHWB
+
+#endif  // MEDIAPIPE_FRAMEWORK_FORMATS_HARDWARE_BUFFER_DELAYED_RELEASER_H_
diff --git a/third_party/mediapipe/src/mediapipe/framework/formats/motion/BUILD b/third_party/mediapipe/src/mediapipe/framework/formats/motion/BUILD
index 8f40202..5f39f79 100644
--- a/third_party/mediapipe/src/mediapipe/framework/formats/motion/BUILD
+++ b/third_party/mediapipe/src/mediapipe/framework/formats/motion/BUILD
@@ -61,7 +61,7 @@
         "//mediapipe/framework/formats:location_opencv",
         "//mediapipe/framework/port:file_helpers",
         "//mediapipe/framework/port:gtest_main",
-        "//mediapipe/framework/port:integral_types",
+        "//third_party:opencv",
         "@com_google_absl//absl/flags:flag",
         "@com_google_absl//absl/log:absl_check",
         "@com_google_absl//absl/log:absl_log",
diff --git a/third_party/mediapipe/src/mediapipe/framework/formats/tensor.cc b/third_party/mediapipe/src/mediapipe/framework/formats/tensor.cc
index f0f6aa9..f361148e 100644
--- a/third_party/mediapipe/src/mediapipe/framework/formats/tensor.cc
+++ b/third_party/mediapipe/src/mediapipe/framework/formats/tensor.cc
@@ -355,14 +355,6 @@
       << "Tensor conversion between different GPU backing formats is not "
          "supported yet.";
   auto lock(std::make_unique<absl::MutexLock>(&view_mutex_));
-  if ((valid_ & kValidOpenGlBuffer) && gl_context_ != nullptr &&
-      !gl_context_->IsCurrent() && GlContext::IsAnyContextCurrent()) {
-    ABSL_LOG_FIRST_N(WARNING, 1)
-        << "Tensor::GetOpenGlBufferReadView is not executed on the same GL "
-           "context where GL buffer was created. Note that Tensor has "
-           "limited synchronization support when sharing OpenGl objects "
-           "between multiple OpenGL contexts.";
-  }
   AllocateOpenGlBuffer();
   if (!(valid_ & kValidOpenGlBuffer)) {
     // If the call succeeds then AHWB -> SSBO are synchronized so any usage of
@@ -378,7 +370,8 @@
     }
     valid_ |= kValidOpenGlBuffer;
   }
-  return {opengl_buffer_, std::move(lock),
+
+  return {/*is_write_view=*/false, opengl_buffer_, std::move(lock),
 #ifdef MEDIAPIPE_TENSOR_USE_AHWB
           // ssbo_read_ is passed to be populated on OpenGlBufferView
           // destruction in order to perform delayed resources releasing (see
@@ -386,11 +379,11 @@
           //
           // Not passing for the case when AHWB is not in use to avoid creation
           // of unnecessary sync object and memory leak.
-          use_ahwb_ ? &ssbo_read_ : nullptr
+          use_ahwb_ ? &ssbo_read_ : nullptr,
 #else
-          nullptr
+          nullptr,
 #endif  // MEDIAPIPE_TENSOR_USE_AHWB
-  };
+          gl_context_.get(), &gl_write_read_sync_};
 }
 
 Tensor::OpenGlBufferView Tensor::GetOpenGlBufferWriteView(
@@ -413,12 +406,17 @@
            "behavior due to lack of synchronization.";
   }
   valid_ = kValidOpenGlBuffer;
-  return {opengl_buffer_, std::move(lock), nullptr};
+  return {/*is_write_view=*/true, opengl_buffer_,
+          std::move(lock),
+          /*ssbo_read=*/nullptr,  gl_context_.get(),
+          &gl_write_read_sync_};
 }
 
 void Tensor::AllocateOpenGlBuffer() const {
   if (opengl_buffer_ == GL_INVALID_INDEX) {
-    gl_context_ = mediapipe::GlContext::GetCurrent();
+    if (gl_context_ == nullptr) {
+      gl_context_ = mediapipe::GlContext::GetCurrent();
+    }
     ABSL_LOG_IF(FATAL, !gl_context_) << "GlContext is not bound to the thread.";
     glGenBuffers(1, &opengl_buffer_);
     glBindBuffer(GL_SHADER_STORAGE_BUFFER, opengl_buffer_);
@@ -432,14 +430,14 @@
 
 Tensor& Tensor::operator=(Tensor&& src) {
   if (this != &src) {
-    Invalidate();
+    ABSL_CHECK_OK(Invalidate());
     Move(&src);
   }
   return *this;
 }
 
 Tensor::Tensor(Tensor&& src) { Move(&src); }
-Tensor::~Tensor() { Invalidate(); }
+Tensor::~Tensor() { ABSL_CHECK_OK(Invalidate()); }
 
 void Tensor::Move(Tensor* src) {
   valid_ = src->valid_;
@@ -465,6 +463,7 @@
 #if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
   opengl_buffer_ = src->opengl_buffer_;
   src->opengl_buffer_ = GL_INVALID_INDEX;
+  gl_write_read_sync_ = std::move(src->gl_write_read_sync_);
 #endif  // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
 #endif  // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_30
 
@@ -502,7 +501,7 @@
 }
 
 #if MEDIAPIPE_METAL_ENABLED
-void Tensor::Invalidate() {
+absl::Status Tensor::Invalidate() {
 #if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_30
   GLuint cleanup_gl_tex = GL_INVALID_INDEX;
   GLuint cleanup_gl_fb = GL_INVALID_INDEX;
@@ -538,11 +537,12 @@
     });
   }
 #endif  // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_30
+  return absl::OkStatus();
 }
 
 #else
 
-void Tensor::Invalidate() {
+absl::Status Tensor::Invalidate() {
 #if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_30
   GLuint cleanup_gl_tex = GL_INVALID_INDEX;
   GLuint cleanup_gl_fb = GL_INVALID_INDEX;
@@ -552,7 +552,7 @@
 #endif  // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_30
   {
     absl::MutexLock lock(&view_mutex_);
-    ReleaseAhwbStuff();
+    MP_RETURN_IF_ERROR(ReleaseAhwbStuff());
 
     // Don't need to wait for the resource to be deleted because if will be
     // released on last reference deletion inside the OpenGL driver.
@@ -589,6 +589,7 @@
   if (webgpu_texture2d_) webgpu_texture2d_.Destroy();
 #endif  // MEDIAPIPE_USE_WEBGPU
   FreeCpuBuffer();
+  return absl::OkStatus();
 }
 #endif  // MEDIAPIPE_METAL_ENABLED
 
diff --git a/third_party/mediapipe/src/mediapipe/framework/formats/tensor.h b/third_party/mediapipe/src/mediapipe/framework/formats/tensor.h
index 1afd3847..081ef25 100644
--- a/third_party/mediapipe/src/mediapipe/framework/formats/tensor.h
+++ b/third_party/mediapipe/src/mediapipe/framework/formats/tensor.h
@@ -352,28 +352,84 @@
     GLuint name() const { return name_; }
 
     OpenGlBufferView(OpenGlBufferView&& src) : View(std::move(src.lock_)) {
+      is_write_view_ = src.is_write_view_;
       name_ = std::exchange(src.name_, GL_INVALID_INDEX);
       ssbo_read_ = std::exchange(src.ssbo_read_, nullptr);
+      gl_context_ = std::exchange(src.gl_context_, nullptr);
+      gl_write_read_sync_ = std::exchange(src.gl_write_read_sync_, nullptr);
     }
+
     ~OpenGlBufferView() {
-      if (ssbo_read_) {
-        // TODO: update tensor to properly handle cases when
-        // multiple views were requested multiple sync fence may be needed.
-        *ssbo_read_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+      if (!is_write_view_) {
+        // Read view destruction.
+        if (ssbo_read_) {
+          // TODO: update tensor to properly handle cases when
+          // multiple views were requested multiple sync fence may be needed.
+          *ssbo_read_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+        }
+      } else {
+        if (gl_write_read_sync_ != nullptr && gl_context_ != nullptr) {
+          *gl_write_read_sync_ = gl_context_->CreateSyncToken();
+        }
       }
     }
 
    protected:
     friend class Tensor;
 
-    OpenGlBufferView(GLuint name, std::unique_ptr<absl::MutexLock>&& lock,
-                     GLsync* ssbo_read)
-        : View(std::move(lock)), name_(name), ssbo_read_(ssbo_read) {}
+    // NOTE: Update move constructor if adding params.
+    OpenGlBufferView(bool is_write_view, GLuint name,
+                     std::unique_ptr<absl::MutexLock>&& lock, GLsync* ssbo_read,
+                     GlContext* gl_context,
+                     std::shared_ptr<GlSyncPoint>* gl_write_read_sync)
+        : View(std::move(lock)),
+          is_write_view_(is_write_view),
+          name_(name),
+          ssbo_read_(ssbo_read),
+          gl_context_(gl_context),
+          gl_write_read_sync_(gl_write_read_sync) {
+      if (!is_write_view) {
+        MaybeWaitForWrites();
+      }
+    }
+
+    void MaybeWaitForWrites() {
+      if (gl_context_->IsCurrent()) {
+        // Sync is not needed if the view is requested on the same context where
+        // the write view was requested.
+        return;
+      }
+      if (GlContext::IsAnyContextCurrent() && *gl_write_read_sync_ != nullptr) {
+        // In case the read view is requested on a different context than the
+        // one where the write view was requested, we need to wait for the
+        // write sync point to be reached.
+        (*gl_write_read_sync_)->WaitOnGpu();
+        gl_write_read_sync_->reset();
+      }
+    }
+
+    bool is_write_view_;
     GLuint name_;
     GLsync* ssbo_read_;
+    GlContext* gl_context_;
+    std::shared_ptr<GlSyncPoint>* gl_write_read_sync_;
   };
   // A valid OpenGL context must be bound to the calling thread due to possible
   // GPU resource allocation.
+  // Notes on (multi-context) GL synchronization:
+  // 1. GetOpenGlBufferWriteView returns a view that creates a GlSync fence
+  //    object during its destruction.
+  // 2. If the read view is requested on the same context where the write view
+  //    was requested, no GL fence synchronization is needed and the write
+  //    fence object is ignored.
+  // 3. If the read view is requested on a different context than the one where
+  //    the write view was requested, GetOpenGLBufferReadView will wait (on GPU)
+  //    for the sync point created during write view destruction.
+  // 4. A memory barrier is needed when operating on GL buffers to ensure that
+  //    the write operations are visible to subsequent read operations (even on
+  //    the same context) - GL fence synchronization is not enough. GL buffer
+  //    memory barriers are currentlyh NOT manged by the Tensor class and must
+  //    be handled externally.
   OpenGlBufferView GetOpenGlBufferReadView() const;
   OpenGlBufferView GetOpenGlBufferWriteView(
       uint64_t source_location_hash =
@@ -432,7 +488,7 @@
  private:
   friend class MtlBufferView;
   void Move(Tensor*);
-  void Invalidate();
+  absl::Status Invalidate();
   absl::Status ReadBackGpuToCpu() const;
 
   ElementType element_type_;
@@ -502,7 +558,7 @@
   bool AllocateAhwbMapToSsbo() const;
   bool InsertAhwbToSsboFence() const;
   void MoveAhwbStuff(Tensor* src);
-  void ReleaseAhwbStuff();
+  absl::Status ReleaseAhwbStuff();
   void* MapAhwbToCpuRead() const;
   void* MapAhwbToCpuWrite() const;
   void MoveCpuOrSsboToAhwb() const;
@@ -522,6 +578,7 @@
 #if MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
   mutable GLuint opengl_buffer_ = GL_INVALID_INDEX;
   void AllocateOpenGlBuffer() const;
+  mutable std::shared_ptr<GlSyncPoint> gl_write_read_sync_;
 #endif  // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
   bool NeedsHalfFloatRenderTarget() const;
 #endif  // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_30
diff --git a/third_party/mediapipe/src/mediapipe/framework/formats/tensor_ahwb.cc b/third_party/mediapipe/src/mediapipe/framework/formats/tensor_ahwb.cc
index 111b140..022c3c8 100644
--- a/third_party/mediapipe/src/mediapipe/framework/formats/tensor_ahwb.cc
+++ b/third_party/mediapipe/src/mediapipe/framework/formats/tensor_ahwb.cc
@@ -1,3 +1,4 @@
+#include "absl/status/status.h"
 #include "mediapipe/framework/formats/tensor.h"
 
 #ifdef MEDIAPIPE_TENSOR_USE_AHWB
@@ -10,11 +11,13 @@
 #include <vector>
 
 #include "absl/base/const_init.h"
+#include "absl/base/log_severity.h"
 #include "absl/functional/any_invocable.h"
 #include "absl/log/absl_check.h"
 #include "absl/log/absl_log.h"
 #include "absl/synchronization/mutex.h"
 #include "mediapipe/framework/deps/no_destructor.h"
+#include "mediapipe/framework/formats/ahwb_gpu_releaser.h"
 #include "mediapipe/framework/formats/hardware_buffer.h"
 #include "mediapipe/gpu/gl_base.h"
 #endif  // MEDIAPIPE_TENSOR_USE_AHWB
@@ -85,119 +88,6 @@
   return ((value - 1) | (alignment - 1)) + 1;
 }
 
-// This class keeps tensor's resources while the tensor is in use on GPU or TPU
-// but is already released on CPU. When a regular OpenGL buffer is bound to the
-// GPU queue for execution and released on client side then the buffer is still
-// not released because is being used by GPU. OpenGL driver keeps traking of
-// that. When OpenGL buffer is build on top of AHWB then the traking is done
-// with the DeleyedRelease which, actually, keeps record of all AHWBs allocated
-// and releases each of them if already used. EGL/GL fences are used to check
-// the status of a buffer.
-class DelayedReleaser {
- public:
-  // Non-copyable
-  DelayedReleaser(const DelayedReleaser&) = delete;
-  DelayedReleaser& operator=(const DelayedReleaser&) = delete;
-  // Non-movable
-  DelayedReleaser(DelayedReleaser&&) = delete;
-  DelayedReleaser& operator=(DelayedReleaser&&) = delete;
-
-  static void Add(std::shared_ptr<HardwareBuffer> ahwb, GLuint opengl_buffer,
-                  EGLSyncKHR ssbo_sync, GLsync ssbo_read,
-                  std::list<TensorAhwbUsage>&& ahwb_usages,
-                  std::shared_ptr<mediapipe::GlContext> gl_context) {
-    static absl::Mutex mutex;
-    std::deque<std::unique_ptr<DelayedReleaser>> to_release_local;
-    using std::swap;
-
-    // IsSignaled will grab other mutexes, so we don't want to call it while
-    // holding the deque mutex.
-    {
-      absl::MutexLock lock(&mutex);
-      swap(to_release_local, *to_release_);
-    }
-
-    // Using `new` to access a non-public constructor.
-    to_release_local.emplace_back(absl::WrapUnique(
-        new DelayedReleaser(std::move(ahwb), opengl_buffer, ssbo_sync,
-                            ssbo_read, std::move(ahwb_usages), gl_context)));
-    for (auto it = to_release_local.begin(); it != to_release_local.end();) {
-      if ((*it)->IsSignaled()) {
-        it = to_release_local.erase(it);
-      } else {
-        ++it;
-      }
-    }
-
-    {
-      absl::MutexLock lock(&mutex);
-      to_release_->insert(to_release_->end(),
-                          std::make_move_iterator(to_release_local.begin()),
-                          std::make_move_iterator(to_release_local.end()));
-      to_release_local.clear();
-    }
-  }
-
-  ~DelayedReleaser() { CompleteAndEraseUsages(ahwb_usages_); }
-
-  bool IsSignaled() {
-    bool ready = !HasIncompleteUsages(ahwb_usages_);
-
-    if (ssbo_read_ != 0) {
-      gl_context_->Run([this, &ready]() {
-        GLenum status = glClientWaitSync(ssbo_read_, 0,
-                                         /* timeout ns = */ 0);
-        if (status != GL_CONDITION_SATISFIED && status != GL_ALREADY_SIGNALED) {
-          ready = false;
-          return;
-        }
-        glDeleteSync(ssbo_read_);
-        ssbo_read_ = 0;
-      });
-    }
-
-    if (ready && gl_context_) {
-      gl_context_->Run([this]() {
-        if (fence_sync_ != EGL_NO_SYNC_KHR && IsGlSupported()) {
-          auto egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-          if (egl_display != EGL_NO_DISPLAY) {
-            eglDestroySyncKHR(egl_display, fence_sync_);
-          }
-          fence_sync_ = EGL_NO_SYNC_KHR;
-        }
-        glDeleteBuffers(1, &opengl_buffer_);
-        opengl_buffer_ = GL_INVALID_INDEX;
-      });
-    }
-
-    return ready;
-  }
-
- protected:
-  std::shared_ptr<HardwareBuffer> ahwb_;
-  GLuint opengl_buffer_;
-  // TODO: use wrapper instead.
-  EGLSyncKHR fence_sync_;
-  // TODO: use wrapper instead.
-  GLsync ssbo_read_;
-  std::list<TensorAhwbUsage> ahwb_usages_;
-  std::shared_ptr<mediapipe::GlContext> gl_context_;
-
-  static inline NoDestructor<std::deque<std::unique_ptr<DelayedReleaser>>>
-      to_release_;
-
-  DelayedReleaser(std::shared_ptr<HardwareBuffer> ahwb, GLuint opengl_buffer,
-                  EGLSyncKHR fence_sync, GLsync ssbo_read,
-                  std::list<TensorAhwbUsage>&& ahwb_usages,
-                  std::shared_ptr<mediapipe::GlContext> gl_context)
-      : ahwb_(std::move(ahwb)),
-        opengl_buffer_(opengl_buffer),
-        fence_sync_(fence_sync),
-        ssbo_read_(ssbo_read),
-        ahwb_usages_(std::move(ahwb_usages)),
-        gl_context_(gl_context) {}
-};
-
 class AhwbUsageTrack {
  public:
   static void Insert(uint64_t id) {
@@ -419,14 +309,25 @@
   use_ahwb_ = std::exchange(src->use_ahwb_, false);
 }
 
-void Tensor::ReleaseAhwbStuff() {
+absl::Status Tensor::ReleaseAhwbStuff() {
   write_complete_fence_fd_.Reset();
   if (__builtin_available(android 26, *)) {
     if (ahwb_) {
-      if (ssbo_read_ != 0 || fence_sync_ != EGL_NO_SYNC_KHR ||
-          HasIncompleteUsages(ahwb_usages_)) {
-        DelayedReleaser::Add(std::move(ahwb_), opengl_buffer_, fence_sync_,
-                             ssbo_read_, std::move(ahwb_usages_), gl_context_);
+      const bool gl_operation_maybe_pending =
+          ssbo_read_ != 0 || fence_sync_ != EGL_NO_SYNC_KHR;
+      if (gl_operation_maybe_pending && gl_context_ == nullptr) {
+        ABSL_LOG(DFATAL)
+            << "Pending GL operations without captured GL context.";
+      }
+      if ((gl_operation_maybe_pending || HasIncompleteUsages(ahwb_usages_)) &&
+          gl_context_ != nullptr) {
+        // Delay release until the GPU usage is finished.
+        MP_RETURN_IF_ERROR(gl_context_->Run([this]() -> absl::Status {
+          auto& releaser = gl_context_->GetCachedAttachment(kAhwbGpuReleaser);
+          return releaser.AddAndFreeUnusedResources(ahwb_, opengl_buffer_,
+                                                    fence_sync_, ssbo_read_,
+                                                    std::move(ahwb_usages_));
+        }));
         opengl_buffer_ = GL_INVALID_INDEX;
       } else {
         CompleteAndEraseUsages(ahwb_usages_);
@@ -434,6 +335,7 @@
       }
     }
   }
+  return absl::OkStatus();
 }
 
 void* Tensor::MapAhwbToCpuRead() const {
@@ -492,7 +394,7 @@
 bool Tensor::AllocateAhwbMapToSsbo() const { return false; }
 bool Tensor::InsertAhwbToSsboFence() const { return false; }
 void Tensor::MoveAhwbStuff(Tensor* src) {}
-void Tensor::ReleaseAhwbStuff() {}
+absl::Status Tensor::ReleaseAhwbStuff() { return absl::OkStatus(); }
 void* Tensor::MapAhwbToCpuRead() const { return nullptr; }
 void* Tensor::MapAhwbToCpuWrite() const { return nullptr; }
 void Tensor::TrackAhwbUsage(uint64_t key) const {}
diff --git a/third_party/mediapipe/src/mediapipe/framework/formats/tensor_fd_finished_func.cc b/third_party/mediapipe/src/mediapipe/framework/formats/tensor_fd_finished_func.cc
new file mode 100644
index 0000000..87753c5
--- /dev/null
+++ b/third_party/mediapipe/src/mediapipe/framework/formats/tensor_fd_finished_func.cc
@@ -0,0 +1,46 @@
+#include "mediapipe/framework/formats/tensor_fd_finished_func.h"
+
+#include "absl/log/absl_log.h"
+#include "absl/time/time.h"
+#include "mediapipe/framework/formats/shared_fd.h"
+#include "mediapipe/util/sync_wait.h"
+
+namespace mediapipe {
+namespace {
+
+inline bool IsFinished(bool wait, const SharedFd& fd) {
+  const auto is_signaled = IsSignaled(fd);
+  if (!is_signaled.ok()) {
+    ABSL_LOG(ERROR) << is_signaled.status();
+    return false;
+  }
+  if (!wait) {
+    return *is_signaled;
+  }
+
+  if (*is_signaled) {
+    return true;
+  }
+
+  auto status = SyncWait(fd, absl::InfiniteDuration());
+  if (!status.ok()) {
+    ABSL_LOG(ERROR) << status;
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+bool FdFinishedFunc::operator()(bool wait) { return IsFinished(wait, fd_); }
+
+bool MultipleFdsFinishedFunc::operator()(bool wait) {
+  for (const auto& fd : fds_) {
+    if (!IsFinished(wait, fd)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+}  // namespace mediapipe
diff --git a/third_party/mediapipe/src/mediapipe/framework/formats/tensor_fd_finished_func.h b/third_party/mediapipe/src/mediapipe/framework/formats/tensor_fd_finished_func.h
new file mode 100644
index 0000000..c297b5c8
--- /dev/null
+++ b/third_party/mediapipe/src/mediapipe/framework/formats/tensor_fd_finished_func.h
@@ -0,0 +1,36 @@
+#ifndef MEDIAPIPE_FRAMEWORK_FORMATS_TENSOR_FD_FINISHED_FUNC_H_
+#define MEDIAPIPE_FRAMEWORK_FORMATS_TENSOR_FD_FINISHED_FUNC_H_
+
+#include <utility>
+#include <vector>
+
+#include "mediapipe/framework/formats/shared_fd.h"
+
+namespace mediapipe {
+// Funcs below to be used by Tensor::SetWritingFinishedFD and
+// Tensor::SetReadingFinishedFunc.
+class FdFinishedFunc {
+ public:
+  explicit FdFinishedFunc(SharedFd fd) : fd_(std::move(fd)) {}
+
+  bool operator()(bool wait);
+
+ private:
+  // SharedFd to support copy construction required by std::function.
+  SharedFd fd_;
+};
+
+class MultipleFdsFinishedFunc {
+ public:
+  explicit MultipleFdsFinishedFunc(std::vector<SharedFd> fds)
+      : fds_(std::move(fds)) {}
+
+  bool operator()(bool wait);
+
+ private:
+  std::vector<SharedFd> fds_;
+};
+
+}  // namespace mediapipe
+
+#endif  // MEDIAPIPE_FRAMEWORK_FORMATS_TENSOR_FD_FINISHED_FUNC_H_
diff --git a/third_party/mediapipe/src/mediapipe/framework/formats/tensor_opencv.cc b/third_party/mediapipe/src/mediapipe/framework/formats/tensor_opencv.cc
new file mode 100644
index 0000000..6cf02d8
--- /dev/null
+++ b/third_party/mediapipe/src/mediapipe/framework/formats/tensor_opencv.cc
@@ -0,0 +1,116 @@
+// Copyright 2022 The MediaPipe Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "mediapipe/framework/formats/tensor_opencv.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+#include "absl/log/absl_check.h"
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/str_cat.h"
+#include "mediapipe/framework/formats/tensor.h"
+#include "mediapipe/framework/port/opencv_core_inc.h"
+#include "mediapipe/framework/port/ret_check.h"
+#include "mediapipe/framework/port/status_macros.h"
+
+namespace mediapipe::formats {
+namespace {
+
+// Maps the Tensor element type to OpenCV Mat type.
+absl::StatusOr<int> GetMatType(Tensor::ElementType element_type, int channels) {
+  switch (element_type) {
+    case Tensor::ElementType::kFloat32:
+      return CV_32FC(channels);
+    case Tensor::ElementType::kUInt8:
+      return CV_8UC(channels);
+    case Tensor::ElementType::kInt8:
+      return CV_8SC(channels);
+    case Tensor::ElementType::kInt32:
+      return CV_32SC(channels);
+    case Tensor::ElementType::kChar:
+      return CV_8SC(channels);
+    case Tensor::ElementType::kBool:
+      return CV_8UC(channels);
+    default:
+      return absl::InvalidArgumentError(absl::StrCat(
+          "Unsupported Tensor element type: ", static_cast<int>(element_type)));
+  }
+}
+
+}  // namespace
+
+absl::StatusOr<cv::Mat> MatView(const Tensor& tensor,
+                                const Tensor::CpuReadView& view,
+                                std::vector<int> slice) {
+  // By default, don't slice.
+  if (slice.empty()) {
+    slice.insert(slice.end(), tensor.shape().dims.size(), -1);
+  }
+
+  RET_CHECK_EQ(slice.size(), tensor.shape().dims.size())
+          .SetCode(absl::StatusCode::kInvalidArgument)
+      << "Slice must have the same number of elements as the number of "
+         "dimensions in the tensor.";
+
+  // Unfortunately, OpenCV does not support slicing in the last dimension. The
+  // last dimension always has to be consecutive.
+  RET_CHECK_EQ(slice.back(), -1).SetCode(absl::StatusCode::kInvalidArgument)
+      << "cv::Mat does not support slicing the last dimension.";
+
+  // The mat dimensions is determined by the number of -1s in the slice.
+  int num_mat_dims = std::count(slice.begin(), slice.end(), -1);
+
+  // Compute the offset and strides for the sliced mat.
+  int offset = 0;
+  std::vector<int> mat_dims(num_mat_dims);
+  std::vector<size_t> mat_steps(num_mat_dims);
+  int curr_mat_dim = num_mat_dims - 1;
+  int curr_stride = tensor.element_size();
+  for (int n = tensor.shape().dims.size() - 1; n >= 0; --n) {
+    if (slice[n] == -1) {
+      // Create an additional mat dimension.
+      mat_dims[curr_mat_dim] = tensor.shape().dims[n];
+      mat_steps[curr_mat_dim] = curr_stride;
+      curr_mat_dim--;
+    } else {
+      // Address a fixed position in this dimension.
+      if (slice[n] < 0 || slice[n] >= tensor.shape().dims[n]) {
+        return absl::InvalidArgumentError(
+            absl::StrCat("Slice ", slice[n], " is out of bounds for dimension ",
+                         n, " of shape ", tensor.shape().dims[n]));
+      }
+      offset += slice[n] * curr_stride;
+    }
+    curr_stride *= tensor.shape().dims[n];
+  }
+
+  // The last mat dimension is technically not a dimension, but rather the
+  // number of channels.
+  ABSL_CHECK(!mat_dims.empty() && !mat_steps.empty());
+  int mat_channels = mat_channels = mat_dims.back();
+  mat_dims.pop_back();
+  mat_steps.pop_back();
+
+  MP_ASSIGN_OR_RETURN(int mat_type,
+                      GetMatType(tensor.element_type(), mat_channels));
+  uint8_t* mat_buffer = const_cast<uint8_t*>(view.buffer<uint8_t>() + offset);
+  return cv::Mat(mat_dims.size(), mat_dims.data(), mat_type, mat_buffer,
+                 mat_steps.data());
+}
+
+}  // namespace mediapipe::formats
diff --git a/third_party/mediapipe/src/mediapipe/framework/formats/tensor_opencv.h b/third_party/mediapipe/src/mediapipe/framework/formats/tensor_opencv.h
new file mode 100644
index 0000000..684f79c5
--- /dev/null
+++ b/third_party/mediapipe/src/mediapipe/framework/formats/tensor_opencv.h
@@ -0,0 +1,58 @@
+// Copyright 2025 The MediaPipe Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Helper functions for working with ImageFrame and OpenCV.
+#ifndef MEDIAPIPE_FRAMEWORK_FORMATS_TENSOR_OPENCV_H_
+#define MEDIAPIPE_FRAMEWORK_FORMATS_TENSOR_OPENCV_H_
+
+#include <vector>
+
+#include "absl/status/statusor.h"
+#include "mediapipe/framework/formats/tensor.h"
+#include "mediapipe/framework/port/opencv_core_inc.h"
+
+namespace mediapipe::formats {
+
+// Creates a cv::Mat view into a Tensor (zero copy).
+// The passed read view needs to outlive the returned cv::Mat.
+//
+// If slice is specified, the view is sliced by the specified dimensions. A
+// value of -1 means the full dimension is used. For instance, if the tensor
+// has shape [2, 64, 128, 3] and slice is [1, -1, -1, 3], the mat will have
+// dims [64, 128] and will contain the Tensor[1, :, :, 3]]. If set, slice must
+// have the same number of elements as the number of dimensions in the tensor.
+//
+// When converting a const Tensor into a cv::Mat, the const modifier is lost.
+// The caller must be careful not to use the returned object to modify the
+// data in a const Tensor, even though the returned data is mutable.
+//
+// Usage:
+//   Tensor tensor = ... tensor of shape [10, 20, 3] ...;
+//   MP_ASSIGN_OR_RETURN(TensorMatView view, TensorMatView::Create(tensor));
+//   // view.mat is a view into the data in tensor with 2 dims and 3 channels.
+//   // view.mat.data points into tensor.GetCpuReadView().buffer<T>().
+absl::StatusOr<cv::Mat> MatView(const Tensor& tensor,
+                                const Tensor::CpuReadView& view,
+                                std::vector<int> slice = {});
+
+// Prevent passing in the view as an rvalue reference, e.g.
+// MatView(tensor, tensor.GetCpuReadView());
+// The view needs to stay in scope while the mat is in scope.
+absl::StatusOr<cv::Mat> MatView(const Tensor& tensor,
+                                Tensor::CpuReadView&& view,
+                                std::vector<int> slice = {}) = delete;
+
+}  // namespace mediapipe::formats
+
+#endif  // MEDIAPIPE_FRAMEWORK_FORMATS_IMAGE_FRAME_OPENCV_H_
diff --git a/third_party/mediapipe/src/mediapipe/framework/graph_runtime_info.proto b/third_party/mediapipe/src/mediapipe/framework/graph_runtime_info.proto
index 1488a33..ad278549 100644
--- a/third_party/mediapipe/src/mediapipe/framework/graph_runtime_info.proto
+++ b/third_party/mediapipe/src/mediapipe/framework/graph_runtime_info.proto
@@ -20,7 +20,7 @@
 option java_outer_classname = "GraphRuntimeInfoProto";
 
 // The runtime info for an input stream.
-message StreamRuntimeInfo {
+message InputStreamRuntimeInfo {
   // The name of the stream in the format "TAG:index:stream_name"
   string stream_name = 1;
 
@@ -34,6 +34,18 @@
   int64 minimum_timestamp_or_bound = 4;
 }
 
+// The runtime info for an output stream.
+message OutputStreamRuntimeInfo {
+  // The name of the stream in the format "TAG:index:stream_name"
+  string stream_name = 1;
+
+  // The total number of packets added to the queue.
+  int32 number_of_packets_added = 2;
+
+  // The minimum timestamp or timestanp bound of the stream.
+  int64 minimum_timestamp_or_bound = 3;
+}
+
 // The runtime info for a calculator.
 message CalculatorRuntimeInfo {
   // The name of the calculator.
@@ -49,7 +61,10 @@
   int64 timestamp_bound = 4;
 
   // The runtime info for each input stream of the calculator.
-  repeated StreamRuntimeInfo input_stream_infos = 5;
+  repeated InputStreamRuntimeInfo input_stream_infos = 5;
+
+  // The runtime info for each output stream of the calculator.
+  repeated OutputStreamRuntimeInfo output_stream_infos = 6;
 }
 
 // The runtime info for the whole graph.
diff --git a/third_party/mediapipe/src/mediapipe/framework/graph_service_manager.cc b/third_party/mediapipe/src/mediapipe/framework/graph_service_manager.cc
index 90b637a..01625b5 100644
--- a/third_party/mediapipe/src/mediapipe/framework/graph_service_manager.cc
+++ b/third_party/mediapipe/src/mediapipe/framework/graph_service_manager.cc
@@ -5,12 +5,15 @@
 #include "absl/status/status.h"
 #include "mediapipe/framework/graph_service.h"
 #include "mediapipe/framework/packet.h"
+#include "mediapipe/framework/port/ret_check.h"
 
 namespace mediapipe {
 
 absl::Status GraphServiceManager::SetServicePacket(
     const GraphServiceBase& service, Packet p) {
   // TODO: check service is already set?
+  RET_CHECK(!p.IsEmpty()) << "SetServicePacket called for " << service.key
+                          << " with empty Packet.";
   service_packets_[service.key] = std::move(p);
   return absl::OkStatus();
 }
diff --git a/third_party/mediapipe/src/mediapipe/framework/graph_service_manager.h b/third_party/mediapipe/src/mediapipe/framework/graph_service_manager.h
index b78a4cf..b9ace492 100644
--- a/third_party/mediapipe/src/mediapipe/framework/graph_service_manager.h
+++ b/third_party/mediapipe/src/mediapipe/framework/graph_service_manager.h
@@ -4,44 +4,46 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <utility>
 
+#include "absl/log/absl_check.h"
 #include "absl/status/status.h"
 #include "mediapipe/framework/graph_service.h"
 #include "mediapipe/framework/packet.h"
+#include "mediapipe/framework/port/ret_check.h"
 
 namespace mediapipe {
 
 class GraphServiceManager {
  public:
-  GraphServiceManager() = default;
-
-  explicit GraphServiceManager(
-      const GraphServiceManager* external_graph_manager) {
-    if (external_graph_manager != nullptr) {
-      // Nested graphs inherit all graph services from their parent graph and
-      // disable the registration of new services in the nested graph. This
-      // ensures that all services are created during the initialization of
-      // parent graph.
-      service_packets_ = external_graph_manager->ServicePackets();
-    }
-  }
-
   using ServiceMap = std::map<std::string, Packet>;
 
+  GraphServiceManager() = default;
+
   template <typename T>
   absl::Status SetServiceObject(const GraphService<T>& service,
                                 std::shared_ptr<T> object) {
+    RET_CHECK(object != nullptr) << "SetServiceObject called for "
+                                 << service.key << " with empty shared_ptr.";
     return SetServicePacket(service,
                             MakePacket<std::shared_ptr<T>>(std::move(object)));
   }
 
   absl::Status SetServicePacket(const GraphServiceBase& service, Packet p);
 
+  void SetServicePackets(const ServiceMap& service_packets) {
+    service_packets_ = service_packets;
+  }
+
   template <typename T>
   std::shared_ptr<T> GetServiceObject(const GraphService<T>& service) const {
     Packet p = GetServicePacket(service);
     if (p.IsEmpty()) return nullptr;
-    return p.Get<std::shared_ptr<T>>();
+    auto ptr = p.Get<std::shared_ptr<T>>();
+    ABSL_CHECK(ptr != nullptr)
+        << "GraphService " << service.key << " is not set (empty shared_ptr).";
+
+    return ptr;
   }
   const ServiceMap& ServicePackets() const { return service_packets_; }
 
diff --git a/third_party/mediapipe/src/mediapipe/framework/output_stream_handler.cc b/third_party/mediapipe/src/mediapipe/framework/output_stream_handler.cc
index 377de6c..e27d1c6 100644
--- a/third_party/mediapipe/src/mediapipe/framework/output_stream_handler.cc
+++ b/third_party/mediapipe/src/mediapipe/framework/output_stream_handler.cc
@@ -14,7 +14,12 @@
 
 #include "mediapipe/framework/output_stream_handler.h"
 
+#include <string>
+#include <vector>
+
 #include "absl/log/absl_check.h"
+#include "absl/status/status.h"
+#include "absl/strings/str_cat.h"
 #include "absl/synchronization/mutex.h"
 #include "mediapipe/framework/collection_item_id.h"
 #include "mediapipe/framework/output_stream_shard.h"
@@ -121,6 +126,30 @@
   return (*output_stream_managers_.begin())->Name();
 }
 
+std::string OutputStreamHandler::DebugStreamName(CollectionItemId id) const {
+  const auto tag_map = output_stream_managers_.TagMap();
+  const std::string& stream_name = tag_map->Names()[id.value()];
+  const auto& [stream_tag, stream_idx] = tag_map->TagAndIndexFromId(id);
+  return absl::StrCat(stream_tag, ":", stream_idx, ":", stream_name);
+}
+
+std::vector<OutputStreamHandler::OutputStreamMonitoringInfo>
+OutputStreamHandler::GetMonitoringInfo() {
+  std::vector<OutputStreamMonitoringInfo> monitoring_info_vector;
+  for (CollectionItemId id = output_stream_managers_.BeginId();
+       id < output_stream_managers_.EndId(); ++id) {
+    const auto& stream = output_stream_managers_.Get(id);
+    if (!stream) {
+      continue;
+    }
+    monitoring_info_vector.emplace_back(OutputStreamMonitoringInfo(
+        {.stream_name = DebugStreamName(id),
+         .num_packets_added = stream->NumPacketsAdded(),
+         .next_timestamp_bound = stream->NextTimestampBound()}));
+  }
+  return monitoring_info_vector;
+}
+
 void OutputStreamHandler::TryPropagateTimestampBound(Timestamp input_bound) {
   // TODO Some non-range values, such as PostStream(), should also be
   // propagated.
diff --git a/third_party/mediapipe/src/mediapipe/framework/output_stream_handler.h b/third_party/mediapipe/src/mediapipe/framework/output_stream_handler.h
index 7d2c3983..e6dd8d2 100644
--- a/third_party/mediapipe/src/mediapipe/framework/output_stream_handler.h
+++ b/third_party/mediapipe/src/mediapipe/framework/output_stream_handler.h
@@ -22,6 +22,7 @@
 #include <unordered_map>
 #include <unordered_set>
 #include <utility>
+#include <vector>
 
 // TODO: Move protos in another CL after the C++ code migration.
 #include "absl/base/thread_annotations.h"
@@ -34,7 +35,6 @@
 #include "mediapipe/framework/output_stream_manager.h"
 #include "mediapipe/framework/packet_set.h"
 #include "mediapipe/framework/port/logging.h"
-#include "mediapipe/framework/port/status.h"
 #include "mediapipe/framework/timestamp.h"
 #include "mediapipe/framework/tool/tag_map.h"
 
@@ -49,6 +49,15 @@
       OutputStreamToSourcesMap;
   typedef internal::Collection<OutputStreamManager*> OutputStreamManagerSet;
 
+  // Struct to return monitoring info via GetMonitoringInfo;
+  struct OutputStreamMonitoringInfo {
+    std::string stream_name;
+    // The total number of packets added to the output stream.
+    int num_packets_added;
+    // The next timestamp bound of the output stream.
+    Timestamp next_timestamp_bound;
+  };
+
   // The constructor of the OutputStreamHandler takes four arguments.
   // The tag_map argument holds the information needed for tag/index retrieval
   // for the output streams; the calculator_context_manager for managing the
@@ -91,7 +100,7 @@
   }
 
   // Calls OutputStreamManager::PrepareForRun(error_callback) per stream, and
-  // resets data memebers.
+  // resets data members.
   void PrepareForRun(const std::function<void(absl::Status)>& error_callback)
       ABSL_LOCKS_EXCLUDED(timestamp_mutex_);
 
@@ -124,6 +133,14 @@
     return output_stream_managers_;
   }
 
+  // Return the stream name for an input stream in the format:
+  // stream_tag:stream_index:stream_name.
+  std::string DebugStreamName(CollectionItemId id) const;
+
+  // Returns a vector of tuples of stream name, number of packets added, and
+  // the next timestamp bound for each stream (for monitoring purposes).
+  std::vector<OutputStreamMonitoringInfo> GetMonitoringInfo();
+
  protected:
   // Checks if the given input bound should be propagated or not. If any output
   // streams with OffsetEnabled() need to have the timestamp bounds updated,
diff --git a/third_party/mediapipe/src/mediapipe/framework/output_stream_manager.cc b/third_party/mediapipe/src/mediapipe/framework/output_stream_manager.cc
index 0cb5929..42d2d7d 100644
--- a/third_party/mediapipe/src/mediapipe/framework/output_stream_manager.cc
+++ b/third_party/mediapipe/src/mediapipe/framework/output_stream_manager.cc
@@ -14,7 +14,10 @@
 
 #include "mediapipe/framework/output_stream_manager.h"
 
+#include <list>
+
 #include "absl/log/absl_check.h"
+#include "absl/log/absl_log.h"
 #include "absl/synchronization/mutex.h"
 #include "mediapipe/framework/input_stream_handler.h"
 #include "mediapipe/framework/port/status_builder.h"
@@ -40,6 +43,7 @@
     absl::MutexLock lock(&stream_mutex_);
     next_timestamp_bound_ = Timestamp::PreStream();
     closed_ = false;
+    num_packets_added_ = 0;
   }
 }
 
@@ -165,20 +169,21 @@
 void OutputStreamManager::PropagateUpdatesToMirrors(
     Timestamp next_timestamp_bound, OutputStreamShard* output_stream_shard) {
   ABSL_CHECK(output_stream_shard);
+  std::list<Packet>* packets_to_propagate = output_stream_shard->OutputQueue();
   {
     if (next_timestamp_bound != Timestamp::Unset()) {
       absl::MutexLock lock(&stream_mutex_);
       next_timestamp_bound_ = next_timestamp_bound;
+      num_packets_added_ += packets_to_propagate->size();
       VLOG(3) << "Next timestamp bound for output " << output_stream_spec_.name
               << " is " << next_timestamp_bound_;
     }
   }
-  std::list<Packet>* packets_to_propagate = output_stream_shard->OutputQueue();
   VLOG(3) << "Output stream: " << Name()
           << " queue size: " << packets_to_propagate->size();
   VLOG(3) << "Output stream: " << Name()
           << " next timestamp: " << next_timestamp_bound;
-  bool add_packets = !packets_to_propagate->empty();
+  const bool add_packets = !packets_to_propagate->empty();
   bool set_bound =
       (next_timestamp_bound != Timestamp::Unset()) &&
       (!add_packets ||
@@ -218,4 +223,9 @@
   output_stream_shard->Reset(next_timestamp_bound, closed);
 }
 
+int OutputStreamManager::NumPacketsAdded() const {
+  absl::MutexLock lock(&stream_mutex_);
+  return num_packets_added_;
+}
+
 }  // namespace mediapipe
diff --git a/third_party/mediapipe/src/mediapipe/framework/output_stream_manager.h b/third_party/mediapipe/src/mediapipe/framework/output_stream_manager.h
index 1df29af..c141d56 100644
--- a/third_party/mediapipe/src/mediapipe/framework/output_stream_manager.h
+++ b/third_party/mediapipe/src/mediapipe/framework/output_stream_manager.h
@@ -15,10 +15,12 @@
 #ifndef MEDIAPIPE_FRAMEWORK_OUTPUT_STREAM_MANAGER_H_
 #define MEDIAPIPE_FRAMEWORK_OUTPUT_STREAM_MANAGER_H_
 
+#include <cstdint>
 #include <functional>
 #include <string>
 #include <vector>
 
+#include "absl/base/thread_annotations.h"
 #include "absl/synchronization/mutex.h"
 #include "mediapipe/framework/output_stream_shard.h"
 #include "mediapipe/framework/packet.h"
@@ -102,6 +104,10 @@
   OutputStreamSpec* Spec() { return &output_stream_spec_; }
   const OutputStreamSpec* Spec() const { return &output_stream_spec_; }
 
+  // Returns the total number of packets added to the output stream. This is
+  // used for monitoring purposes.
+  int NumPacketsAdded() const;
+
  private:
   // The necessary information to locate an InputStreamImpl.
   struct Mirror {
@@ -120,6 +126,9 @@
   mutable absl::Mutex stream_mutex_;
   Timestamp next_timestamp_bound_ ABSL_GUARDED_BY(stream_mutex_);
   bool closed_ ABSL_GUARDED_BY(stream_mutex_);
+  // Monotonically increasing total number of packets added to the output
+  // stream. This is used for monitoring purposes.
+  int64_t num_packets_added_ ABSL_GUARDED_BY(stream_mutex_) = 0;
 };
 
 }  // namespace mediapipe
diff --git a/third_party/mediapipe/src/mediapipe/framework/thread_pool_executor.proto b/third_party/mediapipe/src/mediapipe/framework/thread_pool_executor.proto
index 50b19eb..161c373 100644
--- a/third_party/mediapipe/src/mediapipe/framework/thread_pool_executor.proto
+++ b/third_party/mediapipe/src/mediapipe/framework/thread_pool_executor.proto
@@ -22,6 +22,9 @@
 
 import "mediapipe/framework/mediapipe_options.proto";
 
+option java_package = "com.google.mediapipe.proto";
+option java_outer_classname = "ThreadPoolExecutorOptionsProto";
+
 message ThreadPoolExecutorOptions {
   extend MediaPipeOptions {
     optional ThreadPoolExecutorOptions ext = 157116819;
diff --git a/third_party/mediapipe/src/mediapipe/framework/tool/BUILD b/third_party/mediapipe/src/mediapipe/framework/tool/BUILD
index 383d2b6..7bec367 100644
--- a/third_party/mediapipe/src/mediapipe/framework/tool/BUILD
+++ b/third_party/mediapipe/src/mediapipe/framework/tool/BUILD
@@ -466,6 +466,7 @@
     hdrs = ["status_util.h"],
     visibility = ["//visibility:public"],
     deps = [
+        "//mediapipe/framework/deps:no_destructor",
         "//mediapipe/framework/port:status",
         "@com_google_absl//absl/base:core_headers",
         "@com_google_absl//absl/log:absl_check",
@@ -991,10 +992,12 @@
         "//mediapipe/framework:calculator_cc_proto",
         "//mediapipe/framework:graph_runtime_info_cc_proto",
         "//mediapipe/framework:vlog_utils",
+        "//mediapipe/framework/port:file_helpers",
         "//mediapipe/framework/port:logging",
         "//mediapipe/framework/port:ret_check",
         "//mediapipe/framework/port:threadpool",
         "@com_google_absl//absl/base:log_severity",
+        "@com_google_absl//absl/flags:flag",
         "@com_google_absl//absl/functional:any_invocable",
         "@com_google_absl//absl/log",
         "@com_google_absl//absl/log:absl_check",
diff --git a/third_party/mediapipe/src/mediapipe/framework/tool/graph_runtime_info_utils.cc b/third_party/mediapipe/src/mediapipe/framework/tool/graph_runtime_info_utils.cc
index 86f28d31..e70de672 100644
--- a/third_party/mediapipe/src/mediapipe/framework/tool/graph_runtime_info_utils.cc
+++ b/third_party/mediapipe/src/mediapipe/framework/tool/graph_runtime_info_utils.cc
@@ -1,5 +1,7 @@
 #include "mediapipe/framework/tool/graph_runtime_info_utils.h"
 
+#include <algorithm>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -17,12 +19,28 @@
   const absl::Time caputure_time =
       absl::FromUnixMicros(graph_runtime_info.capture_time_unix_us());
   std::string calculators_runtime_info_str;
-  std::vector<std::string> calculators_with_unprocessed_packets;
+  std::set<std::string> calculators_with_unprocessed_packets;
   std::vector<std::string> running_calculators;
-  int num_packets_in_input_queues = 0;
+
+  // Analyze packets in input queues.
+  int num_total_pending_packets = 0;
   for (const auto& calculator_info : graph_runtime_info.calculator_infos()) {
     const bool is_idle = calculator_info.last_process_finish_unix_us() >=
                          calculator_info.last_process_start_unix_us();
+    int calculator_pending_packets = 0;
+    Timestamp min_ts_bound_of_streams_with_unprocessed_packets =
+        Timestamp::Max();
+    for (const auto& input_stream_info : calculator_info.input_stream_infos()) {
+      calculator_pending_packets += input_stream_info.queue_size();
+      num_total_pending_packets += input_stream_info.queue_size();
+      const Timestamp stream_ts_bound = Timestamp::CreateNoErrorChecking(
+          input_stream_info.minimum_timestamp_or_bound());
+      if (input_stream_info.queue_size() > 0) {
+        min_ts_bound_of_streams_with_unprocessed_packets = std::min(
+            min_ts_bound_of_streams_with_unprocessed_packets, stream_ts_bound);
+      }
+    }
+    // Determine calculator state.
     const std::string calculator_state_str =
         is_idle ? absl::StrFormat(
                       "idle for %.2fs",
@@ -39,38 +57,76 @@
     if (!is_idle) {
       running_calculators.push_back(calculator_info.calculator_name());
     }
+    const Timestamp calculator_ts_bound =
+        Timestamp::CreateNoErrorChecking(calculator_info.timestamp_bound());
     absl::StrAppend(
         &calculators_runtime_info_str,
-        absl::StrFormat(
-            "\n%s: (%s, ts bound : %s)", calculator_info.calculator_name(),
-            calculator_state_str,
-            Timestamp::CreateNoErrorChecking(calculator_info.timestamp_bound())
-                .DebugString()));
-    bool calculator_has_unprocessed_packets = false;
+        absl::StrFormat("\n%s: (%s%s, ts bound : %s)\n",
+                        calculator_info.calculator_name(), calculator_state_str,
+                        calculator_pending_packets > 0
+                            ? absl::StrCat(", pending packets: ",
+                                           calculator_pending_packets)
+                            : "",
+                        calculator_ts_bound.DebugString()));
+    if (calculator_pending_packets > 0) {
+      // Predict streams that might be waiting for packets.
+      std::vector<std::string> streams_with_waiting_for_packets;
+      for (const auto& input_stream_info :
+           calculator_info.input_stream_infos()) {
+        const Timestamp stream_ts_bound = Timestamp::CreateNoErrorChecking(
+            input_stream_info.minimum_timestamp_or_bound());
+        if (stream_ts_bound <
+            min_ts_bound_of_streams_with_unprocessed_packets) {
+          streams_with_waiting_for_packets.push_back(
+              input_stream_info.stream_name());
+        }
+      }
+      const std::string waiting_for_packets_str =
+          absl::StrCat("waiting on stream(s): ",
+                       absl::StrJoin(streams_with_waiting_for_packets, ", "));
+      absl::StrAppend(&calculators_runtime_info_str, waiting_for_packets_str,
+                      "\n");
+      calculators_with_unprocessed_packets.insert(absl::StrCat(
+          calculator_info.calculator_name(), " ", waiting_for_packets_str));
+    }
+
+    // List input streams with state.
+    if (!calculator_info.input_stream_infos().empty()) {
+      absl::StrAppend(&calculators_runtime_info_str, "Input streams:\n");
+    }
     for (const auto& input_stream_info : calculator_info.input_stream_infos()) {
-      num_packets_in_input_queues += input_stream_info.queue_size();
-      calculator_has_unprocessed_packets |= input_stream_info.queue_size() > 0;
       absl::StrAppend(
           &calculators_runtime_info_str, " * ", input_stream_info.stream_name(),
           " - queue size: ", input_stream_info.queue_size(),
           ", total added: ", input_stream_info.number_of_packets_added(),
-          ", min ts: ",
+          ", ts bound: ",
           Timestamp::CreateNoErrorChecking(
               input_stream_info.minimum_timestamp_or_bound())
               .DebugString(),
           "\n");
     }
-    if (calculator_has_unprocessed_packets) {
-      calculators_with_unprocessed_packets.push_back(
-          calculator_info.calculator_name());
+    // List output streams with state.
+    if (!calculator_info.output_stream_infos().empty()) {
+      absl::StrAppend(&calculators_runtime_info_str, "Output streams:\n");
+    }
+    for (const auto& output_stream_info :
+         calculator_info.output_stream_infos()) {
+      absl::StrAppend(&calculators_runtime_info_str, " * ",
+                      output_stream_info.stream_name(), ", total added: ",
+                      output_stream_info.number_of_packets_added(),
+                      ", ts bound: ",
+                      Timestamp::CreateNoErrorChecking(
+                          output_stream_info.minimum_timestamp_or_bound())
+                          .DebugString(),
+                      "\n");
     }
   }
+
   const std::string calulators_with_unprocessed_packets_str =
-      num_packets_in_input_queues > 0
+      !calculators_with_unprocessed_packets.empty()
           ? absl::StrCat(
-                " (in calculators: ",
-                absl::StrJoin(calculators_with_unprocessed_packets, ", "), ")")
-          : "";
+                absl::StrJoin(calculators_with_unprocessed_packets, "\n"))
+          : "\n";
   const std::string running_calculators_str =
       running_calculators.empty()
           ? "None"
@@ -78,8 +134,8 @@
                          absl::StrJoin(running_calculators, ", "), ")");
   return absl::StrFormat(
       "Graph runtime info: \nRunning calculators: %s\nNum packets in input "
-      "queues: %d%s\n%s\n",
-      running_calculators_str, num_packets_in_input_queues,
+      "queues: %d\n%s\n%s\n",
+      running_calculators_str, num_total_pending_packets,
       calulators_with_unprocessed_packets_str, calculators_runtime_info_str);
 }
 
diff --git a/third_party/mediapipe/src/mediapipe/framework/tool/ios.bzl b/third_party/mediapipe/src/mediapipe/framework/tool/ios.bzl
index a0fe0be5..45f6b75 100644
--- a/third_party/mediapipe/src/mediapipe/framework/tool/ios.bzl
+++ b/third_party/mediapipe/src/mediapipe/framework/tool/ios.bzl
@@ -14,7 +14,7 @@
 
 """MediaPipe Task Library Helper Rules for iOS"""
 
-MPP_TASK_MINIMUM_OS_VERSION = "12.0"
+MPP_TASK_MINIMUM_OS_VERSION = "15.0"
 
 # When the static framework is built with bazel, the all header files are moved
 # to the "Headers" directory with no header path prefixes. This auxiliary rule
diff --git a/third_party/mediapipe/src/mediapipe/framework/tool/status_util.cc b/third_party/mediapipe/src/mediapipe/framework/tool/status_util.cc
index 19f3fc6..1c6a8e3 100644
--- a/third_party/mediapipe/src/mediapipe/framework/tool/status_util.cc
+++ b/third_party/mediapipe/src/mediapipe/framework/tool/status_util.cc
@@ -20,6 +20,7 @@
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_join.h"
 #include "absl/strings/string_view.h"
+#include "mediapipe/framework/deps/no_destructor.h"
 
 namespace mediapipe {
 namespace tool {
@@ -32,9 +33,10 @@
   return absl::Status(absl::StatusCode::kUnknown, message);
 }
 
-absl::Status StatusStop() {
-  return absl::Status(absl::StatusCode::kOutOfRange,
-                      "mediapipe::tool::StatusStop()");
+const absl::Status& StatusStop() {
+  static const NoDestructor<absl::Status> kStatusStop(
+      absl::StatusCode::kOutOfRange, "mediapipe::tool::StatusStop()");
+  return *kStatusStop;
 }
 
 absl::Status AddStatusPrefix(absl::string_view prefix,
diff --git a/third_party/mediapipe/src/mediapipe/framework/tool/status_util.h b/third_party/mediapipe/src/mediapipe/framework/tool/status_util.h
index 0db03ec..9088ec2 100644
--- a/third_party/mediapipe/src/mediapipe/framework/tool/status_util.h
+++ b/third_party/mediapipe/src/mediapipe/framework/tool/status_util.h
@@ -30,7 +30,7 @@
 // be called on it again).  When returned from a non-source Calculator
 // it signals that the graph should be cancelled (which is handled by
 // closing all source Calculators and waiting for the graph to finish).
-absl::Status StatusStop();
+const absl::Status& StatusStop();
 
 // Return a status which signals an invalid initial condition (for
 // example an InputSidePacket does not include all necessary fields).
diff --git a/third_party/mediapipe/src/mediapipe/framework/type_map.h b/third_party/mediapipe/src/mediapipe/framework/type_map.h
index 1236687..242bdb6 100644
--- a/third_party/mediapipe/src/mediapipe/framework/type_map.h
+++ b/third_party/mediapipe/src/mediapipe/framework/type_map.h
@@ -211,10 +211,10 @@
   friend class StaticMap::ValueInserter;
 
   // Returns a pointer to the one true instance of MapName class.
-  static MapName* GetMap() {
+  static StaticMap* GetMap() {
     // TODO: Uses gtl::NoDestructor for the thread-safe one-time
     // initialization if gtl::NoDestructor will be open sourced by ABSL.
-    static MapName* instance = new MapName();
+    static StaticMap* instance = new MapName();
     return instance;
   }
 
diff --git a/third_party/mediapipe/src/mediapipe/gpu/BUILD b/third_party/mediapipe/src/mediapipe/gpu/BUILD
index 5cc4d149..0ccb1d3 100644
--- a/third_party/mediapipe/src/mediapipe/gpu/BUILD
+++ b/third_party/mediapipe/src/mediapipe/gpu/BUILD
@@ -1167,6 +1167,77 @@
     alwayslink = 1,
 )
 
+mediapipe_proto_library(
+    name = "gl_shader_calculator_proto",
+    srcs = ["gl_shader_calculator.proto"],
+    visibility = ["//visibility:public"],
+    deps = [
+        "//mediapipe/framework:calculator_options_proto",
+        "//mediapipe/framework:calculator_proto",
+    ],
+)
+
+cc_library(
+    name = "gl_shader_calculator",
+    srcs = ["gl_shader_calculator.cc"],
+    deps = [
+        ":gl_shader_calculator_cc_proto",
+        "//mediapipe/framework:calculator_context",
+        "//mediapipe/framework:calculator_contract",
+        "//mediapipe/framework:calculator_framework",
+        "//mediapipe/framework:calculator_options_cc_proto",
+        "//mediapipe/framework:timestamp",
+        "//mediapipe/framework/api2:node",
+        "//mediapipe/framework/api2:packet",
+        "//mediapipe/framework/api2:port",
+        "//mediapipe/framework/port:ret_check",
+        "//mediapipe/framework/port:status",
+        "//mediapipe/gpu:gl_calculator_helper",
+        "//mediapipe/gpu:gl_simple_shaders",
+        "//mediapipe/gpu:gpu_buffer",
+        "//mediapipe/gpu:gpu_buffer_format",
+        "//mediapipe/gpu:shader_util",
+        "//mediapipe/util:resource_util",
+        "//third_party/GL:GLES2_headers",
+        "@com_google_absl//absl/log",
+        "@com_google_absl//absl/log:check",
+        "@com_google_absl//absl/status",
+        "@com_google_absl//absl/types:span",
+    ],
+    alwayslink = 1,
+)
+
+cc_test(
+    name = "gl_shader_calculator_test",
+    size = "small",
+    timeout = "moderate",
+    srcs = ["gl_shader_calculator_test.cc"],
+    data = [
+        ":testdata/googlelogo_color_272x92dp.png",
+    ] + glob(["testdata/scuba_goldens/*.png"]),
+    deps = [
+        ":gl_shader_calculator",
+        ":gl_shader_calculator_cc_proto",
+        "//mediapipe/framework:calculator_cc_proto",
+        "//mediapipe/framework:calculator_framework",
+        "//mediapipe/framework/api2:builder",
+        "//mediapipe/framework/api2:packet",
+        "//mediapipe/framework/formats:image_frame",
+        "//mediapipe/framework/port:gtest",
+        "//mediapipe/framework/port:status",
+        "//mediapipe/framework/tool:test_util",
+        "//mediapipe/gpu:gl_simple_shaders",
+        "//mediapipe/gpu:gpu_buffer_to_image_frame_calculator",
+        "//mediapipe/gpu:image_frame_to_gpu_buffer_calculator",
+        "@com_google_absl//absl/functional:function_ref",
+        "@com_google_absl//absl/log",
+        "@com_google_absl//absl/status",
+        "@com_google_absl//absl/strings",
+        "@com_google_absl//absl/strings:str_format",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
 cc_library(
     name = "gl_surface_sink_calculator",
     srcs = ["gl_surface_sink_calculator.cc"],
@@ -1291,7 +1362,6 @@
 objc_library(
     name = "mps_sobel_calculator",
     srcs = ["MPSSobelCalculator.mm"],
-    copts = ["-std=c++17"],
     features = ["-layering_check"],
     visibility = ["//visibility:public"],
     deps = [
diff --git a/third_party/mediapipe/src/mediapipe/gpu/gpu_shared_data_internal.cc b/third_party/mediapipe/src/mediapipe/gpu/gpu_shared_data_internal.cc
index 7b9d75f..5e70fe3 100644
--- a/third_party/mediapipe/src/mediapipe/gpu/gpu_shared_data_internal.cc
+++ b/third_party/mediapipe/src/mediapipe/gpu/gpu_shared_data_internal.cc
@@ -108,6 +108,13 @@
   return gpu_resources;
 }
 
+GpuResources::StatusOrGpuResources GpuResources::Create(
+    const GpuResources& gpu_resources,
+    const MultiPoolOptions* gpu_buffer_pool_options) {
+  return Create(gpu_resources.gl_context()->native_context(),
+                gpu_buffer_pool_options);
+}
+
 GpuResources::GpuResources(std::shared_ptr<GlContext> gl_context,
                            const MultiPoolOptions* gpu_buffer_pool_options)
     : gl_key_context_(new GlContextMapType(),
@@ -239,9 +246,10 @@
 // TODO: expose and use an actual ID instead of using the
 // canonicalized name.
 const std::shared_ptr<GlContext>& GpuResources::gl_context(
-    CalculatorContext* cc) {
+    CalculatorContext* cc) const {
   if (cc) {
-    auto it = gl_key_context_->find(node_key_[cc->NodeName()]);
+    const auto node_key_it = node_key_.find(cc->NodeName());
+    const auto it = gl_key_context_->find(node_key_it->second);
     if (it != gl_key_context_->end()) {
       return it->second;
     }
diff --git a/third_party/mediapipe/src/mediapipe/gpu/gpu_shared_data_internal.h b/third_party/mediapipe/src/mediapipe/gpu/gpu_shared_data_internal.h
index 75bdaca..4867c61 100644
--- a/third_party/mediapipe/src/mediapipe/gpu/gpu_shared_data_internal.h
+++ b/third_party/mediapipe/src/mediapipe/gpu/gpu_shared_data_internal.h
@@ -57,6 +57,12 @@
       PlatformGlContext external_context,
       const MultiPoolOptions* gpu_buffer_pool_options = nullptr);
 
+  // Creates a GpuResources instance that is shared with the GL context provided
+  // by the gpu_resources argument.
+  static StatusOrGpuResources Create(
+      const GpuResources& gpu_resources,
+      const MultiPoolOptions* gpu_buffer_pool_options = nullptr);
+
   // The destructor must be defined in the implementation file so that on iOS
   // the correct ARC release calls are generated.
   ~GpuResources();
@@ -65,9 +71,11 @@
 
   // Shared GL context for calculators.
   // TODO: require passing a context or node identifier.
-  const std::shared_ptr<GlContext>& gl_context() { return gl_context(nullptr); }
+  const std::shared_ptr<GlContext>& gl_context() const {
+    return gl_context(nullptr);
+  }
 
-  const std::shared_ptr<GlContext>& gl_context(CalculatorContext* cc);
+  const std::shared_ptr<GlContext>& gl_context(CalculatorContext* cc) const;
 
   // Shared buffer pool.
   GpuBufferMultiPool& gpu_buffer_pool() { return gpu_buffer_pool_; }
diff --git a/third_party/mediapipe/src/mediapipe/gpu/metal.bzl b/third_party/mediapipe/src/mediapipe/gpu/metal.bzl
index 853a164a..dda5eb1 100644
--- a/third_party/mediapipe/src/mediapipe/gpu/metal.bzl
+++ b/third_party/mediapipe/src/mediapipe/gpu/metal.bzl
@@ -171,7 +171,7 @@
 METAL_LIBRARY_ATTRS = dicts.add(apple_support.action_required_attrs(), {
     "srcs": attr.label_list(allow_files = [".metal"], allow_empty = False),
     "hdrs": attr.label_list(allow_files = [".h"]),
-    "deps": attr.label_list(providers = [["objc", CcInfo], [apple_common.Objc, CcInfo]]),
+    "deps": attr.label_list(providers = [[apple_common.Objc, CcInfo]]),
     "copts": attr.string_list(),
     "minimum_os_version": attr.string(),
 })
diff --git a/third_party/mediapipe/src/mediapipe/gpu/webgpu/BUILD b/third_party/mediapipe/src/mediapipe/gpu/webgpu/BUILD
index 797f2d4..40445db 100644
--- a/third_party/mediapipe/src/mediapipe/gpu/webgpu/BUILD
+++ b/third_party/mediapipe/src/mediapipe/gpu/webgpu/BUILD
@@ -1,5 +1,6 @@
 load("@bazel_skylib//lib:selects.bzl", "selects")
 load("//mediapipe/framework:mediapipe_cc_test.bzl", "mediapipe_cc_test")
+load("//mediapipe/framework/port:build_config.bzl", "mediapipe_proto_library")
 
 licenses(["notice"])
 
@@ -129,8 +130,16 @@
         "//mediapipe/framework/port:status",
         "//mediapipe/web:jspi_check",
         "//third_party/dawn:webgpu_headers",
+        "@com_google_absl//absl/base:no_destructor",
+        "@com_google_absl//absl/status",
         "@com_google_absl//absl/status:statusor",
-    ],
+        "@com_google_absl//absl/time",
+    ] + select({
+        "//mediapipe:emscripten": [
+            "//third_party/emdawnwebgpu:webgpu",
+        ],
+        "//conditions:default": [],
+    }),
 )
 
 cc_library(
@@ -140,8 +149,40 @@
     deps = [
         ":webgpu_service",
         ":webgpu_texture_view",
+        ":webgpu_utils",
         "//mediapipe/calculators/tensor:image_to_tensor_converter",
         "//mediapipe/framework:calculator_framework",
         "//mediapipe/framework/formats:tensor",
     ],
 )
+
+cc_library(
+    name = "webgpu_shader_calculator",
+    srcs = ["webgpu_shader_calculator.cc"],
+    deps = [
+        ":webgpu_shader_calculator_cc_proto",
+        "//mediapipe/framework:calculator_framework",
+        "//mediapipe/framework:calculator_options_cc_proto",
+        "//mediapipe/framework/api2:node",
+        "//mediapipe/framework/deps:re2",
+        "//mediapipe/framework/port:status",
+        "//mediapipe/gpu:gpu_buffer",
+        "//mediapipe/gpu:gpu_buffer_format",
+        "//mediapipe/gpu/webgpu:webgpu_service",
+        "//mediapipe/gpu/webgpu:webgpu_texture_buffer",
+        "//mediapipe/gpu/webgpu:webgpu_texture_buffer_3d",
+        "//mediapipe/gpu/webgpu:webgpu_texture_view",
+        "//mediapipe/gpu/webgpu:webgpu_utils",
+        "//mediapipe/util:resource_util",
+        "@com_google_absl//absl/strings:str_format",
+    ],
+    alwayslink = 1,
+)
+
+mediapipe_proto_library(
+    name = "webgpu_shader_calculator_proto",
+    srcs = ["webgpu_shader_calculator.proto"],
+    deps = [
+        "//mediapipe/framework:calculator_proto",
+    ],
+)
diff --git a/third_party/mediapipe/src/mediapipe/gpu/webgpu/image_to_tensor_converter_webgpu_texture.cc b/third_party/mediapipe/src/mediapipe/gpu/webgpu/image_to_tensor_converter_webgpu_texture.cc
index 9843cf2f..0a38ae4 100644
--- a/third_party/mediapipe/src/mediapipe/gpu/webgpu/image_to_tensor_converter_webgpu_texture.cc
+++ b/third_party/mediapipe/src/mediapipe/gpu/webgpu/image_to_tensor_converter_webgpu_texture.cc
@@ -19,6 +19,7 @@
 #include "mediapipe/gpu/gpu_buffer_format.h"
 #include "mediapipe/gpu/webgpu/webgpu_service.h"
 #include "mediapipe/gpu/webgpu/webgpu_texture_view.h"
+#include "mediapipe/gpu/webgpu/webgpu_utils.h"
 
 namespace mediapipe {
 namespace {
@@ -131,7 +132,7 @@
                                                kTileSize, kTileSize);
 
     // Create the shader module.
-    wgpu::ShaderModuleWGSLDescriptor wgsl;
+    wgpu::ShaderSourceWGSL wgsl;
     wgsl.code = shader.c_str();
     wgpu::ShaderModuleDescriptor shader_desc = {.nextInChain = &wgsl};
     wgpu::ShaderModule module =
@@ -147,7 +148,8 @@
                 .constants = nullptr,
             },
     };
-    pipeline_ = service_.device().CreateComputePipeline(&pipeline_desc);
+    pipeline_ =
+        WebGpuCreateComputePipelineAsync(service_.device(), &pipeline_desc);
 
     // Create a uniform buffer for the parameters.
     wgpu::BufferDescriptor buffer_desc = {
@@ -217,8 +219,9 @@
             .size = sizeof(Parameters),
         },
     };
+    MP_ASSIGN_OR_RETURN(wgpu::ComputePipeline * pipeline, pipeline_.Get());
     wgpu::BindGroupDescriptor bind_group_desc = {
-        .layout = pipeline_.GetBindGroupLayout(0),
+        .layout = pipeline->GetBindGroupLayout(0),
         .entryCount = sizeof(entries) / sizeof(entries[0]),
         .entries = entries,
     };
@@ -231,7 +234,7 @@
     // Create and submit a command buffer that dispatches the compute shader.
     auto command_encoder = device.CreateCommandEncoder();
     auto pass_encoder = command_encoder.BeginComputePass();
-    pass_encoder.SetPipeline(pipeline_);
+    pass_encoder.SetPipeline(*pipeline);
     pass_encoder.SetBindGroup(0, bind_group);
     pass_encoder.DispatchWorkgroups(num_groups_x, num_groups_y);
     pass_encoder.End();
@@ -256,7 +259,7 @@
   }
 
   const WebGpuService& service_;
-  wgpu::ComputePipeline pipeline_;
+  WebGpuAsyncFuture<wgpu::ComputePipeline> pipeline_;
   wgpu::Buffer params_buffer_;
 
   struct Parameters {  // Must match `Parameters` in WGSL above.
diff --git a/third_party/mediapipe/src/mediapipe/gpu/webgpu/webgpu_shader_calculator.cc b/third_party/mediapipe/src/mediapipe/gpu/webgpu/webgpu_shader_calculator.cc
new file mode 100644
index 0000000..63a48c94
--- /dev/null
+++ b/third_party/mediapipe/src/mediapipe/gpu/webgpu/webgpu_shader_calculator.cc
@@ -0,0 +1,1100 @@
+#include <webgpu/webgpu_cpp.h>
+
+#include <algorithm>
+#include <cstdint>
+#include <cstring>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+#include "absl/log/absl_log.h"
+#include "absl/log/check.h"
+#include "absl/status/status.h"
+#include "absl/strings/numbers.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_split.h"
+#include "absl/strings/string_view.h"
+#include "mediapipe/framework/api2/node.h"
+#include "mediapipe/framework/api2/packet.h"
+#include "mediapipe/framework/api2/port.h"
+#include "mediapipe/framework/calculator_framework.h"
+#include "mediapipe/framework/calculator_options.pb.h"
+#include "mediapipe/framework/deps/re2.h"
+#include "mediapipe/framework/port/ret_check.h"
+#include "mediapipe/framework/port/status_macros.h"
+#include "mediapipe/framework/resources.h"
+#include "mediapipe/gpu/gpu_buffer.h"
+#include "mediapipe/gpu/gpu_buffer_format.h"
+#include "mediapipe/gpu/webgpu/webgpu_service.h"
+#include "mediapipe/gpu/webgpu/webgpu_shader_calculator.pb.h"
+#include "mediapipe/gpu/webgpu/webgpu_texture_buffer_3d.h"
+#include "mediapipe/gpu/webgpu/webgpu_texture_view.h"
+#include "mediapipe/gpu/webgpu/webgpu_utils.h"
+
+namespace mediapipe {
+
+// Compiles a given WGSL shader, and runs it over the input WebGPU-backed
+// GpuBuffer streams to produce an output WebGPU-backed GpuBuffer stream.
+// We expect a "Params" struct in the shader for our uniforms. We will
+// automatically pipe in values for 'outputSize' and 'time' using the size of
+// the output texture and the timestamp in seconds, respectively. Otherwise, all
+// uniforms in Params are expected to be f32 or vectors of f32. We will bind all
+// f32 uniforms to INPUT_FLOAT streams, matching the order those streams are
+// are given to the order of f32 uniforms in the Params struct. And we will
+// bind all vec2<f32>, vec3<f32>, and vec4<f32> uniforms to INPUT_FLOAT_VEC
+// streams, matching the order those streams are given to the order of vec*<f32>
+// uniforms in the Params struct.
+// We bind all input buffers, matching the order they are given to the
+// calculator via INPUT_BUFFER, with the order they are listed in the shader
+// source code. We similarly bind all input 3d buffers (if any), matching the
+// order they are given to the calculator via INPUT_BUFFER_3D, with the order
+// they are listed in the shader source code.
+//
+// Inputs:
+//   TRIGGER (Any):
+//     Stream which is used (in the absence of INPUT_BUFFER and INPUT_FLOAT
+//     streams) to trigger output of an input-free shader.
+//   INPUT_BUFFER (GpuBuffer, repeated):
+//     List of input buffers. Must contain one for every 2d texture the shader
+//     code references.
+//   INPUT_BUFFER_3D (WebGpuTextureBuffer3d, repeated):
+//     List of 3d input buffers, for compute shaders. Must contain one for every
+//     3d texture the shader code references.
+//   INPUT_FLOAT (float, repeated):
+//     List of float value streams. Must contain one for every float uniform
+//     the shader code references.
+//   INPUT_FLOAT_VEC (vec<float>, repeated):
+//     List of float vector streams. Must contain one for every vec2, vec3, or
+//     vec4 uniform the shader code references.
+//   WIDTH (int32_t):
+//     Input stream which will dynamically set the rendering output width.
+//     Overrides other methods of setting this property.
+//   HEIGHT (int32_t):
+//     Input stream which will dynamically set the rendering output height.
+//     Overrides other methods of setting this property.
+//   DEPTH (int32_t):
+//     Input stream which will dynamically set the rendering output depth.
+//     This is unused for normal (2d) rendering, and if used will change the
+//     output type to be a WebGpuTextureBuffer3d. Overrides other methods of
+//     setting this property.
+//
+// Outputs:
+//   OUTPUT (GpuBuffer)
+//     Frames containing the result of the 2D rendering. This will be the output
+//     stream unless 3D compute shading is occurring.
+//   OUTPUT_3D (WebGpuTextureBuffer3d)
+//     Frames containing the result of the 3D compute shading, when an output
+//     depth has been specified.
+
+namespace {
+
+using ::mediapipe::api2::AnyType;
+using ::mediapipe::api2::Input;
+using ::mediapipe::api2::NodeImpl;
+using ::mediapipe::api2::NodeIntf;
+using ::mediapipe::api2::Output;
+
+// One query for start time, one for end time.
+constexpr uint32_t kQueryBufferByteSize = 2 * sizeof(uint64_t);
+
+// WebGpu uses this as a default for each dimension.
+constexpr size_t kDefaultWorkgroupSize = 1;
+
+// WebGpu imposes a minimum buffer size for queries, so we may need to pad.
+constexpr uint32_t kMinQueryBufferSize = 256u;
+
+// Search terms we use for parsing shader code.
+constexpr char kParseTermBinding[] = "@binding(";
+constexpr char kParseTermParams[] = "struct Params {";
+constexpr char kParseTermWorkgroup[] = "@workgroup_size(";
+const size_t kParseTermBindingSize = std::strlen(kParseTermBinding);
+const size_t kParseTermParamsSize = std::strlen(kParseTermParams);
+const size_t kParseTermWorkgroupSize = std::strlen(kParseTermWorkgroup);
+
+// If no shader provided, we assume passthrough with same-size input and output.
+constexpr char kDefaultWebGpuShaderSource[] = R"(
+struct Params {
+  outputSize : vec2<i32>
+}
+
+@group(0) @binding(0) var inputTex : texture_2d<f32>;
+@group(0) @binding(1) var outputTex : texture_storage_2d<rgba8unorm, write>;
+@group(0) @binding(2) var<uniform> params : Params;
+
+@compute @workgroup_size(8, 8)
+fn main(
+  @builtin(global_invocation_id) gid : vec3<u32>
+) {
+  let outputCoord = vec2<i32>(gid.xy);
+  if (outputCoord.x >= params.outputSize.x
+      || outputCoord.y >= params.outputSize.y) {
+    return;
+  }
+  let input = textureLoad(inputTex, outputCoord, 0);
+  textureStore(outputTex, outputCoord, input);
+}
+)";
+
+#ifdef __EMSCRIPTEN__
+// Expose the information which is used in JavaScript later to display the
+// WebGPU metrics in real-time.
+EM_JS(void, ExposeProfilingResults,
+      (const char* calc_name, void* wgpu_buffer_ptr, int32_t num_repetitions), {
+        // Initialize profiling call
+        if (!Module.WEBGPU_SHADER_CALC_PROFILE) {
+          Module.WEBGPU_SHADER_CALC_PROFILE = async() => {
+            console.log('WebGpuShaderCalculator profiling results: ');
+            for (const calc in Module.WEBGPU_SHADER_CALC_METRICS) {
+              const readBuffer = Module.WEBGPU_SHADER_CALC_METRICS[calc].buffer;
+              await readBuffer.mapAsync(GPUMapMode.READ);
+              const resultsBuffer =
+                  new BigInt64Array(readBuffer.getMappedRange());
+              const timeDelta = resultsBuffer[1] - resultsBuffer[0];
+              if (Number.MIN_SAFE_INTEGER < timeDelta &&
+                  timeDelta < Number.MAX_SAFE_INTEGER) {
+                const timeMs = Number(timeDelta) / 1000000;
+                const numRepetitions =
+                    Module.WEBGPU_SHADER_CALC_METRICS[calc].repetitions;
+                console.log(`${calc} : ${timeMs / numRepetitions} ms`);
+              }
+              readBuffer.unmap();
+            }
+            console.log('Finished printing WebGpuShaderCalculator profiling.');
+          };
+        }
+
+        // Expose the buffer directly to our table.
+        const gpuReadBuffer = WebGPU.getJsObject(wgpu_buffer_ptr);
+        Module.WEBGPU_SHADER_CALC_METRICS =
+            Module.WEBGPU_SHADER_CALC_METRICS || {};
+        Module.WEBGPU_SHADER_CALC_METRICS[UTF8ToString(calc_name)] = {
+          buffer : gpuReadBuffer,
+          repetitions : num_repetitions,
+        };
+      });
+#else
+void ExposeProfilingResults(const char* calc_name, void* wgpu_buffer_ptr,
+                            int32_t num_repetitions) {
+  ABSL_LOG(WARNING) << "Exposing profiling results only implemented on web.";
+}
+#endif  // __EMSCRIPTEN__
+
+// Quick helper to remove comments in shader code before parsing it for various
+// search terms and tokens.
+std::string RemoveComments(const std::string& str) {
+  // First we remove all `/* ... */` blocks.
+  // We match the sequence of "/*", any non-null character sequence (so we can
+  // include multi-line comment blocks), and finally "*/". We use '?' to request
+  // non-greedy matching.
+  std::string new_str = str;
+  RE2 pattern_comment_block("/\\*[^\\0]*?\\*/");
+  RE2::GlobalReplace(&new_str, pattern_comment_block, "");
+
+  // Then we remove all remaining `// ...` lines.
+  // For this, we want greedy matching up to a newline.
+  RE2 pattern_comment_line("//.*");
+  RE2::GlobalReplace(&new_str, pattern_comment_line, "");
+  return new_str;
+}
+
+class ScopedWebGpuErrorHandler {
+ public:
+  ScopedWebGpuErrorHandler(
+      WebGpuService* service, std::string_view callsite,
+      mediapipe::Timestamp timestamp = mediapipe::Timestamp::Unset())
+      : service_(service), callsite_(callsite), timestamp_(timestamp) {
+    PushErrorScopes();
+  }
+
+  ~ScopedWebGpuErrorHandler() { PopErrorScopes(); }
+
+ private:
+  WebGpuService* service_ = nullptr;
+  std::string callsite_;
+  mediapipe::Timestamp timestamp_;
+
+  void PushErrorScopes();
+  void PopErrorScopes();
+
+  static std::string MapErrorTypesToString(wgpu::ErrorType type) {
+    switch (type) {
+      case wgpu::ErrorType::NoError:
+        return "NoError";
+      case wgpu::ErrorType::Validation:
+        return "Validation";
+      case wgpu::ErrorType::OutOfMemory:
+        return "OutOfMemory";
+      case wgpu::ErrorType::Internal:
+        return "Internal";
+      default:
+        return "Unknown";
+    }
+  }
+};
+
+void ScopedWebGpuErrorHandler::PushErrorScopes() {
+  service_->device().PushErrorScope(wgpu::ErrorFilter::Validation);
+  service_->device().PushErrorScope(wgpu::ErrorFilter::OutOfMemory);
+  service_->device().PushErrorScope(wgpu::ErrorFilter::Internal);
+}
+
+void ScopedWebGpuErrorHandler::PopErrorScopes() {
+  std::function<void(wgpu::PopErrorScopeStatus, wgpu::ErrorType,
+                     wgpu::StringView)>
+      callback = [callsite = callsite_, timestamp = timestamp_](
+                     wgpu::PopErrorScopeStatus status, wgpu::ErrorType type,
+                     wgpu::StringView message) {
+        if (type == wgpu::ErrorType::NoError) {
+          return;
+        }
+        std::string timestamp_str =
+            timestamp.IsSpecialValue()
+                ? timestamp.DebugString()
+                : absl::StrFormat("%d", timestamp.Value());
+
+        // Note that we only log the error message here and do not bubble up
+        // an error status. Given the asynchronous nature of WebGPU and its
+        // error handling via callbacks, we would only be able to return
+        // errors in a Process() call after a Process() call in which the error
+        // occurred.
+        ABSL_LOG(ERROR) << "WebGPU error of type: "
+                        << MapErrorTypesToString(type) << " encountered in "
+                        << callsite << " at timestamp: " << timestamp_str
+                        << ". "
+                        << " Error message: " << std::string(message);
+      };
+
+  // We pushed 3 error scopes, so we need to pop 3.
+  service_->device().PopErrorScope(wgpu::CallbackMode::AllowSpontaneous,
+                                   callback);
+  service_->device().PopErrorScope(wgpu::CallbackMode::AllowSpontaneous,
+                                   callback);
+  service_->device().PopErrorScope(wgpu::CallbackMode::AllowSpontaneous,
+                                   callback);
+}
+
+// Quick helper to remove whitespace and parse our "a : b," list into tokens.
+std::string ExtractParamFromTo(const std::string& str, int start_index,
+                               int end_index) {
+  std::string token = "";
+  for (int i = start_index; i <= end_index; i++) {
+    if (str[i] == ',' || str[i] == '}' || str[i] == ';' || str[i] == ':') break;
+    if (str[i] == ' ' || str[i] == '\n') continue;
+    token += str[i];
+  }
+  return token;
+}
+
+struct ParamOffsets {
+  int num_params = 0;
+  std::optional<int> output_size_offset;
+  std::optional<int> time_offset;
+  std::vector<int> float_offsets;
+  std::vector<int> float_vec_offsets;
+};
+
+absl::StatusOr<ParamOffsets> GetParamOffsets(const std::string& source) {
+  ParamOffsets offsets;
+
+  // First we extract the Params struct info.
+  int param_start = source.find(kParseTermParams);
+  if (param_start == std::string::npos) {
+    return absl::InternalError(
+        "Could not parse Params struct from WebGPU shader.");
+  }
+  param_start += kParseTermParamsSize;  // skip over search term
+  int param_end = source.find('}', param_start);
+  std::string param_source =
+      source.substr(param_start, param_end - param_start);
+
+  param_start = 0;
+  int offset = 0;
+  while (true) {
+    int param_split = param_source.find(':', param_start);
+    if (param_split == std::string::npos) {
+      offsets.num_params = offset;
+      return offsets;
+    }
+
+    std::string param_name =
+        ExtractParamFromTo(param_source, param_start, param_split);
+
+    int param_end = param_source.find(',', param_split);
+    if (param_end == std::string::npos) param_end = param_source.size() - 1;
+
+    std::string param_type =
+        ExtractParamFromTo(param_source, param_split + 1, param_end);
+
+    // Now we handle parameters we wish to auto-hook up:
+    //   outputSize and time
+    // And otherwise, we assume parameters will come from input streams
+    if (param_name == "outputSize") {
+      offsets.output_size_offset = offset;
+      offset += 3;  // we just always use 3, in case of depth
+    } else if (param_name == "time") {
+      offsets.time_offset = offset;
+      offset += 1;
+    } else if (param_type == "f32") {
+      offsets.float_offsets.push_back(offset);
+      offset += 1;
+    } else if (param_type == "vec2<f32>") {
+      offsets.float_vec_offsets.push_back(offset);
+      offset += 2;
+    } else if (param_type == "vec3<f32>") {
+      offsets.float_vec_offsets.push_back(offset);
+      offset += 3;
+    } else if (param_type == "vec4<f32>") {
+      offsets.float_vec_offsets.push_back(offset);
+      offset += 4;
+    } else {
+      return absl::InternalError(
+          absl::StrCat("Cannot parse Params type: ", param_type, " for ",
+                       "parameter ", param_name));
+    }
+
+    param_start = param_end + 1;
+  }
+}
+
+// We return a vector of all binding locations which match the given term.
+absl::StatusOr<std::vector<int>> GetBindingLocations(
+    const std::string& search_term, const std::string& source) {
+  std::vector<int> binding_locations;
+  std::string binding_str;
+  int next_binding_start = 0;
+  int next_binding_end;
+  while (true) {
+    next_binding_start = source.find(kParseTermBinding, next_binding_start);
+    if (next_binding_start == std::string::npos) break;
+    next_binding_start += kParseTermBindingSize;  // skip over search term
+    next_binding_end = source.find(';', next_binding_start);
+    binding_str = source.substr(next_binding_start,
+                                next_binding_end - next_binding_start);
+    if (binding_str.find(search_term) != std::string::npos) {
+      int binding_str_end = binding_str.find(')');
+      if (binding_str_end != std::string::npos) {
+        int location = std::stoi(binding_str.substr(0, binding_str_end));
+        binding_locations.push_back(location);
+      } else {
+        return absl::InternalError(
+            absl::StrCat("Binding could not be parsed at: ", binding_str));
+      }
+    }
+  }
+  return binding_locations;
+}
+
+// We expect a unique location for these, or else none at all, in which case we
+// return std::nullopt.
+absl::StatusOr<std::optional<int>> GetBindingLocation(
+    const std::string& search_term, const std::string& source) {
+  MP_ASSIGN_OR_RETURN(const auto& locations,
+                      GetBindingLocations(search_term, source));
+  if (locations.size() > 1) {
+    return absl::InternalError(absl::StrFormat(
+        "Expected a unique binding location for %s, but found %d.", search_term,
+        locations.size()));
+  }
+  if (locations.empty()) return std::nullopt;
+  return locations[0];
+}
+
+// We return a vector of the workgroup sizes.
+std::vector<int> GetWorkgroupSizes(const std::string& source) {
+  std::vector<int> results;
+  int expr_start = source.find(kParseTermWorkgroup);
+  if (expr_start == std::string::npos) return results;
+  expr_start += kParseTermWorkgroupSize;  // skip over search term
+  int expr_end = source.find(')', expr_start);
+  std::string expr_str = source.substr(expr_start, expr_end - expr_start);
+  std::vector<absl::string_view> terms = absl::StrSplit(expr_str, ',');
+  for (const auto& term : terms) {
+    int new_val;
+    if (absl::SimpleAtoi(term, &new_val)) {
+      results.push_back(new_val);
+    } else {
+      ABSL_LOG(WARNING) << "Error parsing workgroup size at: " << term << " in "
+                        << expr_str;
+    }
+  }
+  return results;
+}
+
+// We return the output format for the given texture type. Specifically, we
+// assume there is only one output in the shader which is formatted as:
+// "[TEXTURE_TYPE]<[FORMAT], write>", and we want to return [FORMAT].
+std::string GetOutputFormat(const std::string& texture_type,
+                            const std::string& source) {
+  // Find texture_type in our shader code
+  const int expr_start = source.find(texture_type);
+  if (expr_start == std::string::npos) {
+    return "Error parsing output format: cannot find " + texture_type;
+  }
+
+  // Then find the next '<' character.
+  int term_start = source.find('<', expr_start);
+  if (term_start == std::string::npos) {
+    return "Error parsing output format: cannot find starting '<'";
+  }
+  term_start++;
+
+  // We'll also find the enclosing '>' character, just so we can provide a more
+  // helpful error message if/when the term isn't formatted properly.
+  const int term_end = source.find('>', term_start);
+  if (term_end == std::string::npos) {
+    return "Error parsing output format: cannot find ending '>'";
+  }
+
+  // Then parse start of term until following ',' character.
+  const int comma = source.find(',', term_start);
+  if (comma == std::string::npos || comma > term_end) {
+    return "Error parsing output format: not of type '<FORMAT, write>'";
+  }
+
+  // Return that substring if it exists.
+  return source.substr(term_start, comma - term_start);
+}
+
+}  // namespace
+
+class WebGpuShaderCalculator
+    : public NodeImpl<NodeIntf, WebGpuShaderCalculator> {
+ public:
+  WebGpuShaderCalculator() = default;
+  WebGpuShaderCalculator(const WebGpuShaderCalculator&) = delete;
+  ~WebGpuShaderCalculator() override = default;
+
+  static constexpr auto kCalculatorName = "WebGpuShaderCalculator";
+
+  static constexpr Input<GpuBuffer>::Multiple kInputBuffers{"INPUT_BUFFER"};
+  static constexpr Input<WebGpuTextureBuffer3d>::Multiple kInputBuffers3d{
+      "INPUT_BUFFER_3D"};
+  static constexpr Input<float>::Multiple kInputFloats{"INPUT_FLOAT"};
+  static constexpr Input<std::vector<float>>::Multiple kInputFloatVecs{
+      "INPUT_FLOAT_VEC"};
+  static constexpr Input<int32_t>::Optional kInputWidth{"WIDTH"};
+  static constexpr Input<int32_t>::Optional kInputHeight{"HEIGHT"};
+  static constexpr Input<int32_t>::Optional kInputDepth{"DEPTH"};
+  static constexpr Input<AnyType>::Optional kInputTrigger{"TRIGGER"};
+  static constexpr Output<GpuBuffer>::Optional kOutput{"OUTPUT"};
+  static constexpr Output<WebGpuTextureBuffer3d>::Optional kOutput3d{
+      "OUTPUT_3D"};
+
+  MEDIAPIPE_NODE_CONTRACT(kInputBuffers, kInputBuffers3d, kInputFloats,
+                          kInputFloatVecs, kInputWidth, kInputHeight,
+                          kInputDepth, kInputTrigger, kOutput, kOutput3d);
+
+  static absl::Status UpdateContract(mediapipe::CalculatorContract* cc);
+  absl::Status Open(CalculatorContext* cc) override;
+  absl::Status Process(CalculatorContext* cc) override;
+  absl::Status Close(CalculatorContext* cc) override;
+
+ private:
+  absl::Status InitWebGpuShader();
+  void InitProfiling();
+  absl::Status WebGpuBindAndRender(
+      CalculatorContext* cc, const wgpu::ComputePipeline& pipeline, int width,
+      int height, int depth, const std::vector<WebGpuTextureView>& src_textures,
+      const std::vector<WebGpuTextureView>& src_textures_3d,
+      const std::vector<float>& src_floats,
+      const std::vector<std::vector<float>>& src_float_vecs);
+  absl::Status WebGpuBindAndRenderToView(
+      CalculatorContext* cc, const wgpu::ComputePipeline& pipeline, int width,
+      int height, int depth, const std::vector<WebGpuTextureView>& src_textures,
+      const std::vector<WebGpuTextureView>& src_textures_3d,
+      const std::vector<float>& src_floats,
+      const std::vector<std::vector<float>>& src_float_vecs,
+      WebGpuTextureView& out_view);
+  void HandleEmptyPacket(CalculatorContext* cc, int index,
+                         bool has_gpu_buffer_input,
+                         const std::string& stream_debug_name);
+
+  std::string shader_source_;
+
+  // These will be grabbed from @workgroup_size in the shader, if available.
+  size_t workgroup_size_x_ = kDefaultWorkgroupSize;
+  size_t workgroup_size_y_ = kDefaultWorkgroupSize;
+  size_t workgroup_size_z_ = kDefaultWorkgroupSize;
+
+  GpuBufferFormat output_format_ = GpuBufferFormat::kRGBA32;
+  std::optional<int32_t> output_width_;
+  std::optional<int32_t> output_height_;
+  std::optional<int32_t> output_depth_;
+
+  std::optional<int> sampler_binding_;
+  std::optional<int> output_texture_binding_;
+  std::optional<int> uniform_binding_;
+  std::vector<int> input_texture_bindings_;
+  std::vector<int> input_texture_3d_bindings_;
+
+  ParamOffsets param_offsets_;
+  uint32_t params_size_;
+  std::unique_ptr<float[]> params_data_;
+
+  bool passthrough_first_buffer_on_empty_packets_ = true;
+
+  WebGpuService* service_ = nullptr;
+  WebGpuAsyncFuture<wgpu::ComputePipeline> pipeline_future_;
+  wgpu::Buffer params_;
+  wgpu::Sampler sampler_;
+
+  // For profiling (requires extensions and Chrome Canary)
+  bool profile_ = false;
+  uint32_t repetitions_ = 1000;
+  uint32_t skip_starting_frames_ = 100;
+  wgpu::QuerySet query_set_;
+  wgpu::Buffer query_buffer_;
+  wgpu::Buffer dst_buffer_;
+  wgpu::PassTimestampWrites timestamp_writes_;
+};
+
+absl::Status WebGpuShaderCalculator::UpdateContract(
+    mediapipe::CalculatorContract* cc) {
+  RET_CHECK(kOutput(cc).IsConnected() || kOutput3d(cc).IsConnected())
+      << "Output tag expected.";
+  RET_CHECK(kOutput(cc).IsConnected() != kOutput3d(cc).IsConnected())
+      << "Only one output tag expected.";
+  RET_CHECK(kInputBuffers(cc).Count() > 0 || kInputBuffers3d(cc).Count() > 0 ||
+            kInputTrigger(cc).IsConnected())
+      << "At least one input tag expected.";
+  cc->UseService(mediapipe::kWebGpuService);
+  return absl::OkStatus();
+}
+
+absl::Status WebGpuShaderCalculator::Open(CalculatorContext* cc) {
+  // Grab our shader sources from options, or default init them.
+  const mediapipe::WebGpuShaderCalculatorOptions& options =
+      cc->Options().GetExtension(mediapipe::WebGpuShaderCalculatorOptions::ext);
+
+  if (options.has_shader_path()) {
+    std::unique_ptr<Resource> resource_shader_source;
+    MP_ASSIGN_OR_RETURN(resource_shader_source,
+                        cc->GetResources().Get(options.shader_path()));
+    shader_source_ = resource_shader_source->ToStringView();
+  } else if (options.has_shader_source()) {
+    shader_source_ = options.shader_source();
+  } else {
+    shader_source_ = kDefaultWebGpuShaderSource;
+  }
+
+  if (options.has_output_width()) {
+    output_width_ = options.output_width();
+  }
+  if (options.has_output_height()) {
+    output_height_ = options.output_height();
+  }
+  if (options.has_output_depth()) {
+    output_depth_ = options.output_depth();
+  }
+
+  if (options.has_profiling_options()) {
+    const auto profiling_options = options.profiling_options();
+    if (profiling_options.has_enable()) {
+      profile_ = profiling_options.enable();
+    }
+    if (profiling_options.has_repetitions()) {
+      repetitions_ = profiling_options.repetitions();
+    }
+    if (profiling_options.has_skip_starting_frames()) {
+      skip_starting_frames_ = profiling_options.skip_starting_frames();
+    }
+  }
+
+  // Request WebGpu resources
+  service_ = &cc->Service(kWebGpuService).GetObject();
+  MP_RETURN_IF_ERROR(InitWebGpuShader());
+  if (profile_) InitProfiling();
+
+  return absl::OkStatus();
+}
+
+void WebGpuShaderCalculator::InitProfiling() {
+  // TODO: Check for timestamp extension, so we can error out
+  // gracefully if user is running profiling in the wrong environment/setup.
+
+  ScopedWebGpuErrorHandler error_handler(
+      service_, "WebGpuShaderCalculator::InitProfiling");
+
+  // Create buffers: one for the queries, and one for exposed results.
+  // We currently have only 2 queries in our set: start and end.
+  wgpu::BufferDescriptor query_buffer_desc = {
+      .usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::QueryResolve,
+      .size = std::max(kMinQueryBufferSize, kQueryBufferByteSize),
+  };
+  query_buffer_ = service_->device().CreateBuffer(&query_buffer_desc);
+  wgpu::BufferDescriptor dst_buffer_desc = {
+      .usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst,
+      .size = std::max(kMinQueryBufferSize, kQueryBufferByteSize),
+  };
+  dst_buffer_ = service_->device().CreateBuffer(&dst_buffer_desc);
+
+  // Then make our query set
+  wgpu::QuerySetDescriptor query_set_descriptor = {
+      .type = wgpu::QueryType::Timestamp,
+      .count = 2,
+  };
+  query_set_ = service_->device().CreateQuerySet(&query_set_descriptor);
+
+  // Set our timestamp_writes_ data for quick compute pass descriptor production
+  timestamp_writes_ = {.querySet = query_set_,
+                       .beginningOfPassWriteIndex = 0,
+                       .endOfPassWriteIndex = 1};
+}
+
+absl::Status WebGpuShaderCalculator::InitWebGpuShader() {
+  ScopedWebGpuErrorHandler error_handler(
+      service_, "WebGpuShaderCalculator::InitWebGpuShader");
+  const std::string comment_free_shader_src = RemoveComments(shader_source_);
+
+  // Parse shader to grab workgroup sizes, if overridden
+  const auto workgroup_sizes = GetWorkgroupSizes(comment_free_shader_src);
+  if (!workgroup_sizes.empty()) workgroup_size_x_ = workgroup_sizes[0];
+  if (workgroup_sizes.size() > 1) workgroup_size_y_ = workgroup_sizes[1];
+  if (workgroup_sizes.size() > 2) workgroup_size_z_ = workgroup_sizes[2];
+
+  // Parse shader to grab binding locations. Try 2d first, then 3d.
+  // TODO: Allow for multiple outputs.
+  MP_ASSIGN_OR_RETURN(
+      output_texture_binding_,
+      GetBindingLocation("texture_storage_2d", comment_free_shader_src));
+  if (!output_texture_binding_) {
+    MP_ASSIGN_OR_RETURN(
+        output_texture_binding_,
+        GetBindingLocation("texture_storage_3d", comment_free_shader_src));
+    if (!output_texture_binding_) {
+      return absl::InternalError("Bound output texture needed in shader.");
+    } else {
+      // Ensure if 3D texture output that we're using the appropriate output
+      // type.
+      const std::string output_format_str =
+          GetOutputFormat("texture_storage_3d", comment_free_shader_src);
+      if (output_format_str != "rg32uint") {
+        return absl::InternalError(absl::StrFormat(
+            "Output 3D texture format not supported. Should be rg32uint. Was: "
+            "%s",
+            output_format_str));
+      }
+    }
+  } else {
+    const std::string output_format_str =
+        GetOutputFormat("texture_storage_2d", comment_free_shader_src);
+    // Choose type of WebGPU output texture from our limited subset of supported
+    // types.
+    if (output_format_str == "rgba8unorm") {
+      output_format_ = GpuBufferFormat::kRGBA32;
+    } else if (output_format_str == "rgba32float") {
+      output_format_ = GpuBufferFormat::kRGBAFloat128;
+    } else if (output_format_str == "r32float") {
+      output_format_ = GpuBufferFormat::kGrayFloat32;
+    } else {
+      return absl::InternalError(absl::StrFormat(
+          "Output 2D texture format not supported. Should be rgba8unorm, "
+          "rgba32float, or r32float. Was: %s",
+          output_format_str));
+    }
+  }
+
+  MP_ASSIGN_OR_RETURN(sampler_binding_,
+                      GetBindingLocation("sampler", comment_free_shader_src));
+  MP_ASSIGN_OR_RETURN(uniform_binding_,
+                      GetBindingLocation("Params", comment_free_shader_src));
+  MP_ASSIGN_OR_RETURN(
+      input_texture_bindings_,
+      GetBindingLocations("texture_2d", comment_free_shader_src));
+  MP_ASSIGN_OR_RETURN(
+      input_texture_3d_bindings_,
+      GetBindingLocations("texture_3d", comment_free_shader_src));
+
+  // Parse shader to grab Params uniform struct offsets
+  MP_ASSIGN_OR_RETURN(param_offsets_, GetParamOffsets(comment_free_shader_src));
+  params_data_ = std::make_unique<float[]>(param_offsets_.num_params);
+  params_size_ = param_offsets_.num_params * sizeof(float);
+
+  // Create the shader module.
+  wgpu::ShaderModuleWGSLDescriptor wgsl_desc = {};
+  wgsl_desc.code = shader_source_.c_str();
+  wgpu::ShaderModuleDescriptor shader_desc = {
+      .nextInChain = &wgsl_desc,
+  };
+  wgpu::ShaderModule module =
+      service_->device().CreateShaderModule(&shader_desc);
+
+  if (!module) {
+    return absl::InternalError("Failed to create shader module.");
+  }
+
+  // Create the compute pipeline
+  wgpu::ComputePipelineDescriptor pipeline_desc = {
+      .compute =
+          {
+              .module = module,
+              .entryPoint = "main",
+              .constantCount = 0,
+              .constants = nullptr,
+          },
+  };
+  pipeline_future_ =
+      WebGpuCreateComputePipelineAsync(service_->device(), &pipeline_desc);
+
+  // Create a uniform buffer for the parameters
+  wgpu::BufferDescriptor buffer_desc = {
+      .usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst,
+      .size = params_size_,
+  };
+  params_ = service_->device().CreateBuffer(&buffer_desc);
+  if (!params_) {
+    return absl::InternalError("Failed to create params buffer.");
+  }
+
+  // And a default sampler in case we need that too
+  wgpu::SamplerDescriptor sampler_desc = {
+      .magFilter = wgpu::FilterMode::Linear,
+      .minFilter = wgpu::FilterMode::Linear,
+  };
+  sampler_ = service_->device().CreateSampler(&sampler_desc);
+  if (!sampler_) {
+    return absl::InternalError("Failed to create sampler.");
+  }
+  return absl::OkStatus();
+}
+
+// Helper function for when we encounter an empty packet in one of our expected
+// input sets.
+void WebGpuShaderCalculator::HandleEmptyPacket(
+    CalculatorContext* cc, int index, bool has_gpu_buffer_input,
+    const std::string& stream_debug_name) {
+  if (passthrough_first_buffer_on_empty_packets_) {
+    ABSL_LOG_EVERY_N(WARNING, 100)
+        << stream_debug_name << " input stream at id: " << index
+        << " was empty. Passing through input buffer at index 0.";
+    // We pass through first normal input first if we have any streams for that,
+    // and only otherwise pass through first 3d input.
+    if (has_gpu_buffer_input) {
+      kOutput(cc).Send(*kInputBuffers(cc).begin());
+    } else {
+      kOutput3d(cc).Send(*kInputBuffers3d(cc).begin());
+    }
+  } else {
+    ABSL_LOG_EVERY_N(WARNING, 100)
+        << stream_debug_name << " input stream at id: " << index
+        << " was empty. Skipping frame.";
+  }
+}
+
+absl::Status WebGpuShaderCalculator::Process(CalculatorContext* cc) {
+  ScopedWebGpuErrorHandler scoped_error_handler(
+      service_, "WebGpuShaderCalculator::Process", cc->InputTimestamp());
+
+  MP_ASSIGN_OR_RETURN(wgpu::ComputePipeline * pipeline, pipeline_future_.Get(),
+                      _.SetCode(absl::StatusCode::kInternal).SetPrepend()
+                          << "Failed to create pipeline: ");
+
+  if (kInputWidth(cc).IsConnected() && !kInputWidth(cc).IsEmpty()) {
+    output_width_ = kInputWidth(cc).Get();
+  }
+  if (kInputHeight(cc).IsConnected() && !kInputHeight(cc).IsEmpty()) {
+    output_height_ = kInputHeight(cc).Get();
+  }
+  if (kInputDepth(cc).IsConnected() && !kInputDepth(cc).IsEmpty()) {
+    output_depth_ = kInputDepth(cc).Get();
+  }
+
+  // Setup source textures from input gpu buffers
+  const bool has_gpu_buffer_input = kInputBuffers(cc).Count() > 0;
+  std::vector<WebGpuTextureView> src_textures;
+  for (auto it = kInputBuffers(cc).begin(); it != kInputBuffers(cc).end();
+       ++it) {
+    auto packet_stream = *it;
+    if (packet_stream.IsEmpty()) {
+      if (it == kInputBuffers(cc).begin()) {
+        ABSL_LOG_EVERY_N(WARNING, 100)
+            << "GPU buffer input stream first packet was empty. "
+            << "Skipping frame.";
+      } else {
+        HandleEmptyPacket(cc, std::distance(kInputBuffers(cc).begin(), it),
+                          has_gpu_buffer_input, "GPU buffer");
+      }
+      return absl::OkStatus();
+    }
+    const auto& gpu_buffer = packet_stream.Get();
+    src_textures.push_back(gpu_buffer.GetReadView<WebGpuTextureView>());
+  }
+
+  std::vector<WebGpuTextureView> src_textures_3d;
+  for (auto it = kInputBuffers3d(cc).begin(); it != kInputBuffers3d(cc).end();
+       ++it) {
+    auto packet_stream = *it;
+    if (packet_stream.IsEmpty()) {
+      if (it == kInputBuffers3d(cc).begin() && !has_gpu_buffer_input) {
+        ABSL_LOG_EVERY_N(WARNING, 100)
+            << "3D texture buffer input stream first packet was empty,"
+            << "and no GPU buffer input stream attached. Skipping "
+            << "frame.";
+      } else {
+        HandleEmptyPacket(cc, std::distance(kInputBuffers3d(cc).begin(), it),
+                          has_gpu_buffer_input, "3D texture buffer");
+      }
+      return absl::OkStatus();
+    }
+    const auto& texture_3d = packet_stream.Get();
+    src_textures_3d.push_back(texture_3d.GetReadView());
+  }
+
+  std::vector<float> src_floats;
+  for (auto it = kInputFloats(cc).begin(); it != kInputFloats(cc).end(); ++it) {
+    auto packet_stream = *it;
+    if (packet_stream.IsEmpty()) {
+      HandleEmptyPacket(cc, std::distance(kInputFloats(cc).begin(), it),
+                        has_gpu_buffer_input, "Float uniform");
+      return absl::OkStatus();
+    }
+    src_floats.push_back(packet_stream.Get());
+  }
+
+  std::vector<std::vector<float>> src_float_vecs;
+  for (auto it = kInputFloatVecs(cc).begin(); it != kInputFloatVecs(cc).end();
+       ++it) {
+    auto packet_stream = *it;
+    if (packet_stream.IsEmpty()) {
+      HandleEmptyPacket(cc, std::distance(kInputFloatVecs(cc).begin(), it),
+                        has_gpu_buffer_input, "Float vector uniform");
+      return absl::OkStatus();
+    }
+    src_float_vecs.push_back(packet_stream.Get());
+  }
+
+  // Destination size default is 640x480 if no inputs, and otherwise, we'll
+  // use size of first input.
+  int width = 640;
+  int height = 480;
+  int depth = 0;
+
+  if (!src_textures.empty()) {
+    width = src_textures[0].width();
+    height = src_textures[0].height();
+  } else if (!src_textures_3d.empty()) {
+    width = src_textures_3d[0].width();
+    height = src_textures_3d[0].height();
+    depth = src_textures_3d[0].depth();
+  }
+
+  if (output_width_) width = output_width_.value();
+  if (output_height_) height = output_height_.value();
+  if (output_depth_) depth = output_depth_.value();
+
+  if (kOutput(cc).IsConnected() && depth > 0) {
+    depth = 0;
+    ABSL_LOG(WARNING)
+        << "Forcing depth to 0 because output tag indicates that we "
+        << "are rendering to a 2D texture, not a 3D texture.";
+  }
+
+  MP_RETURN_IF_ERROR(WebGpuBindAndRender(cc, *pipeline, width, height, depth,
+                                         src_textures, src_textures_3d,
+                                         src_floats, src_float_vecs));
+  return absl::OkStatus();
+}
+
+absl::Status WebGpuShaderCalculator::WebGpuBindAndRender(
+    CalculatorContext* cc, const wgpu::ComputePipeline& pipeline, int width,
+    int height, int depth, const std::vector<WebGpuTextureView>& src_textures,
+    const std::vector<WebGpuTextureView>& src_textures_3d,
+    const std::vector<float>& src_floats,
+    const std::vector<std::vector<float>>& src_float_vecs) {
+  ScopedWebGpuErrorHandler scoped_error_handler(
+      service_, "WebGpuShaderCalculator::WebGpuBindAndRender",
+      cc->InputTimestamp());
+  // Setup rendering to new destination GpuBuffer or WebGpuTextureBuffer3d, if
+  // not rendering to screen. TODO: Allow for different output formats.
+  if (depth == 0) {
+    // Standard 2d texture rendering
+    GpuBuffer out_buffer(width, height, output_format_);
+    WebGpuTextureView out_view = out_buffer.GetWriteView<WebGpuTextureView>();
+    MP_RETURN_IF_ERROR(WebGpuBindAndRenderToView(
+        cc, pipeline, width, height, depth, src_textures, src_textures_3d,
+        src_floats, src_float_vecs, out_view));
+    kOutput(cc).Send(std::move(out_buffer));
+  } else {
+    // Special 3d texture rendering
+    auto out_buffer = WebGpuTextureBuffer3d::Create(
+        width, height, depth, WebGpuTextureFormat3d::kRG32Uint);
+    WebGpuTextureView out_view = out_buffer->GetWriteView();
+    MP_RETURN_IF_ERROR(WebGpuBindAndRenderToView(
+        cc, pipeline, width, height, depth, src_textures, src_textures_3d,
+        src_floats, src_float_vecs, out_view));
+    kOutput3d(cc).Send(std::move(out_buffer));
+  }
+  return absl::OkStatus();
+}
+
+absl::Status WebGpuShaderCalculator::WebGpuBindAndRenderToView(
+    CalculatorContext* cc, const wgpu::ComputePipeline& pipeline, int width,
+    int height, int depth, const std::vector<WebGpuTextureView>& src_textures,
+    const std::vector<WebGpuTextureView>& src_textures_3d,
+    const std::vector<float>& src_floats,
+    const std::vector<std::vector<float>>& src_float_vecs,
+    WebGpuTextureView& out_view) {
+  ScopedWebGpuErrorHandler scoped_error_handler(
+      service_, "WebGpuShaderCalculator::WebGpuBindAndRenderToView",
+      cc->InputTimestamp());
+  const wgpu::Device& device = service_->device();
+
+  // Update Params struct
+  if (param_offsets_.output_size_offset) {
+    reinterpret_cast<int32_t*>(
+        params_data_.get())[param_offsets_.output_size_offset.value()] = width;
+    reinterpret_cast<int32_t*>(
+        params_data_.get())[param_offsets_.output_size_offset.value() + 1] =
+        height;
+    reinterpret_cast<int32_t*>(
+        params_data_.get())[param_offsets_.output_size_offset.value() + 2] =
+        depth;
+  }
+  if (param_offsets_.time_offset) {
+    params_data_[param_offsets_.time_offset.value()] =
+        cc->InputTimestamp().Seconds();
+  }
+
+  RET_CHECK_LE(src_floats.size(), param_offsets_.float_offsets.size())
+      << "Must have at least as many float uniforms as float inputs. "
+         "Potentially there is a mismatch between the shader and the graph "
+         "config.";
+
+  for (int i = 0; i < src_floats.size(); i++) {
+    params_data_[param_offsets_.float_offsets[i]] = src_floats[i];
+  }
+
+  RET_CHECK_LE(src_float_vecs.size(), param_offsets_.float_vec_offsets.size())
+      << "Must have at least as many float vector uniforms as float vector "
+         "inputs. Potentially there is a mismatch between the shader and the "
+         "graph config.";
+
+  for (int i = 0; i < src_float_vecs.size(); i++) {
+    int offset = param_offsets_.float_vec_offsets[i];
+    for (const float val : src_float_vecs[i]) {
+      params_data_[offset] = val;
+      offset++;
+    }
+  }
+
+  device.GetQueue().WriteBuffer(params_, 0, params_data_.get(), params_size_);
+
+  // Create the bind group; here's where we bind everything.
+  // TODO: Optimize, and allow for many more binding types, including
+  // uniforms.
+  // For input textures
+  uint32_t num_entries = src_textures.size() + src_textures_3d.size();
+  if (sampler_binding_) num_entries++;  // For sampler
+  num_entries++;                        // For destination texture
+  if (uniform_binding_) num_entries++;  // For Params
+
+  std::vector<wgpu::BindGroupEntry> entries;
+  entries.reserve(num_entries);
+
+  if (sampler_binding_) {
+    entries.push_back({
+        .binding = static_cast<uint32_t>(sampler_binding_.value()),
+        .sampler = sampler_,
+    });
+  }
+  int in_texture_count = 0;
+  for (auto& src_texture : src_textures) {
+    entries.push_back({
+        .binding =
+            static_cast<uint32_t>(input_texture_bindings_[in_texture_count]),
+        .textureView = src_texture.texture().CreateView(),
+    });
+    in_texture_count++;
+  }
+  in_texture_count = 0;
+  for (auto& src_texture_3d : src_textures_3d) {
+    entries.push_back({
+        .binding =
+            static_cast<uint32_t>(input_texture_3d_bindings_[in_texture_count]),
+        .textureView = src_texture_3d.texture().CreateView(),
+    });
+    in_texture_count++;
+  }
+  entries.push_back({
+      .binding = static_cast<uint32_t>(output_texture_binding_.value()),
+      .textureView = out_view.texture().CreateView(),
+  });
+  if (uniform_binding_) {
+    entries.push_back({
+        .binding = static_cast<uint32_t>(uniform_binding_.value()),
+        .buffer = params_,
+        .size = params_size_,
+    });
+  }
+
+  wgpu::BindGroupDescriptor bind_group_desc = {
+      .layout = pipeline.GetBindGroupLayout(0),
+      .entryCount = num_entries,
+      .entries = entries.data(),
+  };
+  wgpu::BindGroup bind_group = device.CreateBindGroup(&bind_group_desc);
+  if (!bind_group) {
+    return absl::InternalError("Failed to create bind group.");
+  }
+
+  // Round up the number of workgroups to cover the whole texture.
+  const uint32_t num_groups_x =
+      (out_view.width() + workgroup_size_x_ - 1) / workgroup_size_x_;
+  const uint32_t num_groups_y =
+      (out_view.height() + workgroup_size_y_ - 1) / workgroup_size_y_;
+
+  // For views onto 2d textures, depth() will still be 1, by default.
+  const uint32_t num_groups_z =
+      (out_view.depth() + workgroup_size_z_ - 1) / workgroup_size_z_;
+
+  // Create and submit a command buffer that dispatches the compute shader.
+  wgpu::ComputePassDescriptor pass_descriptor;
+  if (profile_) {
+    pass_descriptor = {
+        .timestampWrites = &timestamp_writes_,
+    };
+  } else {
+    repetitions_ = 1;           // No repetitions if not profiling
+    skip_starting_frames_ = 0;  // No frame skipping if not profiling
+  }
+  auto command_encoder = device.CreateCommandEncoder();
+  for (int i = 0; i < repetitions_ + skip_starting_frames_; ++i) {
+    auto pass_encoder = (profile_ && i == skip_starting_frames_)
+                            ? command_encoder.BeginComputePass(&pass_descriptor)
+                            : command_encoder.BeginComputePass();
+    pass_encoder.SetPipeline(pipeline);
+    pass_encoder.SetBindGroup(0, bind_group);
+    pass_encoder.DispatchWorkgroups(num_groups_x, num_groups_y, num_groups_z);
+    pass_encoder.End();
+  }
+  if (profile_) {
+    command_encoder.ResolveQuerySet(query_set_, /*firstQuery=*/0, 2,
+                                    query_buffer_, /*destinationOffset=*/0);
+    command_encoder.CopyBufferToBuffer(query_buffer_, /*offset=*/0, dst_buffer_,
+                                       /*offset=*/0, kQueryBufferByteSize);
+  }
+  wgpu::CommandBuffer command_buffers[] = {
+      command_encoder.Finish(),
+  };
+  device.GetQueue().Submit(std::size(command_buffers), command_buffers);
+
+  if (profile_) {
+    ExposeProfilingResults(cc->NodeName().c_str(), dst_buffer_.Get(),
+                           repetitions_);
+  }
+  return absl::OkStatus();
+}
+
+absl::Status WebGpuShaderCalculator::Close(CalculatorContext* cc) {
+  service_ = nullptr;
+  pipeline_future_.Reset();
+  return absl::OkStatus();
+}
+
+}  // namespace mediapipe
diff --git a/third_party/mediapipe/src/mediapipe/gpu/webgpu/webgpu_shader_calculator.proto b/third_party/mediapipe/src/mediapipe/gpu/webgpu/webgpu_shader_calculator.proto
new file mode 100644
index 0000000..05e70b2
--- /dev/null
+++ b/third_party/mediapipe/src/mediapipe/gpu/webgpu/webgpu_shader_calculator.proto
@@ -0,0 +1,41 @@
+syntax = "proto2";
+
+package mediapipe;
+
+import "mediapipe/framework/calculator.proto";
+
+message WebGpuShaderCalculatorOptions {
+  extend CalculatorOptions {
+    optional WebGpuShaderCalculatorOptions ext = 507638011;
+  }
+
+  message ProfilingOptions {
+    // Must be set to true to enable profiling. Default is false.
+    optional bool enable = 1;
+    // Number of times to repeatedly enqueue the shader on the GPU during
+    // timing. Averaging over larger values lets us amortize away the cost of
+    // the query itself.
+    optional int32 repetitions = 2;
+    // Number of times the shader will be enqueued on the GPU before timing
+    // query is started.
+    optional int32 skip_starting_frames = 3;
+  }
+
+  // The source code for the WGSL shader, if not default.
+  optional string shader_source = 1;
+
+  // The path to a file containing source code for the WGSL shader, if not
+  // default.  Will override shader_source if set.
+  optional string shader_path = 2;
+
+  // These can be used to set the output dimensions of the shader-- otherwise,
+  // the size of the first input texture will be matched, or if no input texture
+  // is given, a default size of 640x480 will be used.
+  optional int32 output_width = 3;
+  optional int32 output_height = 4;
+  // Depth is only used for 3D textures.
+  optional int32 output_depth = 6;
+
+  // Options for profiling; profiling will be disabled if not included.
+  optional ProfilingOptions profiling_options = 5;
+}
diff --git a/third_party/mediapipe/src/mediapipe/gpu/webgpu/webgpu_utils.cc b/third_party/mediapipe/src/mediapipe/gpu/webgpu/webgpu_utils.cc
index 2bb2f09..5056de26 100644
--- a/third_party/mediapipe/src/mediapipe/gpu/webgpu/webgpu_utils.cc
+++ b/third_party/mediapipe/src/mediapipe/gpu/webgpu/webgpu_utils.cc
@@ -1,6 +1,5 @@
 #include "mediapipe/gpu/webgpu/webgpu_utils.h"
 
-#include <webgpu/webgpu.h>
 #include <webgpu/webgpu_cpp.h>
 #ifdef __EMSCRIPTEN__
 #include <emscripten/em_js.h>
@@ -9,9 +8,14 @@
 
 #include <cstdint>
 #include <memory>
+#include <optional>
+#include <string>
+#include <utility>
 
+#include "absl/base/no_destructor.h"
 #include "absl/status/status.h"
 #include "absl/status/statusor.h"
+#include "absl/time/time.h"
 #include "mediapipe/framework/port/status_macros.h"
 #include "mediapipe/web/jspi_check.h"
 
@@ -19,6 +23,12 @@
 
 namespace {
 
+static absl::NoDestructor<wgpu::Instance> kWebGpuInstance([] {
+  wgpu::InstanceDescriptor instance_desc = {};
+  instance_desc.capabilities.timedWaitAnyEnable = true;
+  return wgpu::CreateInstance(&instance_desc);
+}());
+
 #ifdef __EMSCRIPTEN__
 
 EM_ASYNC_JS(void, mediapipe_map_buffer_jspi,
@@ -46,6 +56,142 @@
 
 }  // namespace
 
+template <typename T>
+WebGpuAsyncFuture<T>::WebGpuAsyncFuture(WebGpuAsyncFuture<T>&& other)
+    : future_(other.future_), result_(std::move(other.result_)) {
+  other.future_ = std::nullopt;
+}
+
+template <typename T>
+WebGpuAsyncFuture<T>::~WebGpuAsyncFuture() {
+  Reset();
+}
+
+template <typename T>
+WebGpuAsyncFuture<T>& WebGpuAsyncFuture<T>::operator=(
+    WebGpuAsyncFuture<T>&& other) {
+  Reset();  // Free the current future if any.
+  future_ = other.future_;
+  other.future_ = std::nullopt;
+  result_ = std::move(other.result_);
+  return *this;
+}
+
+template <typename T>
+absl::StatusOr<T*> WebGpuAsyncFuture<T>::Get(absl::Duration timeout) {
+  if (result_ == nullptr) {
+    return absl::FailedPreconditionError("Uninitialized WebGpuAsyncFuture.");
+  }
+
+  if (!result_->has_value()) {
+    if (!future_.has_value()) {
+      return absl::FailedPreconditionError("No value and no pending future.");
+    }
+
+    wgpu::WaitStatus wait_status = kWebGpuInstance->WaitAny(
+        future_.value(), timeout == absl::InfiniteDuration()
+                             ? UINT64_MAX
+                             : absl::ToInt64Nanoseconds(timeout));
+    if (wait_status == wgpu::WaitStatus::TimedOut) {
+      return absl::DeadlineExceededError(
+          "Timed out waiting for WebGPU future.");
+    } else if (wait_status != wgpu::WaitStatus::Success) {
+      return absl::InternalError("WebGPU future wait failed.");
+    }
+    future_ = std::nullopt;
+
+    if (!result_->has_value()) {
+      return absl::InternalError("Result not set.");
+    }
+  }
+
+  auto& value = result_->value();
+  if (value.ok()) {
+    return absl::StatusOr<T*>(&value.value());
+  } else {
+    return value.status();
+  }
+}
+
+template <typename T>
+void WebGpuAsyncFuture<T>::Reset() {
+  if (future_.has_value()) {
+    // Collect the result of the future to avoid a memory leak.
+    Get().IgnoreError();
+  }
+  future_ = std::nullopt;
+  result_ = nullptr;
+}
+
+template class WebGpuAsyncFuture<wgpu::ComputePipeline>;
+template class WebGpuAsyncFuture<wgpu::RenderPipeline>;
+
+wgpu::ShaderModule CreateWgslShader(wgpu::Device device, const char* const code,
+                                    const char* label) {
+  wgpu::ShaderModuleWGSLDescriptor wgsl;
+  wgsl.code = code;
+  wgpu::ShaderModuleDescriptor desc;
+  desc.nextInChain = &wgsl;
+  desc.label = label;
+  return device.CreateShaderModule(&desc);
+}
+
+WebGpuAsyncFuture<wgpu::ComputePipeline> WebGpuCreateComputePipelineAsync(
+    const wgpu::Device& device,
+    wgpu::ComputePipelineDescriptor const* descriptor) {
+  auto holder =
+      std::make_unique<std::optional<absl::StatusOr<wgpu::ComputePipeline>>>();
+  auto* holder_ptr = holder.get();
+
+#ifdef __EMSCRIPTEN__
+  if (!IsJspiAvailable()) {
+    *holder_ptr = device.CreateComputePipeline(descriptor);
+    return WebGpuAsyncFuture<wgpu::ComputePipeline>(std::nullopt,
+                                                    std::move(holder));
+  }
+#endif  // __EMSCRIPTEN__
+
+  auto future = device.CreateComputePipelineAsync(
+      descriptor, wgpu::CallbackMode::WaitAnyOnly,
+      [holder_ptr](wgpu::CreatePipelineAsyncStatus status,
+                   wgpu::ComputePipeline pipeline, wgpu::StringView message) {
+        if (status != wgpu::CreatePipelineAsyncStatus::Success) {
+          *holder_ptr = absl::InternalError(std::string(message));
+          return;
+        }
+        *holder_ptr = pipeline;
+      });
+  return WebGpuAsyncFuture<wgpu::ComputePipeline>(future, std::move(holder));
+}
+
+WebGpuAsyncFuture<wgpu::RenderPipeline> WebGpuCreateRenderPipelineAsync(
+    const wgpu::Device& device,
+    wgpu::RenderPipelineDescriptor const* descriptor) {
+  auto holder =
+      std::make_unique<std::optional<absl::StatusOr<wgpu::RenderPipeline>>>();
+  auto* holder_ptr = holder.get();
+
+#ifdef __EMSCRIPTEN__
+  if (!IsJspiAvailable()) {
+    *holder_ptr = device.CreateRenderPipeline(descriptor);
+    return WebGpuAsyncFuture<wgpu::RenderPipeline>(std::nullopt,
+                                                   std::move(holder));
+  }
+#endif  // __EMSCRIPTEN__
+
+  auto future = device.CreateRenderPipelineAsync(
+      descriptor, wgpu::CallbackMode::WaitAnyOnly,
+      [holder_ptr](wgpu::CreatePipelineAsyncStatus status,
+                   wgpu::RenderPipeline pipeline, wgpu::StringView message) {
+        if (status != wgpu::CreatePipelineAsyncStatus::Success) {
+          *holder_ptr = absl::InternalError(std::string(message));
+          return;
+        }
+        *holder_ptr = pipeline;
+      });
+  return WebGpuAsyncFuture<wgpu::RenderPipeline>(future, std::move(holder));
+}
+
 absl::StatusOr<uint32_t> WebGpuTextureFormatBytesPerPixel(
     wgpu::TextureFormat format) {
   switch (format) {
diff --git a/third_party/mediapipe/src/mediapipe/gpu/webgpu/webgpu_utils.h b/third_party/mediapipe/src/mediapipe/gpu/webgpu/webgpu_utils.h
index c342fed..1373b80 100644
--- a/third_party/mediapipe/src/mediapipe/gpu/webgpu/webgpu_utils.h
+++ b/third_party/mediapipe/src/mediapipe/gpu/webgpu/webgpu_utils.h
@@ -4,11 +4,44 @@
 #include <webgpu/webgpu_cpp.h>
 
 #include <cstdint>
+#include <memory>
+#include <optional>
 
 #include "absl/status/statusor.h"
+#include "absl/time/time.h"
 
 namespace mediapipe {
 
+template <typename T>
+class WebGpuAsyncFuture {
+ public:
+  WebGpuAsyncFuture<T>() = default;
+  WebGpuAsyncFuture<T>(WebGpuAsyncFuture<T>&& other);
+  ~WebGpuAsyncFuture();
+  inline explicit WebGpuAsyncFuture(
+      std::optional<wgpu::Future> future,
+      std::unique_ptr<std::optional<absl::StatusOr<T>>> result)
+      : future_(future), result_(std::move(result)) {}
+
+  WebGpuAsyncFuture<T>& operator=(WebGpuAsyncFuture<T>&& other);
+
+  absl::StatusOr<T*> Get(absl::Duration timeout = absl::InfiniteDuration());
+  void Reset();
+
+ private:
+  std::optional<wgpu::Future> future_;
+  std::unique_ptr<std::optional<absl::StatusOr<T>>> result_;
+};
+
+wgpu::ShaderModule CreateWgslShader(wgpu::Device device, const char* code,
+                                    const char* label);
+WebGpuAsyncFuture<wgpu::ComputePipeline> WebGpuCreateComputePipelineAsync(
+    const wgpu::Device& device,
+    wgpu::ComputePipelineDescriptor const* descriptor);
+WebGpuAsyncFuture<wgpu::RenderPipeline> WebGpuCreateRenderPipelineAsync(
+    const wgpu::Device& device,
+    wgpu::RenderPipelineDescriptor const* descriptor);
+
 absl::StatusOr<uint32_t> WebGpuTextureFormatBytesPerPixel(
     wgpu::TextureFormat format);
 absl::StatusOr<uint32_t> WebGpuTextureFormatDepth(wgpu::TextureFormat format);
diff --git a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection.pbtxt b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection.pbtxt
index b85d224d..93fa128 100644
--- a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection.pbtxt
+++ b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection.pbtxt
@@ -2,7 +2,7 @@
 #
 # EXAMPLE:
 #   node {
-#     calculator: "FaceDetectionFrontCpu"
+#     calculator: "FaceDetection"
 #     input_stream: "IMAGE:image"
 #     input_stream: "ROI:roi"
 #     output_stream: "DETECTIONS:face_detections"
diff --git a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_full_range.pbtxt b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_full_range.pbtxt
index b526b67..cc61024 100644
--- a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_full_range.pbtxt
+++ b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_full_range.pbtxt
@@ -6,7 +6,7 @@
 #
 # EXAMPLE:
 #   node {
-#     calculator: "FaceDetectionShortRange"
+#     calculator: "FaceDetectionFullRange"
 #     input_stream: "IMAGE:image_frame"
 #     output_stream: "DETECTIONS:face_detections"
 #   }
diff --git a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_full_range_cpu.pbtxt b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_full_range_cpu.pbtxt
index 50c0f5d..bebe0fa 100644
--- a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_full_range_cpu.pbtxt
+++ b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_full_range_cpu.pbtxt
@@ -1,4 +1,11 @@
 # MediaPipe graph to detect faces. (CPU input and inference.)
+#
+# EXAMPLE:
+#   node {
+#     calculator: "FaceDetectionFullRangeCpu"
+#     input_stream: "IMAGE:image"
+#     output_stream: "DETECTIONS:face_detections"
+#   }
 
 type: "FaceDetectionFullRangeCpu"
 
diff --git a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_full_range_gpu.pbtxt b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_full_range_gpu.pbtxt
index 52b6e361..e0a6b49 100644
--- a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_full_range_gpu.pbtxt
+++ b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_full_range_gpu.pbtxt
@@ -1,4 +1,11 @@
 # MediaPipe graph to detect faces. (GPU input and inference.)
+#
+# EXAMPLE:
+#   node {
+#     calculator: "FaceDetectionFullRangeGpu"
+#     input_stream: "IMAGE:image"
+#     output_stream: "DETECTIONS:face_detections"
+#   }
 
 type: "FaceDetectionFullRangeGpu"
 
diff --git a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_short_range_by_roi_cpu.pbtxt b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_short_range_by_roi_cpu.pbtxt
index 6dab296..e589ee3d7 100644
--- a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_short_range_by_roi_cpu.pbtxt
+++ b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_short_range_by_roi_cpu.pbtxt
@@ -1,6 +1,12 @@
 # MediaPipe graph to detect faces. (CPU input and inference, with region-of-interest.)
-
-type: "FaceDetectionShortRangeCpu"
+#
+# EXAMPLE:
+#   node {
+#     calculator: "FaceDetectionShortRangeByRoiCpu"
+#     input_stream: "IMAGE:image"
+#     output_stream: "DETECTIONS:face_detections"
+#   }
+type: "FaceDetectionShortRangeByRoiCpu"
 
 # The input image, either ImageFrame, or (multi-backend) Image.
 input_stream: "IMAGE:image"
diff --git a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_short_range_by_roi_gpu.pbtxt b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_short_range_by_roi_gpu.pbtxt
index 6f9e9e98f..1f0e3aae 100644
--- a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_short_range_by_roi_gpu.pbtxt
+++ b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_short_range_by_roi_gpu.pbtxt
@@ -1,8 +1,15 @@
 # MediaPipe graph to detect faces. (GPU input and inference, with region-of-interest.)
+#
+# EXAMPLE:
+#   node {
+#     calculator: "FaceDetectionShortRangeByRoiGpu"
+#     input_stream: "IMAGE:image"
+#     output_stream: "DETECTIONS:face_detections"
+#   }
 
-type: "FaceDetectionShortRangeGpu"
+type: "FaceDetectionShortRangeByRoiGpu"
 
-# The input image, either ImageFrame, or (multi-backend) Image.
+# The input image, either GpuBuffer, or (multi-backend) Image.
 input_stream: "IMAGE:image"
 
 # ROI (region of interest) within the given image where faces should be
diff --git a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_short_range_cpu.pbtxt b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_short_range_cpu.pbtxt
index 21b63917..fe1dfe7 100644
--- a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_short_range_cpu.pbtxt
+++ b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_short_range_cpu.pbtxt
@@ -1,5 +1,11 @@
 # MediaPipe graph to detect faces. (CPU input and inference.)
-
+#
+# EXAMPLE:
+#   node {
+#     calculator: "FaceDetectionShortRangeCpu"
+#     input_stream: "IMAGE:image"
+#     output_stream: "DETECTIONS:face_detections"
+#   }
 type: "FaceDetectionShortRangeCpu"
 
 # The input image, either ImageFrame, or (multi-backend) Image.
diff --git a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_short_range_gpu.pbtxt b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_short_range_gpu.pbtxt
index ededa13..016dd07 100644
--- a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_short_range_gpu.pbtxt
+++ b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_short_range_gpu.pbtxt
@@ -1,5 +1,11 @@
 # MediaPipe graph to detect faces. (GPU input and inference.)
-
+#
+# EXAMPLE:
+#   node {
+#     calculator: "FaceDetectionShortRangeGpu"
+#     input_stream: "IMAGE:image"
+#     output_stream: "DETECTIONS:face_detections"
+#   }
 type: "FaceDetectionShortRangeGpu"
 
 # The input image, either GpuBuffer, or (multi-backend) Image.
diff --git a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_without_roi.pbtxt b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_without_roi.pbtxt
index b728934..3bbe2d9d 100644
--- a/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_without_roi.pbtxt
+++ b/third_party/mediapipe/src/mediapipe/modules/face_detection/face_detection_without_roi.pbtxt
@@ -6,7 +6,7 @@
 #
 # EXAMPLE:
 #   node {
-#     calculator: "FaceDetectionFrontCpu"
+#     calculator: "FaceDetectionWithoutRoi"
 #     input_stream: "IMAGE:image"
 #     output_stream: "DETECTIONS:face_detections"
 #   }
diff --git a/third_party/mediapipe/src/mediapipe/tasks/BUILD b/third_party/mediapipe/src/mediapipe/tasks/BUILD
index 582fc4c..665e70e 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/BUILD
+++ b/third_party/mediapipe/src/mediapipe/tasks/BUILD
@@ -14,6 +14,14 @@
 
 package(default_visibility = ["//visibility:public"])
 
+config_setting(
+    name = "build_for_3p",
+    define_values = {
+        "BUILD_FOR_3P": "1",
+    },
+    visibility = ["//visibility:public"],
+)
+
 package_group(
     name = "internal",
     packages = [
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/c/BUILD b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/c/BUILD
index 3db359f..910fb7cb 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/c/BUILD
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/c/BUILD
@@ -15,6 +15,8 @@
 package(default_visibility = [
     "//mediapipe/tasks/ios:__subpackages__",
     "//mediapipe/tasks/java/com/google/mediapipe/tasks:__subpackages__",
+    "//mediapipe/tasks/web/genai:__subpackages__",
+    "//third_party/odml/litert:__subpackages__",
 ])
 
 cc_library(
@@ -24,8 +26,14 @@
 
 cc_library(
     name = "libllm_inference_engine_cpu",
-    srcs = ["llm_inference_engine_cpu.cc"],
-    hdrs = ["llm_inference_engine.h"],
+    srcs = ["llm_inference_engine_cpu.cc"] + select({
+        "@org_tensorflow//tensorflow:ios": ["llm_inference_engine_ios.cc"],
+        "//conditions:default": [],
+    }),
+    hdrs = ["llm_inference_engine.h"] + select({
+        "@org_tensorflow//tensorflow:ios": ["llm_inference_engine_ios.h"],
+        "//conditions:default": [],
+    }),
     tags = ["swift_module=MediaPipeTasksGenAIC"],
     deps = [
         "//mediapipe/framework/deps:file_path",
@@ -56,7 +64,13 @@
         "@org_tensorflow//tensorflow/lite/delegates/xnnpack:xnnpack_delegate_hdrs_only",
         "@org_tensorflow//tensorflow/lite/experimental/genai:genai_ops",
         "@org_tensorflow//tensorflow/lite/kernels:builtin_ops",
-    ],
+    ] + select({
+        "@org_tensorflow//tensorflow:ios": [
+            "//third_party/apple_frameworks:CoreGraphics",
+            "@skia//:mac_utils",
+        ],
+        "//conditions:default": [],
+    }),
 )
 
 cc_binary(
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/c/llm_inference_engine.h b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/c/llm_inference_engine.h
index b40df16..2dcbb59 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/c/llm_inference_engine.h
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/c/llm_inference_engine.h
@@ -39,6 +39,10 @@
 
 typedef void LlmInferenceEngine_Session;
 
+typedef void SentencePieceProcessor;
+
+typedef void Constraint;
+
 // LlmActivationDataType defines the activation data type for the model.
 typedef enum {
   // Use Default activation data type mentioned in the model metadata file.
@@ -65,6 +69,9 @@
 
   // Use GPU backend.
   kLlmPreferredBackendGpu = 1,
+
+  // Use CPU backend.
+  kLlmPreferredBackendCpu = 2,
 } LlmPreferredBackend;
 
 // LlmSessionConfig configures how to execute the model.
@@ -73,12 +80,17 @@
   const char* model_path;
 
 #ifdef __EMSCRIPTEN__
+  // Web only supports the following model loading methods:
+  // * File System loading for converted LLMs. model_path has to be set and its
+  //  name has to end with .task.
+  // * Stream loading for handwritten LLMs. read_model_fn has to be set.
+
   // Function to read model file.
   // The function returns a pointer to heap memory that contains the model file
   // contents started from `offset` with `size`.
   // Since the model file is hosted on JavaScript layer and this function copies
   // the data to the heap memory, the `mode` instructs how the source model file
-  // data should be mainuplated:
+  // data should be manipulated:
   //   0: Data will be kept in memory after read.
   //   1: Data will not be accessed again and can be discarded.
   //   2: All data has been used and can be discarded.
@@ -101,6 +113,9 @@
   // Maximum number of tokens for input and output.
   size_t max_num_tokens;
 
+  // Maximum number of images to be used for vision modality.
+  size_t max_num_images;
+
   // Number of decode steps per sync. Used by GPU only. The default value is 3.
   size_t num_decode_steps_per_sync;
 
@@ -144,6 +159,27 @@
   LlmPreferredBackend preferred_backend;
 } LlmModelSettings;
 
+// LlmPromptTemplates defines the prompt templates for the session.
+typedef struct {
+  // The prompt prefix for the user role.
+  const char* user_prefix;
+
+  // The prompt suffix for the user role.
+  const char* user_suffix;
+
+  // The prompt prefix for the model role.
+  const char* model_prefix;
+
+  // The prompt suffix for the model role.
+  const char* model_suffix;
+
+  // The prompt prefix for the system role.
+  const char* system_prefix;
+
+  // The prompt suffix for the system role.
+  const char* system_suffix;
+} LlmPromptTemplates;
+
 // LlmSessionConfig configures how to execute the model.
 typedef struct {
   // Top K number of tokens to be sampled from for each decoding step.
@@ -170,12 +206,35 @@
 
   // Whether to configure the graph to include the vision modality.
   bool enable_vision_modality;
+
+  // Prompt templates to use for the session.
+  // If not provided, the default prompt templates will be used.
+  const LlmPromptTemplates* prompt_templates;
 } LlmSessionConfig;
 
+// The config used to update the runtime behavior of the session.
+typedef struct {
+  // Top K number of tokens to be sampled from for each decoding step.
+  size_t* topk;
+
+  // Maximum cumulative probability over the tokens to sample from in each
+  // decoding step for top-p / nucleus sampling.
+  float* topp;
+
+  // Randomness when decoding the next token, 0.0f means greedy decoding.
+  float* temperature;
+
+  // random seed, for reproducible sampling.
+  size_t* random_seed;
+
+  // The constraint to use for the session.
+  Constraint* constraint;
+} SessionRuntimeConfig;
+
 // LlmResponseContext is the return type for
 // LlmInferenceEngine_Session_PredictSync.
 typedef struct {
-  // An array of string. The size of the array depends on the number of
+  // An array of strings. The size of the array depends on the number of
   // responses.
   char** response_array;
 
@@ -195,6 +254,11 @@
     const LlmModelSettings* model_settings,
     LlmInferenceEngine_Engine** engine_out, char** error_msg);
 
+// Returns the SentencePieceProcessor handle used by the engine.
+ODML_EXPORT int LlmInferenceEngine_GetSentencePieceProcessor(
+    LlmInferenceEngine_Engine* engine,
+    const SentencePieceProcessor** processor_out, char** error_msg);
+
 // Free the engine, will release ownership of resource held by the engine.
 // Resource might be freed if no sessions are referencing to it.
 ODML_EXPORT void LlmInferenceEngine_Engine_Delete(
@@ -205,8 +269,13 @@
     LlmInferenceEngine_Engine* engine, const LlmSessionConfig* session_config,
     LlmInferenceEngine_Session** session_out, char** error_msg);
 
+// Update the runtime config for the session.
+ODML_EXPORT int LlmInferenceEngine_UpdateRuntimeConfig(
+    LlmInferenceEngine_Session* session,
+    const SessionRuntimeConfig* runtime_config, char** error_msg);
+
 // Free the session, will wait until graph is done executing.
-ODML_EXPORT void LlmInferenceEngine_Session_Delete(
+ODML_EXPORT int LlmInferenceEngine_Session_Delete(
     LlmInferenceEngine_Session* session);
 
 // Add query chunk to the session. This can be called multiple times to add
@@ -239,6 +308,10 @@
     void (*callback)(void* callback_context,
                      LlmResponseContext* response_context));
 
+// Request cancellation for pending processes.
+ODML_EXPORT int LlmInferenceEngine_Session_PendingProcessCancellation(
+    LlmInferenceEngine_Session* session, char** error_msg);
+
 // Clone the provided session.
 ODML_EXPORT int LlmInferenceEngine_Session_Clone(
     LlmInferenceEngine_Session* session,
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/c/llm_inference_engine_cpu.cc b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/c/llm_inference_engine_cpu.cc
index 6939f55..8ac2308 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/c/llm_inference_engine_cpu.cc
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/c/llm_inference_engine_cpu.cc
@@ -47,11 +47,13 @@
 #include "mediapipe/tasks/cc/genai/inference/proto/transformer_params.pb.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/metadata_utils.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/model_data.h"
-#include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/scoped_file.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/xnn_utils/graph_builder.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm_builder_factory.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm_weights.h"
+// clang-format off
+#include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/scoped_file.h"
+// clang-format on
 #include "sentencepiece/src/sentencepiece_processor.h"  // from @com_google_sentencepiece
 #include "sentencepiece/src/util.h"  // from @com_google_sentencepiece
 #include "tensorflow/lite/c/common.h"
@@ -64,6 +66,8 @@
 
 namespace {
 
+using ::mediapipe::tasks::genai::llm_utils::ScopedFile;
+
 constexpr int kCheckLastKChars = 10;
 
 struct TfLiteLlm {
@@ -318,8 +322,7 @@
 absl::StatusOr<std::unique_ptr<LlmInferenceEngineCpu_Engine>>
 CreateXnnLlmCpuEngine(const LlmModelSettings* model_settings) {
   MP_ASSIGN_OR_RETURN(auto model_file,
-                      mediapipe::tasks::genai::llm_utils::ScopedFile::Open(
-                          model_settings->model_path));
+                      ScopedFile::Open(model_settings->model_path));
   MP_ASSIGN_OR_RETURN(auto model_data,
                       mediapipe::tasks::genai::llm_utils::ModelData::Create(
                           std::move(model_file)));
@@ -573,8 +576,9 @@
   return 0;
 }
 
-void LlmInferenceEngine_Session_Delete(LlmInferenceEngine_Session* session) {
+int LlmInferenceEngine_Session_Delete(LlmInferenceEngine_Session* session) {
   delete reinterpret_cast<LlmInferenceEngineCpu_Session*>(session);
+  return 0;
 }
 
 int LlmInferenceEngine_Session_AddQueryChunk(
@@ -679,6 +683,12 @@
   return 0;
 }
 
+int LlmInferenceEngine_Session_PendingProcessCancellation(
+    LlmInferenceEngine_Session* session, char** error_msg) {
+  *error_msg = strdup("Not implemented");
+  return 12;
+}
+
 int LlmInferenceEngine_Session_Clone(
     LlmInferenceEngine_Session* session,
     LlmInferenceEngine_Session** cloned_session, char** error_msg) {
@@ -698,3 +708,17 @@
   }
   return output_ids.size();
 }
+
+int LlmInferenceEngine_UpdateRuntimeConfig(LlmInferenceEngine_Session* session,
+                                           const SessionRuntimeConfig* config,
+                                           char** error_msg) {
+  *error_msg = strdup("Not implemented");
+  return 12;
+}
+
+int LlmInferenceEngine_GetSentencePieceProcessor(
+    LlmInferenceEngine_Engine* engine,
+    const SentencePieceProcessor** processor_out, char** error_msg) {
+  *error_msg = strdup("Not implemented");
+  return 12;
+}
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/c/llm_inference_engine_cpu_main.cc b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/c/llm_inference_engine_cpu_main.cc
index 7825a8fe..36d93373 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/c/llm_inference_engine_cpu_main.cc
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/c/llm_inference_engine_cpu_main.cc
@@ -66,7 +66,7 @@
 ABSL_FLAG(
     std::optional<std::string>, prompt, std::nullopt,
     "The input prompt to be fed to the model. The flag is not relevant when "
-    "running the benchmark, i.e. the input_token_limits value is set.");
+    "running the benchmark, i.e. the input_token_limit value is set.");
 
 namespace {
 
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/calculators/BUILD b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/calculators/BUILD
index df5bcc69..08ffb6d 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/calculators/BUILD
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/calculators/BUILD
@@ -16,6 +16,7 @@
 
 package(default_visibility = [
     "//mediapipe/tasks:__subpackages__",
+    "//third_party/odml/litert_lm/runtime:__subpackages__",
     "//third_party/odml/vogo:__subpackages__",
 ])
 
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/common/mdspan.h b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/common/mdspan.h
index ec123e6..c9486fb 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/common/mdspan.h
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/common/mdspan.h
@@ -59,7 +59,7 @@
 }  // namespace mdspan_internal
 
 template <typename T>
-MdSpan<T, 1> MakeMdSpan(absl::Nonnull<T*> data, size_t d1,
+MdSpan<T, 1> MakeMdSpan(T* /*absl_nonnull - not yet supported*/ data, size_t d1,
                         std::function<void()> deleter = nullptr) {
   auto delete_helper =
       deleter
@@ -68,8 +68,8 @@
   return MdSpan<T, 1>(data, {d1}, delete_helper);
 }
 template <typename T>
-MdSpan<T, 2> MakeMdSpan(absl::Nonnull<T*> data, size_t d1, size_t d2,
-                        std::function<void()> deleter = nullptr) {
+MdSpan<T, 2> MakeMdSpan(T* /*absl_nonnull - not yet supported*/ data, size_t d1,
+                        size_t d2, std::function<void()> deleter = nullptr) {
   auto delete_helper =
       deleter
           ? std::make_shared<mdspan_internal::DeleteHelper>(std::move(deleter))
@@ -77,7 +77,8 @@
   return MdSpan<T, 2>(data, {d1, d2}, delete_helper);
 }
 template <typename T>
-MdSpan<T, 3> MakeMdSpan(absl::Nonnull<T*> data, size_t d1, size_t d2, size_t d3,
+MdSpan<T, 3> MakeMdSpan(T* /*absl_nonnull - not yet supported*/ data, size_t d1,
+                        size_t d2, size_t d3,
                         std::function<void()> deleter = nullptr) {
   auto delete_helper =
       deleter
@@ -86,8 +87,9 @@
   return MdSpan<T, 3>(data, {d1, d2, d3}, delete_helper);
 }
 template <typename T>
-MdSpan<T, 4> MakeMdSpan(absl::Nonnull<T*> data, size_t d1, size_t d2, size_t d3,
-                        size_t d4, std::function<void()> deleter = nullptr) {
+MdSpan<T, 4> MakeMdSpan(T* /*absl_nonnull - not yet supported*/ data, size_t d1,
+                        size_t d2, size_t d3, size_t d4,
+                        std::function<void()> deleter = nullptr) {
   auto delete_helper =
       deleter
           ? std::make_shared<mdspan_internal::DeleteHelper>(std::move(deleter))
@@ -95,7 +97,7 @@
   return MdSpan<T, 4>(data, {d1, d2, d3, d4}, delete_helper);
 }
 template <typename T, typename D, typename... Sizes>
-auto MakeMdSpan(absl::Nonnull<D*> data, Sizes... sizes) {
+auto MakeMdSpan(D* /*absl_nonnull - not yet supported*/ data, Sizes... sizes) {
   return MakeMdSpan(static_cast<T*>(data), sizes...);
 }
 
@@ -178,17 +180,19 @@
 
  private:
   template <typename U>
-  friend MdSpan<U, 1> MakeMdSpan(absl::Nonnull<U*> data, size_t d1,
+  friend MdSpan<U, 1> MakeMdSpan(U* /*absl_nonnull - not yet supported*/ data,
+                                 size_t d1, std::function<void()> deleter);
+  template <typename U>
+  friend MdSpan<U, 2> MakeMdSpan(U* /*absl_nonnull - not yet supported*/ data,
+                                 size_t d1, size_t d2,
                                  std::function<void()> deleter);
   template <typename U>
-  friend MdSpan<U, 2> MakeMdSpan(absl::Nonnull<U*> data, size_t d1, size_t d2,
+  friend MdSpan<U, 3> MakeMdSpan(U* /*absl_nonnull - not yet supported*/ data,
+                                 size_t d1, size_t d2, size_t d3,
                                  std::function<void()> deleter);
   template <typename U>
-  friend MdSpan<U, 3> MakeMdSpan(absl::Nonnull<U*> data, size_t d1, size_t d2,
-                                 size_t d3, std::function<void()> deleter);
-  template <typename U>
-  friend MdSpan<U, 4> MakeMdSpan(absl::Nonnull<U*> data, size_t d1, size_t d2,
-                                 size_t d3, size_t d4,
+  friend MdSpan<U, 4> MakeMdSpan(U* /*absl_nonnull - not yet supported*/ data,
+                                 size_t d1, size_t d2, size_t d3, size_t d4,
                                  std::function<void()> deleter);
   // MdSpan with arbitrary type/rank.
   template <typename U, size_t K>
@@ -228,7 +232,8 @@
     }
   }
 
-  MdSpan(absl::Nonnull<T*> data, std::array<size_t, Rank> shape,
+  MdSpan(T* /*absl_nonnull - not yet supported*/ data,
+         std::array<size_t, Rank> shape,
          std::shared_ptr<mdspan_internal::DeleteHelper> deleter)
       : shape_internal(std::move(shape)), delete_helper(std::move(deleter)) {
     flattened = absl::MakeSpan(data, size());
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/proto/BUILD b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/proto/BUILD
index bf5a8d7..81ac585 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/proto/BUILD
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/proto/BUILD
@@ -17,8 +17,10 @@
 package(default_visibility = [
     "//mediapipe/tasks:__subpackages__",
     "//mediapipe/tasks/web/genai/llm_inference:__subpackages__",
+    "//mediapipe/web/graph_runner:__subpackages__",
     "//third_party/odml/infra/genai/inference:__subpackages__",
-    "//third_party/odml/litert/llm:__subpackages__",
+    # TODO: Remove this once the litert code is moved to litert_lm.
+    "//third_party/odml/litert_lm:__subpackages__",
 ])
 
 licenses(["notice"])
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/proto/llm_params.proto b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/proto/llm_params.proto
index e613198..de8bbded 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/proto/llm_params.proto
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/proto/llm_params.proto
@@ -27,7 +27,8 @@
   // Unknown LLM model type
   LLM_MODEL_TYPE_UNKNOWN = 0;
 
-  reserved 1, 2, 3, 4, 7, 9, 10, 13, 14, 15, 16, 17, 19;
+  reserved 1, 2, 3, 4, 7, 9, 10, 13, 14, 15, 16, 17, 19, 21, 22, 23, 24, 25, 26,
+      31, 33;
 
   // FALCON RefinedWeb with 1B parameters.
   // https://huggingface.co/tiiuae/falcon-rw-1b
@@ -42,6 +43,18 @@
   // GEMMA v2 with 2B parameters.
   LLM_MODEL_TYPE_GEMMA2_2B = 18;
 
+  // GEMMA v3 with 1B parameters
+  LLM_MODEL_TYPE_GEMMA3_1B = 27;
+
+  // GEMMA v3 with 4B parameters
+  LLM_MODEL_TYPE_GEMMA3_4B = 28;
+
+  // GEMMA v3 with 12B parameters
+  LLM_MODEL_TYPE_GEMMA3_12B = 29;
+
+  // GEMMA v3 with 27B parameters
+  LLM_MODEL_TYPE_GEMMA3_27B = 30;
+
   // StableLM 4E1T with 3B parameters
   LLM_MODEL_TYPE_STABLELM_4E1T_3B = 8;
 
@@ -84,7 +97,10 @@
 
   repeated InputOutputNormalization input_output_normalizations = 7;
 
-  PromptTemplate prompt_template = 8;
+  PromptTemplate prompt_template = 8 [deprecated = true];
+
+  // Prompt templates for different roles.
+  optional PromptTemplates prompt_templates = 17;
 
   // Number of tokens to draft in a single step when using speculative decoding.
   optional int32 num_draft_tokens = 9;
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/proto/prompt_template.proto b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/proto/prompt_template.proto
index a475d45..77292e57 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/proto/prompt_template.proto
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/proto/prompt_template.proto
@@ -19,6 +19,25 @@
 option java_package = "com.google.odml.infra.proto";
 option java_outer_classname = "PromptTemplateProto";
 
+// The role of the prompt.
+// When LLM is decoding, the prompt role should be PROMPT_ROLE_MODEL.
+enum PromptRole {
+  // Unknown prompt role.
+  PROMPT_ROLE_UNKNOWN = 0;
+
+  // No prompt role.
+  PROMPT_ROLE_NONE = 1;
+
+  // User prompt role.
+  PROMPT_ROLE_USER = 2;
+
+  // Model prompt role.
+  PROMPT_ROLE_MODEL = 3;
+
+  // System prompt role.
+  PROMPT_ROLE_SYSTEM = 4;
+}
+
 // Prompt template to be used for prefill and decode calls.
 // Here is an example of the template based on Gemma's specifications here:
 // https://ai.google.dev/gemma/docs/formatting
@@ -31,7 +50,7 @@
 message PromptTemplate {
   // Text prepended to session's context on the first prefill invocation. This
   // is useful for system prompts.
-  string session_prefix = 1;
+  string session_prefix = 1 [deprecated = true];
 
   // Text prepended to the input prompt on the first chunck of the prefill call.
   // This is useful for adding start of user's turn markers.
@@ -41,3 +60,29 @@
   // for adding start of model of model's turn markers.
   string prompt_suffix = 3;
 }
+
+// A collection of prompt templates for different roles.
+// Here is an example of the template based on Gemma's specifications here:
+// https://ai.google.dev/gemma/docs/formatting
+//
+//  message prompt_templates {
+//    .user_template = {
+//      .prompt_prefix = "<start_of_turn>user\n";
+//      .prompt_suffix = "<end_of_turn>\n";
+//    }
+//    .model_template = {
+//      .prompt_prefix = "<start_of_turn>model\n ";
+//      .prompt_suffix = "<end_of_turn>\n";
+//    }
+//  }
+//
+message PromptTemplates {
+  // The template for user role.
+  optional PromptTemplate user_template = 1;
+
+  // The template for model role.
+  optional PromptTemplate model_template = 2;
+
+  // The template for system role.
+  optional PromptTemplate system_template = 3;
+}
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/proto/transformer_params.proto b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/proto/transformer_params.proto
index 9e0d871..78834ad 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/proto/transformer_params.proto
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/proto/transformer_params.proto
@@ -20,6 +20,7 @@
 option java_outer_classname = "TransformerParametersProto";
 
 // The parameters of transformer (https://arxiv.org/pdf/1706.03762.pdf)
+// Next ID: 41
 message TransformerParameters {
   // Batch size of tensors.
   int32 batch_size = 1;
@@ -89,6 +90,8 @@
     // LAYERNORM stands for Layer Normalization, see
     // https://arxiv.org/pdf/1607.06450v1.pdf for details.
     LAYER_NORM = 3;
+    // RMSNORM without scale. This is equivalent to setting all scales to 0.
+    RMS_NORM_NO_SCALE = 4;
   }
 
   message FeedForwardParameters {
@@ -156,18 +159,43 @@
     // Multi-Head-Attention by default.
     optional AttentionScaleType attention_scale_type = 5;
 
-    reserved 6;
+    // If set, determines how many tokens in the context history (before the
+    // current time step) are used for the self-attention calculation.
+    // Otherwise, the full context history is used.
+    optional int32 sliding_window_size = 6;
+
+    // If set, enables separate q and k weighted norms in the attention layer
+    // (used for Gemma3).
+    optional bool qk_norm = 7;
   }
 
   SelfAttentionParameters self_attention_parameters = 16;
 
+  reserved 39;
+
   reserved 17;
   // Whether to skip absolute positional embeddings. If the value is false, then
   // the absolute positional embeddings will be applied to the token embeddings
   // before the attention.
   bool skip_absolute_positional_embeddings = 18;
 
-  reserved 19, 20, 21, 23, 24;
+  reserved 20, 21, 23, 24;
+
+  // If set, will override the default RoPE scaling factor to be the specified
+  // value for all global layers (but will not change local attention layers).
+  optional float global_rope_scaling = 33;
+
+  // The number of local attention layers for each global attention layer. For
+  // example, if the value is 3, then the stacked transformer will have the
+  // pattern L-L-L-G-L-L-L-G- ... Note that if the value is 0, then the stacked
+  // transformer will only have global attention layers.
+  int32 num_local_layers_per_global = 19;
+
+  // If set, will override the default RoPE wavelength to be the specified
+  // value for all global layers (but will not change local attention layers).
+  optional float global_rope_wavelength = 32;
+
+  reserved 40;
 
   // Audio parameters
   // Describes where to interleave residual adapters with transformer layers.
@@ -207,4 +235,41 @@
   int32 audio_vocab_extra_dim = 30;
   // Dimension which we embed audio hard tokens to.
   int32 audio_input_embedding_dim = 31;
+
+  // Laurel configs.
+  message LaurelConfig {
+    // The embedding w/ shape [B, L, d_model] will first be projected to
+    // [B, L, laurel_rank] and then projected to [B, L, d_model].
+    optional int32 laurel_rank = 1;
+    // The scale shift for the post laurel rms normalization. The default value
+    // is 0.0f, which means no scale shift.
+    optional float post_laurel_norm_scale_shift = 2;
+  }
+  optional LaurelConfig laurel_config = 34;
+
+  // The start layer of the kv cache that is shared from the previous layers.
+  optional int32 kv_cache_shared_start_layer = 35;
+
+  // Gemma3 models are trained from bf16, so they are susceptible to overflow
+  // when run in environments without native bf16 support (especially for larger
+  // models, like 4B+). Thus, to ensure correct behavior for these models when
+  // not forcing fp32 precision, we allow for applying a special workaround.
+  optional bool gemma3_bfloat16_fix = 36;
+
+  // Altup configs.
+  message AltupConfig {
+    // The number of modalities for altup.
+    optional int32 altup_num_modalities = 1;
+    // The index of the active modality for altup.
+    optional int32 altup_active_idx = 2;
+    // Number of inputs.
+    optional int32 altup_num_inputs = 3;
+  }
+  optional AltupConfig altup_config = 37;
+
+  // Activation sparsity stddev multiplier. It depends on the specified sparsity
+  // probability. In particular, stddev_multiplier = cdf^{-1}(sparsity_prob),
+  // where cdf is the cumulative distribution function of the Gaussian
+  // distribution.
+  optional float activation_sparsity_stddev_multiplier = 38;
 }
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/BUILD b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/BUILD
index d7c515b..10c960a 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/BUILD
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/BUILD
@@ -17,9 +17,13 @@
 package(default_visibility = [
     "//mediapipe/tasks/cc:__subpackages__",
     "//third_party/odml/infra/genai/inference:__subpackages__",
+    # TODO: Remove this once the litert code is moved to litert_lm.
     "//third_party/odml/litert:__subpackages__",
+    "//third_party/odml/litert_lm:__subpackages__",
 ])
 
+# TODO: Remove this once the litert_lm code is OSS and supported in mediapipe.
+# Deprecated. Use //third_party/odml/litert_lm/runtime/util:memory_mapped_file instead.
 cc_library(
     name = "memory_mapped_file",
     srcs = select({
@@ -35,11 +39,14 @@
         "//mediapipe/framework/port:ret_check",
         "//mediapipe/framework/port:status",
         "@com_google_absl//absl/cleanup",
+        "@com_google_absl//absl/status",
         "@com_google_absl//absl/status:statusor",
         "@com_google_absl//absl/strings",
     ],
 )
 
+# TODO: Remove this once the litert_lm code is OSS and supported in mediapipe.
+# Deprecated. Use //third_party/odml/litert_lm/runtime/util:scoped_file instead.
 cc_library(
     name = "scoped_file",
     srcs = select({
@@ -54,10 +61,16 @@
     ],
 )
 
+# TODO: Remove this once the litert_lm code is OSS and supported in mediapipe.
+
 cc_library(
     name = "metadata_utils",
     srcs = ["metadata_utils.cc"],
     hdrs = ["metadata_utils.h"],
+    defines = select({
+        "//mediapipe/tasks:build_for_3p": ["BUILD_FOR_3P"],
+        "//conditions:default": [],
+    }),
     deps = [
         "//mediapipe/tasks/cc/genai/inference/proto:llm_params_cc_proto",
         "@com_google_absl//absl/algorithm:container",
@@ -70,6 +83,23 @@
     ],
 )
 
+# Utility library for constrained decoding.
+
+cc_library(
+    name = "bitmap",
+    hdrs = ["bitmap.h"],
+)
+
+cc_library(
+    name = "constraint_utils",
+    hdrs = ["constraint_utils.h"],
+    deps = [
+        ":bitmap",
+        "@com_google_absl//absl/status:statusor",
+        "@com_google_absl//absl/strings",
+    ],
+)
+
 cc_library(
     name = "model_data",
     srcs = ["model_data.cc"],
@@ -100,8 +130,23 @@
     name = "well_known_models",
     srcs = ["well_known_models.cc"],
     hdrs = ["well_known_models.h"],
+    defines = select({
+        "//mediapipe/tasks:build_for_3p": ["BUILD_FOR_3P"],
+        "//conditions:default": [],
+    }),
     deps = [
         "//mediapipe/tasks/cc/genai/inference/proto:llm_params_cc_proto",
         "//mediapipe/tasks/cc/genai/inference/proto:transformer_params_cc_proto",
     ],
 )
+
+cc_library(
+    name = "prompt_utils",
+    srcs = ["prompt_utils.cc"],
+    hdrs = ["prompt_utils.h"],
+    deps = [
+        "//mediapipe/tasks/cc/genai/inference/proto:prompt_template_cc_proto",
+        "@com_google_absl//absl/base:core_headers",
+        "@com_google_absl//absl/status:statusor",
+    ],
+)
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file.h b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file.h
index f288275..682a40e 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file.h
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file.h
@@ -46,6 +46,12 @@
   // pointer will be carried over to the underlying path.
   static absl::StatusOr<std::unique_ptr<MemoryMappedFile>> CreateMutable(
       absl::string_view path);
+  // Creates a MemoryMappedFile object from the platform file handle. This does
+  // not take ownership of the passed handle. The `key` passed here is an
+  // optimization when mapping the same file with different offsets.
+  static absl::StatusOr<std::unique_ptr<MemoryMappedFile>> CreateMutable(
+      ScopedFile::PlatformFile file, uint64_t offset = 0u, uint64_t length = 0u,
+      absl::string_view key = "");
 
   virtual ~MemoryMappedFile() = default;
 
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file_posix.cc b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file_posix.cc
index 4409a00..f4fd37cf 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file_posix.cc
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file_posix.cc
@@ -22,7 +22,7 @@
 #include <cstring>
 #include <memory>
 
-#include "absl/cleanup/cleanup.h"
+#include "absl/status/status.h"
 #include "absl/status/statusor.h"
 #include "absl/strings/string_view.h"
 #include "mediapipe/framework/port/ret_check.h"
@@ -93,16 +93,29 @@
 absl::StatusOr<std::unique_ptr<MemoryMappedFile>>
 MemoryMappedFile::CreateMutable(absl::string_view path) {
   MP_ASSIGN_OR_RETURN(auto scoped_file, ScopedFile::OpenWritable(path));
-  int fd = scoped_file.file();
-  RET_CHECK_GE(fd, 0) << "open() failed: " << path;
-  auto close_fd = absl::MakeCleanup([fd] { close(fd); });
+  return CreateMutable(scoped_file.file());
+}
 
-  size_t length = lseek(fd, 0, SEEK_END);
+absl::StatusOr<std::unique_ptr<MemoryMappedFile>>
+MemoryMappedFile::CreateMutable(int file, uint64_t offset, uint64_t length,
+                                absl::string_view key) {
+  RET_CHECK_EQ(offset % GetOffsetAlignment(), 0)
+      << "Offset must be a multiple of page size : " << offset << ", "
+      << GetOffsetAlignment();
 
-  void* data = mmap(nullptr, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-  RET_CHECK_NE(data, MAP_FAILED)
-      << "Failed to map " << path << ", error: " << strerror(errno);
-  RET_CHECK_NE(data, nullptr) << "Failed to map: " << path;
+  size_t file_size = lseek(file, 0, SEEK_END);
+  RET_CHECK_GE(file_size, length + offset) << "Length and offset too large.";
+  if (length == 0) {
+    length = file_size - offset;
+  }
+  if (length == 0) {
+    return absl::InvalidArgumentError("Cannot mmap empty file.");
+  }
+
+  void* data =
+      mmap(nullptr, length, PROT_READ | PROT_WRITE, MAP_SHARED, file, offset);
+  RET_CHECK_NE(data, MAP_FAILED) << "Failed to map, error: " << strerror(errno);
+  RET_CHECK_NE(data, nullptr) << "Failed to map.";
 
   return std::make_unique<MemoryMappedFilePosix>(length, data);
 }
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file_win.cc b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file_win.cc
index 8063c72..f2e6098 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file_win.cc
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file_win.cc
@@ -97,20 +97,29 @@
 absl::StatusOr<std::unique_ptr<MemoryMappedFile>> MemoryMappedFile::Create(
     absl::string_view path) {
   MP_ASSIGN_OR_RETURN(auto scoped_file, ScopedFile::Open(path));
-  return CreateImpl(scoped_file.file(), 0, 0, nullptr, false);
+  return CreateImpl(scoped_file.file(), 0, 0, nullptr, /*writable=*/false);
 }
 
 // static
 absl::StatusOr<std::unique_ptr<MemoryMappedFile>> MemoryMappedFile::Create(
     HANDLE file, uint64_t offset, uint64_t length, absl::string_view key) {
   return CreateImpl(file, offset, length, key.empty() ? nullptr : key.data(),
-                    false);
+                    /*writable=*/false);
 }
 
+// static
 absl::StatusOr<std::unique_ptr<MemoryMappedFile>>
 MemoryMappedFile::CreateMutable(absl::string_view path) {
   MP_ASSIGN_OR_RETURN(auto scoped_file, ScopedFile::OpenWritable(path));
-  return CreateImpl(scoped_file.file(), 0, 0, nullptr, true);
+  return CreateImpl(scoped_file.file(), 0, 0, nullptr, /*writable=*/true);
+}
+
+// static
+absl::StatusOr<std::unique_ptr<MemoryMappedFile>>
+MemoryMappedFile::CreateMutable(HANDLE file, uint64_t offset, uint64_t length,
+                                absl::string_view key) {
+  return CreateImpl(file, offset, length, key.empty() ? nullptr : key.data(),
+                    /*writable=*/true);
 }
 
 }  // namespace mediapipe::tasks::genai::llm_utils
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/model_data.cc b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/model_data.cc
index c3db9f0..6afc70b 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/model_data.cc
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/model_data.cc
@@ -39,15 +39,20 @@
 #include "mediapipe/framework/port/status_macros.h"
 #include "mediapipe/tasks/cc/genai/inference/proto/llm_file_metadata.pb.h"
 #include "mediapipe/tasks/cc/genai/inference/proto/llm_params.pb.h"
-#include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/metadata_utils.h"
+// clang-format off
+#include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/scoped_file.h"
+// clang-format on
 #include "tensorflow/lite/model_builder.h"
 #include "tensorflow/lite/schema/schema_generated.h"
 
 namespace mediapipe::tasks::genai::llm_utils {
 namespace {
 
+using ::mediapipe::tasks::genai::llm_utils::MemoryMappedFile;
+using ::mediapipe::tasks::genai::llm_utils::ScopedFile;
+
 // The maximum size of the tflite::Model (excluding buffers).
 constexpr uint64_t kTfliteBaseSize = 1024 * 1024;
 
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/model_data.h b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/model_data.h
index 94371e7..3e9fb87 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/model_data.h
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/model_data.h
@@ -27,12 +27,18 @@
 #include "absl/types/span.h"
 #include "mediapipe/framework/port/status_macros.h"
 #include "mediapipe/tasks/cc/genai/inference/proto/llm_params.pb.h"
+
+// clang-format off
 #include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/scoped_file.h"
+// clang-format on
 #include "tensorflow/lite/model_builder.h"
 
 namespace mediapipe::tasks::genai::llm_utils {
 
+using ::mediapipe::tasks::genai::llm_utils::MemoryMappedFile;
+using ::mediapipe::tasks::genai::llm_utils::ScopedFile;
+
 // Provides access to data tied to an underlying resource. The resource may be
 // released when this object is destroyed and spans previously returned from
 // GetData() will no longer be valid.
@@ -52,7 +58,8 @@
   uint64_t offset = 0;
   uint64_t size = 0;
 };
-// Gets an offset and size which will be valid to pass to MemoryMappedFile.
+// Gets an offset and size which will be valid to pass to
+// MemoryMappedFile.
 OffsetAndSize GetAlignedOffsetAndSize(uint64_t base_offset, uint64_t base_size);
 
 // Creates a DataHolder by memory mapping `file`. `key` can be passed as an
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/prompt_utils.cc b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/prompt_utils.cc
new file mode 100644
index 0000000..941d3057
--- /dev/null
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/prompt_utils.cc
@@ -0,0 +1,85 @@
+// Copyright 2025 The MediaPipe Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/prompt_utils.h"
+
+#include <string>
+
+#include "absl/status/statusor.h"
+
+namespace mediapipe::tasks::genai::llm_utils {
+
+absl::StatusOr<std::string> GetPromptPrefixFromSinglePromptTemplate(
+    const odml::infra::proto::PromptTemplate& prompt_template,
+    odml::infra::proto::PromptRole last_prompt_role,
+    odml::infra::proto::PromptRole current_prompt_role) {
+  odml::infra::proto::PromptTemplates prompt_templates;
+  *prompt_templates.mutable_user_template() = prompt_template;
+  return GetPromptPrefixFromPromptTemplates(prompt_templates, last_prompt_role,
+                                            current_prompt_role);
+}
+
+absl::StatusOr<std::string> GetPromptPrefixFromPromptTemplates(
+    const odml::infra::proto::PromptTemplates& prompt_templates,
+    odml::infra::proto::PromptRole last_prompt_role,
+    odml::infra::proto::PromptRole current_prompt_role) {
+  std::string prompt_prefix = "";
+  if (last_prompt_role != current_prompt_role) {
+    switch (last_prompt_role) {
+      case odml::infra::proto::PromptRole::PROMPT_ROLE_USER:
+        if (prompt_templates.has_user_template()) {
+          prompt_prefix = prompt_templates.user_template().prompt_suffix();
+        }
+        break;
+      case odml::infra::proto::PromptRole::PROMPT_ROLE_MODEL:
+        if (prompt_templates.has_model_template()) {
+          prompt_prefix = prompt_templates.model_template().prompt_suffix();
+        }
+        break;
+      case odml::infra::proto::PromptRole::PROMPT_ROLE_SYSTEM:
+        if (prompt_templates.has_system_template()) {
+          prompt_prefix = prompt_templates.system_template().prompt_suffix();
+        }
+        break;
+      default:
+        break;
+    }
+
+    switch (current_prompt_role) {
+      case odml::infra::proto::PromptRole::PROMPT_ROLE_USER:
+        if (prompt_templates.has_user_template()) {
+          prompt_prefix =
+              prompt_prefix + prompt_templates.user_template().prompt_prefix();
+        }
+        break;
+      case odml::infra::proto::PromptRole::PROMPT_ROLE_MODEL:
+        if (prompt_templates.has_model_template()) {
+          prompt_prefix =
+              prompt_prefix + prompt_templates.model_template().prompt_prefix();
+        }
+        break;
+      case odml::infra::proto::PromptRole::PROMPT_ROLE_SYSTEM:
+        if (prompt_templates.has_system_template()) {
+          prompt_prefix = prompt_prefix +
+                          prompt_templates.system_template().prompt_prefix();
+        }
+        break;
+      default:
+        break;
+    }
+  }
+  return prompt_prefix;
+}
+
+}  // namespace mediapipe::tasks::genai::llm_utils
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/prompt_utils.h b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/prompt_utils.h
new file mode 100644
index 0000000..318d103
--- /dev/null
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/prompt_utils.h
@@ -0,0 +1,54 @@
+// Copyright 2025 The MediaPipe Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef MEDIAPIPE_TASKS_GENAI_INFERENCE_UTILS_LLM_UTILS_PROMPT_UTILS_H_
+#define MEDIAPIPE_TASKS_GENAI_INFERENCE_UTILS_LLM_UTILS_PROMPT_UTILS_H_
+
+#include <string>
+
+#include "absl/base/attributes.h"
+#include "absl/status/statusor.h"
+#include "mediapipe/tasks/cc/genai/inference/proto/prompt_template.pb.h"
+
+namespace mediapipe::tasks::genai::llm_utils {
+
+// Please do not use this function. It is deprecated in favor of supporting
+// multiple prompt roles via prompt templates. Please use
+// GetPromptPrefixFromPromptTemplates instead.
+// Returns the prompt prefix from the single prompt template based on the last
+// and current prompt roles.
+// prompt_template: The prompt template to reference.
+// last_prompt_role: The role of the last prompt called.
+// current_prompt_role: The role of the current prompt called.
+ABSL_DEPRECATED(
+    "Deprecated in favor of supporting multiple prompt roles via prompt "
+    "templates. Please use GetPromptPrefixFromPromptTemplates instead.")
+absl::StatusOr<std::string> GetPromptPrefixFromSinglePromptTemplate(
+    const odml::infra::proto::PromptTemplate& prompt_template,
+    odml::infra::proto::PromptRole last_prompt_role,
+    odml::infra::proto::PromptRole current_prompt_role);
+
+// Returns the prompt prefix from the prompt templates based on the last and
+// current prompt roles.
+// prompt_templates: The prompt templates to reference.
+// last_prompt_role: The role of the last prompt called.
+// current_prompt_role: The role of the current prompt called.
+absl::StatusOr<std::string> GetPromptPrefixFromPromptTemplates(
+    const odml::infra::proto::PromptTemplates& prompt_templates,
+    odml::infra::proto::PromptRole last_prompt_role,
+    odml::infra::proto::PromptRole current_prompt_role);
+
+}  // namespace mediapipe::tasks::genai::llm_utils
+
+#endif  // MEDIAPIPE_TASKS_GENAI_INFERENCE_UTILS_LLM_UTILS_PROMPT_UTILS_H_
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/well_known_models.cc b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/well_known_models.cc
index 9165967..bfe08e14 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/well_known_models.cc
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/well_known_models.cc
@@ -174,6 +174,241 @@
   return llm_params;
 }
 
+LlmParameters GetGemma3_1BParams() {
+  LlmParameters llm_params;
+  llm_params.set_start_token_id(2);
+  llm_params.add_stop_tokens("<eos>");
+  llm_params.add_stop_tokens("<end_of_turn>");
+
+  // New tokenizer
+  llm_params.set_vocab_size(262144);
+
+  // We don't use gemma3_bfloat16_fix for the 1B variant because the maximum
+  // activations so far seem to stay below the f16 max cap.
+
+  TransformerParameters& transformer_params =
+      *llm_params.mutable_transformer_parameters();
+  transformer_params.set_batch_size(kBatchSize);
+  transformer_params.set_embedding_dim(1152);
+  transformer_params.set_hidden_dimension(6 * 1152);
+  transformer_params.set_head_dimension(256);
+  transformer_params.set_num_heads(4);
+  transformer_params.set_num_stacks(26);
+  transformer_params.set_num_kv_heads(1);
+
+  transformer_params.set_pre_norm(TransformerParameters::RMS_NORM);
+  transformer_params.set_post_norm(TransformerParameters::RMS_NORM);
+  transformer_params.set_final_norm(TransformerParameters::RMS_NORM);
+  transformer_params.set_skip_absolute_positional_embeddings(true);
+  // LLLLLGLLLLLG...
+  transformer_params.set_num_local_layers_per_global(5);
+  transformer_params.set_global_rope_wavelength(1000000.0f);
+
+  TransformerParameters::SelfAttentionParameters& sa_params =
+      *transformer_params.mutable_self_attention_parameters();
+  sa_params.set_attention_mask_type(TransformerParameters::CAUSAL);
+  sa_params.set_qkv_no_bias(true);
+  sa_params.set_post_proj_no_bias(true);
+  sa_params.set_attention_scale_type(
+      TransformerParameters::SCALE_TYPE_INV_SQRT_HEAD_DIM);
+  // Disable softcap
+  sa_params.set_soft_cap_value(0.0f);
+  // Enable qk norms
+  sa_params.set_qk_norm(true);
+  sa_params.set_sliding_window_size(512);
+
+  TransformerParameters::FeedForwardParameters& ff_params =
+      *transformer_params.mutable_feed_forward_parameters();
+  ff_params.set_no_bias(true);
+  ff_params.set_activation(TransformerParameters::GELU);
+  ff_params.set_pre_norm(TransformerParameters::RMS_NORM);
+  ff_params.set_post_norm(TransformerParameters::RMS_NORM);
+
+  TransformerParameters::FinalProjectParameters& fp_params =
+      *transformer_params.mutable_final_project_parameters();
+  fp_params.set_no_bias(true);
+  // Disable soft cap.
+  fp_params.set_soft_cap_value(0.0f);
+
+  return llm_params;
+}
+
+LlmParameters GetGemma3_4BParams() {
+  LlmParameters llm_params;
+  llm_params.set_start_token_id(2);
+  llm_params.add_stop_tokens("<eos>");
+  llm_params.add_stop_tokens("<end_of_turn>");
+  // Vocab is 262144, but with MM tokens, our embedding tensors are size 262208
+  llm_params.set_vocab_size(262208);
+
+  TransformerParameters& transformer_params =
+      *llm_params.mutable_transformer_parameters();
+  transformer_params.set_batch_size(kBatchSize);
+  transformer_params.set_embedding_dim(2560);
+  transformer_params.set_hidden_dimension(2560 * 4);
+  transformer_params.set_head_dimension(256);
+  transformer_params.set_num_heads(8);
+  transformer_params.set_num_stacks(34);
+  transformer_params.set_num_kv_heads(4);
+
+  transformer_params.set_pre_norm(TransformerParameters::RMS_NORM);
+  transformer_params.set_post_norm(TransformerParameters::RMS_NORM);
+  transformer_params.set_final_norm(TransformerParameters::RMS_NORM);
+  transformer_params.set_skip_absolute_positional_embeddings(true);
+  // LLLLLGLLLLLG...
+  transformer_params.set_num_local_layers_per_global(5);
+  transformer_params.set_global_rope_wavelength(1000000.0f);
+  transformer_params.set_global_rope_scaling(8.0f);
+
+  // To allow fp16 usage when bf16 trained
+  transformer_params.set_gemma3_bfloat16_fix(true);
+
+  TransformerParameters::SelfAttentionParameters& sa_params =
+      *transformer_params.mutable_self_attention_parameters();
+  sa_params.set_attention_mask_type(TransformerParameters::CAUSAL);
+  sa_params.set_qkv_no_bias(true);
+  sa_params.set_post_proj_no_bias(true);
+  sa_params.set_attention_scale_type(
+      TransformerParameters::SCALE_TYPE_INV_SQRT_HEAD_DIM);
+  // Disable softcap
+  sa_params.set_soft_cap_value(0.0f);
+  // Enable qk norms
+  sa_params.set_qk_norm(true);
+  sa_params.set_sliding_window_size(1024);
+
+  TransformerParameters::FeedForwardParameters& ff_params =
+      *transformer_params.mutable_feed_forward_parameters();
+  ff_params.set_no_bias(true);
+  ff_params.set_activation(TransformerParameters::GELU);
+  ff_params.set_pre_norm(TransformerParameters::RMS_NORM);
+  ff_params.set_post_norm(TransformerParameters::RMS_NORM);
+
+  TransformerParameters::FinalProjectParameters& fp_params =
+      *transformer_params.mutable_final_project_parameters();
+  fp_params.set_no_bias(true);
+  // Disable soft cap.
+  fp_params.set_soft_cap_value(0.0f);
+  return llm_params;
+}
+
+LlmParameters GetGemma3_12BParams() {
+  LlmParameters llm_params;
+  llm_params.set_start_token_id(2);
+  llm_params.add_stop_tokens("<eos>");
+  llm_params.add_stop_tokens("<end_of_turn>");
+  // Vocab is 262144, but with MM tokens, our embedding tensors are size 262208
+  llm_params.set_vocab_size(262208);
+
+  TransformerParameters& transformer_params =
+      *llm_params.mutable_transformer_parameters();
+  transformer_params.set_batch_size(kBatchSize);
+  transformer_params.set_embedding_dim(3840);
+  transformer_params.set_hidden_dimension(15360);  // 3840 * 4
+  transformer_params.set_head_dimension(256);
+  transformer_params.set_num_heads(16);
+  transformer_params.set_num_stacks(48);
+  transformer_params.set_num_kv_heads(8);
+
+  transformer_params.set_pre_norm(TransformerParameters::RMS_NORM);
+  transformer_params.set_post_norm(TransformerParameters::RMS_NORM);
+  transformer_params.set_final_norm(TransformerParameters::RMS_NORM);
+  transformer_params.set_skip_absolute_positional_embeddings(true);
+  // LLLLLGLLLLLG...
+  transformer_params.set_num_local_layers_per_global(5);
+  transformer_params.set_global_rope_wavelength(1000000.0f);
+  transformer_params.set_global_rope_scaling(8.0f);
+
+  // To allow fp16 usage when bf16 trained
+  transformer_params.set_gemma3_bfloat16_fix(true);
+
+  TransformerParameters::SelfAttentionParameters& sa_params =
+      *transformer_params.mutable_self_attention_parameters();
+  sa_params.set_attention_mask_type(TransformerParameters::CAUSAL);
+  sa_params.set_qkv_no_bias(true);
+  sa_params.set_post_proj_no_bias(true);
+  sa_params.set_attention_scale_type(
+      TransformerParameters::SCALE_TYPE_INV_SQRT_HEAD_DIM);
+  // Disable softcap
+  sa_params.set_soft_cap_value(0.0f);
+  // Enable qk norms
+  sa_params.set_qk_norm(true);
+  sa_params.set_sliding_window_size(1024);
+
+  TransformerParameters::FeedForwardParameters& ff_params =
+      *transformer_params.mutable_feed_forward_parameters();
+  ff_params.set_no_bias(true);
+  ff_params.set_activation(TransformerParameters::GELU);
+  ff_params.set_pre_norm(TransformerParameters::RMS_NORM);
+  ff_params.set_post_norm(TransformerParameters::RMS_NORM);
+
+  TransformerParameters::FinalProjectParameters& fp_params =
+      *transformer_params.mutable_final_project_parameters();
+  fp_params.set_no_bias(true);
+  // Disable soft cap.
+  fp_params.set_soft_cap_value(0.0f);
+  return llm_params;
+}
+
+LlmParameters GetGemma3_27BParams() {
+  LlmParameters llm_params;
+  llm_params.set_start_token_id(2);
+  llm_params.add_stop_tokens("<eos>");
+  llm_params.add_stop_tokens("<end_of_turn>");
+  // Vocab is 262144, but with MM tokens, our embedding tensors are size 262208
+  llm_params.set_vocab_size(262208);
+
+  TransformerParameters& transformer_params =
+      *llm_params.mutable_transformer_parameters();
+  transformer_params.set_batch_size(kBatchSize);
+  transformer_params.set_embedding_dim(5376);
+  transformer_params.set_hidden_dimension(21504);  // 5376 * 4
+  transformer_params.set_head_dimension(128);      // Not 256!
+  transformer_params.set_num_heads(32);
+  transformer_params.set_num_stacks(62);
+  transformer_params.set_num_kv_heads(16);
+
+  transformer_params.set_pre_norm(TransformerParameters::RMS_NORM);
+  transformer_params.set_post_norm(TransformerParameters::RMS_NORM);
+  transformer_params.set_final_norm(TransformerParameters::RMS_NORM);
+  transformer_params.set_skip_absolute_positional_embeddings(true);
+  // LLLLLGLLLLLG...
+  transformer_params.set_num_local_layers_per_global(5);
+  transformer_params.set_global_rope_wavelength(1000000.0f);
+  transformer_params.set_global_rope_scaling(8.0f);
+
+  // To allow fp16 usage when bf16 trained
+  transformer_params.set_gemma3_bfloat16_fix(true);
+
+  TransformerParameters::SelfAttentionParameters& sa_params =
+      *transformer_params.mutable_self_attention_parameters();
+  sa_params.set_attention_mask_type(TransformerParameters::CAUSAL);
+  sa_params.set_qkv_no_bias(true);
+  sa_params.set_post_proj_no_bias(true);
+  // NOTE: This is different from previous Gemma3 models!
+  // It corresponds to `query_pre_attn_scalar = 168`, since 5376/32 = 168.
+  sa_params.set_attention_scale_type(
+      TransformerParameters::SCALE_TYPE_INV_SQRT_D_MODEL_DIV_NUM_HEADS);
+  // Disable softcap
+  sa_params.set_soft_cap_value(0.0f);
+  // Enable qk norms
+  sa_params.set_qk_norm(true);
+  sa_params.set_sliding_window_size(1024);
+
+  TransformerParameters::FeedForwardParameters& ff_params =
+      *transformer_params.mutable_feed_forward_parameters();
+  ff_params.set_no_bias(true);
+  ff_params.set_activation(TransformerParameters::GELU);
+  ff_params.set_pre_norm(TransformerParameters::RMS_NORM);
+  ff_params.set_post_norm(TransformerParameters::RMS_NORM);
+
+  TransformerParameters::FinalProjectParameters& fp_params =
+      *transformer_params.mutable_final_project_parameters();
+  fp_params.set_no_bias(true);
+  // Disable soft cap.
+  fp_params.set_soft_cap_value(0.0f);
+  return llm_params;
+}
+
 LlmParameters GetFalconRW1BParams() {
   LlmParameters llm_params;
   llm_params.set_start_token_id(1);
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/well_known_models.h b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/well_known_models.h
index f0cd8284..4a1e0378 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/well_known_models.h
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/llm_utils/well_known_models.h
@@ -23,6 +23,10 @@
 odml::infra::proto::LlmParameters GetGemma2BParams();
 odml::infra::proto::LlmParameters GetGemma7BParams();
 odml::infra::proto::LlmParameters GetGemma2_2BParams();
+odml::infra::proto::LlmParameters GetGemma3_1BParams();
+odml::infra::proto::LlmParameters GetGemma3_4BParams();
+odml::infra::proto::LlmParameters GetGemma3_12BParams();
+odml::infra::proto::LlmParameters GetGemma3_27BParams();
 odml::infra::proto::LlmParameters GetStablelm4E1T3BParams();
 odml::infra::proto::LlmParameters GetPhi2Params();
 
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/BUILD b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/BUILD
index b3fce26..897693b 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/BUILD
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/BUILD
@@ -66,6 +66,7 @@
         "@com_google_absl//absl/status",
         "@com_google_absl//absl/status:statusor",
         "@com_google_absl//absl/strings",
+        "@pthreadpool",
     ],
 )
 
@@ -181,6 +182,10 @@
     name = "llm_builder_factory",
     srcs = ["llm_builder_factory.cc"],
     hdrs = ["llm_builder_factory.h"],
+    defines = select({
+        "//mediapipe/tasks:build_for_3p": ["BUILD_FOR_3P"],
+        "//conditions:default": [],
+    }),
     deps = [
         ":falcon",
         ":graph_builder",
@@ -194,7 +199,11 @@
         "@com_google_absl//absl/status",
         "@com_google_absl//absl/status:statusor",
         "@com_google_absl//absl/strings",
-    ],
+    ] + select({
+        "//mediapipe/tasks:build_for_3p": [],
+        "//conditions:default": [
+        ],
+    }),
 )
 
 cc_library(
@@ -265,8 +274,10 @@
         "//mediapipe/framework/port:ret_check",
         "//mediapipe/framework/port:status",
         "//mediapipe/tasks/cc/genai/inference/utils/llm_utils:memory_mapped_file",
+        "//mediapipe/tasks/cc/genai/inference/utils/llm_utils:scoped_file",
         "@XNNPACK",
         "@com_google_absl//absl/container:flat_hash_map",
+        "@com_google_absl//absl/functional:overload",
         "@com_google_absl//absl/log:absl_check",
         "@com_google_absl//absl/log:absl_log",
         "@com_google_absl//absl/status",
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/graph_builder.cc b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/graph_builder.cc
index 5a2dc5b..b908cda 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/graph_builder.cc
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/graph_builder.cc
@@ -19,8 +19,10 @@
 #include <cstddef>
 #include <cstdint>
 #include <cstdlib>
+#include <cstring>
 #include <fstream>
 #include <functional>
+#include <ios>
 #include <memory>
 #include <numeric>
 #include <optional>
@@ -44,7 +46,8 @@
 #include "mediapipe/framework/port/status_macros.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/xnn_utils/utils.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/xnn_utils/xnn_tensor.h"
-#include "xnnpack.h"  // from @XNNPACK
+#include "pthreadpool.h"  // from @pthreadpool
+#include "xnnpack.h"      // from @XNNPACK
 
 namespace mediapipe::tasks::genai {
 namespace xnn_utils {
@@ -123,15 +126,6 @@
   return absl::OkStatus();
 }
 
-absl::StatusOr<std::shared_ptr<XnnWeightsCache>> CreateWeightsCache(
-    size_t buffer_size) {
-  RET_CHECK_EQ(xnn_status_success, xnn_initialize(/*allocator=*/nullptr));
-  xnn_weights_cache_t weights_cache = nullptr;
-  RET_CHECK_EQ(xnn_status_success,
-               xnn_create_weights_cache_with_size(buffer_size, &weights_cache));
-  return std::make_shared<XnnWeightsCache>(weights_cache);
-}
-
 absl::StatusOr<std::unique_ptr<XnnGraph>> XnnGraphBuilder::Build() {
   VLOG(2) << "XnnGraphBuilder::Build() building...";
   RET_CHECK_EQ(xnn_status_success, xnn_initialize(nullptr));
@@ -359,14 +353,16 @@
     }
   }
 
+  // Maybe quantize the inputs.
   std::shared_ptr<Tensor> qd_input;
-  bool use_dynamic_quantization = false;
+  bool use_dynamic_quantization = (input->datatype == xnn_datatype_fp16 ||
+                                   input->datatype == xnn_datatype_fp32) &&
+                                  (weight->datatype == xnn_datatype_qcint8 ||
+                                   weight->datatype == xnn_datatype_qcint4);
   if (runtime_configs_->use_dynamic_quantization.has_value()) {
     use_dynamic_quantization =
+        use_dynamic_quantization &&
         runtime_configs_->use_dynamic_quantization.value();
-  } else if (weight->datatype == xnn_datatype_qcint8 ||
-             weight->datatype == xnn_datatype_qcint4) {
-    use_dynamic_quantization = true;
   }
   VLOG(3) << "use_dynamic_quantization: " << use_dynamic_quantization;
   if (use_dynamic_quantization) {
@@ -388,9 +384,9 @@
       RET_CHECK_EQ(bias->num_elements, weight_dim[qc_weight->dim_scale]);
       float* bias_array = bias->DataAs<float>();
       float* scale_array = qc_weight->scale_data.get();
-      std::vector<float> workaround_bias;
+      std::vector<float> workaround_bias(bias->num_elements);
       for (size_t i = 0; i < bias->num_elements; ++i) {
-        workaround_bias.push_back(bias_array[i] / scale_array[i]);
+        workaround_bias[i] = bias_array[i] / scale_array[i];
       }
       MP_RETURN_IF_ERROR(bias->LoadFromVec(std::move(workaround_bias)));
       bias->SetMetadata(kKey, 1);
@@ -403,11 +399,11 @@
   build_steps_.push_back([input, weight, bias, params, output,
                           qd_input](xnn_subgraph_t subgraph) -> absl::Status {
     if (qd_input) {
-      // Set XNN_FLAG_MAYBE_PACK_FOR_GEMM if the weights are 4 bit.
-      uint32_t flags = weight->datatype == xnn_datatype_qcint4 ? 0x00000080 : 0;
-      RET_CHECK_EQ(xnn_status_success,
-                   xnn_define_convert(subgraph, input->tensor_id(subgraph),
-                                      qd_input->tensor_id(subgraph), flags));
+      RET_CHECK_EQ(
+          xnn_status_success,
+          xnn_define_unary(subgraph, xnn_unary_convert, /*params=*/nullptr,
+                           input->tensor_id(subgraph),
+                           qd_input->tensor_id(subgraph), /*flags=*/0));
       RET_CHECK_EQ(
           xnn_status_success,
           xnn_define_fully_connected(
@@ -436,9 +432,9 @@
     std::shared_ptr<Tensor> input, Tensor::DimsType permute) {
   RET_CHECK_EQ(input->dims.size(), permute.size());
   const auto& old_dims = input->dims;
-  std::vector<size_t> new_dims;
+  std::vector<size_t> new_dims(permute.size());
   for (size_t i = 0; i < permute.size(); ++i) {
-    new_dims.push_back(old_dims[permute[i]]);
+    new_dims[i] = old_dims[permute[i]];
   }
   MP_ASSIGN_OR_RETURN(
       auto output, IntermediateTensor(std::move(new_dims), "permute_output"));
@@ -528,11 +524,12 @@
 
   build_steps_.push_back(
       [axis, input1, input2, output](xnn_subgraph_t subgraph) -> absl::Status {
+        const uint32_t input_ids[2] = {input1->tensor_id(subgraph),
+                                       input2->tensor_id(subgraph)};
         RET_CHECK_EQ(
             xnn_status_success,
-            xnn_define_concatenate2(subgraph, axis, input1->tensor_id(subgraph),
-                                    input2->tensor_id(subgraph),
-                                    output->tensor_id(subgraph), /*flags=*/0));
+            xnn_define_concatenate(subgraph, axis, /*num_inputs=*/2, input_ids,
+                                   output->tensor_id(subgraph), /*flags=*/0));
         return absl::OkStatus();
       });
   return output;
@@ -543,14 +540,15 @@
   MP_ASSIGN_OR_RETURN(auto output,
                       IntermediateTensor(input->dims, "square_output"));
 
-  build_steps_.push_back(
-      [output, input](xnn_subgraph_t subgraph) -> absl::Status {
-        RET_CHECK_EQ(xnn_status_success,
-                     xnn_define_square(subgraph, input->tensor_id(subgraph),
-                                       output->tensor_id(subgraph),
-                                       /*flags=*/0));
-        return absl::Status();
-      });
+  build_steps_.push_back([output,
+                          input](xnn_subgraph_t subgraph) -> absl::Status {
+    RET_CHECK_EQ(xnn_status_success,
+                 xnn_define_unary(
+                     subgraph, xnn_unary_square, /*params=*/nullptr,
+                     input->tensor_id(subgraph), output->tensor_id(subgraph),
+                     /*flags=*/0));
+    return absl::Status();
+  });
 
   return output;
 }
@@ -580,9 +578,10 @@
   build_steps_.push_back([output,
                           input](xnn_subgraph_t subgraph) -> absl::Status {
     RET_CHECK_EQ(xnn_status_success,
-                 xnn_define_square_root(subgraph, input->tensor_id(subgraph),
-                                        output->tensor_id(subgraph),
-                                        /*flags=*/0));
+                 xnn_define_unary(
+                     subgraph, xnn_unary_square_root, /*params=*/nullptr,
+                     input->tensor_id(subgraph), output->tensor_id(subgraph),
+                     /*flags=*/0));
     return absl::Status();
   });
 
@@ -602,10 +601,11 @@
       [input, output](xnn_subgraph_t subgraph) -> absl::Status {
         size_t reduction_axis = input->dims.size() - 1;
         RET_CHECK_EQ(xnn_status_success,
-                     xnn_define_static_mean(subgraph, 1, &reduction_axis,
-                                            input->tensor_id(subgraph),
-                                            output->tensor_id(subgraph),
-                                            /*flags=*/XNN_FLAG_KEEP_DIMS));
+                     xnn_define_static_reduce(
+                         subgraph, xnn_reduce_mean, /*num_reduction_axes=*/1,
+                         &reduction_axis, input->tensor_id(subgraph),
+                         output->tensor_id(subgraph),
+                         /*flags=*/XNN_FLAG_KEEP_DIMS));
         return absl::OkStatus();
       });
 #elif defined(XNN_FLAG_REDUCE_DIMS)
@@ -613,10 +613,11 @@
       [input, output](xnn_subgraph_t subgraph) -> absl::Status {
         size_t reduction_axis = input->dims.size() - 1;
         RET_CHECK_EQ(xnn_status_success,
-                     xnn_define_static_mean(subgraph, 1, &reduction_axis,
-                                            input->tensor_id(subgraph),
-                                            output->tensor_id(subgraph),
-                                            /*flags=*/0));
+                     xnn_define_static_reduce(
+                         subgraph, xnn_reduce_mean, /*num_reduction_axes=*/1,
+                         &reduction_axis, input->tensor_id(subgraph),
+                         output->tensor_id(subgraph),
+                         /*flags=*/0));
         return absl::OkStatus();
       });
 #else
@@ -671,15 +672,18 @@
                                          "element_add_output"));
   NewWeight(rhs);
 
-  build_steps_.push_back(
-      [lhs, rhs, output, params](xnn_subgraph_t subgraph) -> absl::Status {
-        RET_CHECK_EQ(
-            xnn_status_success,
-            xnn_define_add2(subgraph, params.out_min, params.out_max,
-                            lhs->tensor_id(subgraph), rhs->tensor_id(subgraph),
-                            output->tensor_id(subgraph), /*flags=*/0));
-        return absl::OkStatus();
-      });
+  build_steps_.push_back([lhs, rhs, output,
+                          params](xnn_subgraph_t subgraph) -> absl::Status {
+    struct xnn_binary_params binary_params;
+    binary_params.output_min = params.out_min;
+    binary_params.output_max = params.out_max;
+    RET_CHECK_EQ(
+        xnn_status_success,
+        xnn_define_binary(subgraph, xnn_binary_add, &binary_params,
+                          lhs->tensor_id(subgraph), rhs->tensor_id(subgraph),
+                          output->tensor_id(subgraph), /*flags=*/0));
+    return absl::OkStatus();
+  });
 
   return output;
 }
@@ -713,11 +717,14 @@
 
   build_steps_.push_back([lhs, rhs, output,
                           params](xnn_subgraph_t subgraph) -> absl::Status {
+    struct xnn_binary_params binary_params;
+    binary_params.output_min = params.out_min;
+    binary_params.output_max = params.out_max;
     RET_CHECK_EQ(
         xnn_status_success,
-        xnn_define_subtract(subgraph, params.out_min, params.out_max,
-                            lhs->tensor_id(subgraph), rhs->tensor_id(subgraph),
-                            output->tensor_id(subgraph), /*flags=*/0));
+        xnn_define_binary(subgraph, xnn_binary_subtract, &binary_params,
+                          lhs->tensor_id(subgraph), rhs->tensor_id(subgraph),
+                          output->tensor_id(subgraph), /*flags=*/0));
     return absl::OkStatus();
   });
 
@@ -743,11 +750,14 @@
 
   build_steps_.push_back([lhs, rhs, output,
                           params](xnn_subgraph_t subgraph) -> absl::Status {
+    struct xnn_binary_params binary_params;
+    binary_params.output_min = params.out_min;
+    binary_params.output_max = params.out_max;
     RET_CHECK_EQ(
         xnn_status_success,
-        xnn_define_multiply2(subgraph, params.out_min, params.out_max,
-                             lhs->tensor_id(subgraph), rhs->tensor_id(subgraph),
-                             output->tensor_id(subgraph), /*flags=*/0));
+        xnn_define_binary(subgraph, xnn_binary_multiply, &binary_params,
+                          lhs->tensor_id(subgraph), rhs->tensor_id(subgraph),
+                          output->tensor_id(subgraph), /*flags=*/0));
     return absl::OkStatus();
   });
 
@@ -773,9 +783,12 @@
 
   build_steps_.push_back([lhs, rhs, output,
                           params](xnn_subgraph_t subgraph) -> absl::Status {
+    struct xnn_binary_params binary_params;
+    binary_params.output_min = params.out_min;
+    binary_params.output_max = params.out_max;
     RET_CHECK_EQ(
         xnn_status_success,
-        xnn_define_divide(subgraph, params.out_min, params.out_max,
+        xnn_define_binary(subgraph, xnn_binary_divide, &binary_params,
                           lhs->tensor_id(subgraph), rhs->tensor_id(subgraph),
                           output->tensor_id(subgraph), /*flags=*/0));
     return absl::OkStatus();
@@ -858,72 +871,140 @@
 }
 
 absl::StatusOr<std::shared_ptr<Tensor>> XnnGraphBuilder::BatchMatMul(
-    std::shared_ptr<Tensor> input, std::shared_ptr<Tensor> weight,
+    std::shared_ptr<Tensor> lhs, std::shared_ptr<Tensor> rhs,
     FullConnParams params) {
-  const auto& lhs_dim = input->dims;
-  const auto& rhs_dim = weight->dims;
+  const auto& lhs_dims = lhs->dims;
+  const auto& rhs_dims = rhs->dims;
 
   // [B, N, T, S] . [B, N', H, S]
-  RET_CHECK_GE(lhs_dim.size(), 3);
-  RET_CHECK_GE(rhs_dim.size(), 3);
+  RET_CHECK_GE(lhs_dims.size(), 3);
+  RET_CHECK_GE(rhs_dims.size(), 3);
   uint32_t flags = 0;
   const size_t N =
-      std::max(lhs_dim[lhs_dim.size() - 3], rhs_dim[rhs_dim.size() - 3]);
-  const size_t T = lhs_dim[lhs_dim.size() - 2];
+      std::max(lhs_dims[lhs_dims.size() - 3], rhs_dims[rhs_dims.size() - 3]);
+  const size_t T = lhs_dims[lhs_dims.size() - 2];
   size_t H;
   if (!params.transpose) {
-    RET_CHECK_EQ(lhs_dim.back(), rhs_dim.back());
+    RET_CHECK_EQ(lhs_dims.back(), rhs_dims.back());
     flags = XNN_FLAG_TRANSPOSE_B;
-    H = rhs_dim[rhs_dim.size() - 2];
+    H = rhs_dims[rhs_dims.size() - 2];
   } else {
-    RET_CHECK_EQ(lhs_dim.back(), rhs_dim[rhs_dim.size() - 2]);
-    H = rhs_dim[rhs_dim.size() - 1];
+    RET_CHECK_EQ(lhs_dims.back(), rhs_dims[rhs_dims.size() - 2]);
+    H = rhs_dims[rhs_dims.size() - 1];
   }
 
-  size_t batch_size = lhs_dim.size() == 3 ? 1 : lhs_dim[0];
-  NewWeight(weight);
-  std::vector<size_t> dims(std::max(lhs_dim.size(), rhs_dim.size()));
+  size_t batch_size = lhs_dims.size() == 3 ? 1 : lhs_dims[0];
+  NewWeight(rhs);
+  std::vector<size_t> dims(std::max(lhs_dims.size(), rhs_dims.size()));
   dims[dims.size() - 1] = H;
   dims[dims.size() - 2] = T;
   dims[dims.size() - 3] = N;
   if (dims.size() > 3) {
     dims[0] = batch_size;
   }
+  // Check if we are computing a "Grouped Query Attention", e.g. N = kN'. If so,
+  // reshape the inputs to [B, N', k, T, S] and [B, N', 1, T, S].
+  // TODO: This should actually be done on the caller side.
+  const bool is_gqa =
+      (lhs_dims[lhs_dims.size() - 3] != rhs_dims[rhs_dims.size() - 3]) &&
+      (rhs_dims[rhs_dims.size() - 3] != 1);
+  std::shared_ptr<Tensor> lhs_reshaped;
+  std::shared_ptr<Tensor> rhs_reshaped;
+  std::shared_ptr<Tensor> output_reshaped;
+  if (is_gqa) {
+    // How many queries per key/value?
+    const size_t num_kv = rhs_dims[rhs_dims.size() - 3];
+    const size_t group_size = lhs_dims[lhs_dims.size() - 3] / num_kv;
+
+    // Expand the queries dimensions.
+    Tensor::DimsType lhs_dims_new{batch_size, num_kv, group_size, 0,
+                                  lhs_dims[lhs_dims.size() - 1]};
+    MP_ASSIGN_OR_RETURN(lhs_reshaped,
+                        IntermediateTensor(lhs_dims_new, lhs->datatype));
+
+    // Expand the key/value dimensions.
+    Tensor::DimsType rhs_dims_new{
+        batch_size, num_kv, 1,
+        params.transpose ? rhs_dims[rhs_dims.size() - 2] : 0,
+        params.transpose ? 0 : rhs_dims[rhs_dims.size() - 1]};
+    MP_ASSIGN_OR_RETURN(rhs_reshaped,
+                        IntermediateTensor(rhs_dims_new, rhs->datatype));
+
+    // Contract the output dimensions.
+    MP_ASSIGN_OR_RETURN(output_reshaped, IntermediateTensor(dims));
+  }
+
   MP_ASSIGN_OR_RETURN(auto output,
                       IntermediateTensor(dims, "batch_mat_mul_output"));
 
-  std::shared_ptr<Tensor> qd_input;
+  std::shared_ptr<Tensor> qd_lhs;
   bool use_dynamic_quantization = false;
   if (runtime_configs_->use_dynamic_quantization.has_value()) {
     use_dynamic_quantization =
         runtime_configs_->use_dynamic_quantization.value();
-  } else if (weight->datatype == xnn_datatype_qcint8 ||
-             weight->datatype == xnn_datatype_qcint4) {
+  } else if (rhs->datatype == xnn_datatype_qcint8 ||
+             rhs->datatype == xnn_datatype_qcint4) {
     use_dynamic_quantization = true;
   }
   VLOG(3) << "use_dynamic_quantization: " << use_dynamic_quantization;
   if (use_dynamic_quantization) {
     MP_ASSIGN_OR_RETURN(
-        qd_input, IntermediateTensor({input->dims.begin(), input->dims.end()},
-                                     xnn_datatype_qdint8));
+        qd_lhs, IntermediateTensor(is_gqa ? lhs_reshaped->dims : lhs->dims,
+                                   xnn_datatype_qdint8));
   }
-  build_steps_.push_back([input, output, weight, flags,
-                          qd_input](xnn_subgraph_t subgraph) -> absl::Status {
-    if (qd_input) {
+
+  build_steps_.push_back([lhs, output, rhs, flags, qd_lhs, lhs_reshaped,
+                          rhs_reshaped, output_reshaped](
+                             xnn_subgraph_t subgraph) -> absl::Status {
+    Tensor* curr_lhs = lhs.get();
+    Tensor* curr_rhs = rhs.get();
+    Tensor* curr_output = output.get();
+
+    // Reshape the inputs if needed.
+    if (lhs_reshaped && rhs_reshaped && output_reshaped) {
+      const size_t input_splits[2] = {lhs_reshaped->dims[1],
+                                      lhs_reshaped->dims[2]};
+      RET_CHECK_EQ(xnn_status_success,
+                   xnn_define_split_dim(
+                       subgraph, /*axis=*/lhs->dims.size() - 3,
+                       /*num_splits=*/2, input_splits, lhs->tensor_id(subgraph),
+                       lhs_reshaped->tensor_id(subgraph), /*flags=*/0));
+      curr_lhs = lhs_reshaped.get();
+      const size_t weight_splits[2] = {rhs_reshaped->dims[1],
+                                       rhs_reshaped->dims[2]};
+      RET_CHECK_EQ(xnn_status_success,
+                   xnn_define_split_dim(subgraph, /*axis=*/rhs->dims.size() - 3,
+                                        /*num_splits=*/2, weight_splits,
+                                        rhs->tensor_id(subgraph),
+                                        rhs_reshaped->tensor_id(subgraph),
+                                        /*flags=*/0));
+      curr_rhs = rhs_reshaped.get();
+
+      curr_output = output_reshaped.get();
+    }
+
+    // Quantize the lhs if needed.
+    if (qd_lhs) {
       RET_CHECK_EQ(
           xnn_status_success,
-          xnn_define_convert(subgraph, input->tensor_id(subgraph),
-                             qd_input->tensor_id(subgraph), /*flags=*/0));
-      RET_CHECK_EQ(
-          xnn_status_success,
-          xnn_define_batch_matrix_multiply(
-              subgraph, qd_input->tensor_id(subgraph),
-              weight->tensor_id(subgraph), output->tensor_id(subgraph), flags));
+          xnn_define_unary(subgraph, xnn_unary_convert, /*params=*/nullptr,
+                           curr_lhs->tensor_id(subgraph),
+                           qd_lhs->tensor_id(subgraph), /*flags=*/0));
+      curr_lhs = qd_lhs.get();
     } else {
-      RET_CHECK_EQ(xnn_status_success, xnn_define_batch_matrix_multiply(
-                                           subgraph, input->tensor_id(subgraph),
-                                           weight->tensor_id(subgraph),
-                                           output->tensor_id(subgraph), flags));
+      RET_CHECK_EQ(xnn_status_success,
+                   xnn_define_batch_matrix_multiply(
+                       subgraph, curr_lhs->tensor_id(subgraph),
+                       curr_rhs->tensor_id(subgraph),
+                       curr_output->tensor_id(subgraph), flags));
+    }
+
+    if (output_reshaped) {
+      RET_CHECK_EQ(
+          xnn_status_success,
+          xnn_define_fuse_dims(subgraph, /*axes_offset=*/1, /*axes_count=*/2,
+                               output_reshaped->tensor_id(subgraph),
+                               output->tensor_id(subgraph), /*flags=*/0));
     }
 
     return absl::OkStatus();
@@ -937,13 +1018,14 @@
   MP_ASSIGN_OR_RETURN(auto output,
                       IntermediateTensor(input->dims, "tanh_output"));
 
-  build_steps_.push_back(
-      [input, output](xnn_subgraph_t subgraph) -> absl::Status {
-        RET_CHECK_EQ(xnn_status_success,
-                     xnn_define_tanh(subgraph, input->tensor_id(subgraph),
-                                     output->tensor_id(subgraph), /*flags=*/0));
-        return absl::OkStatus();
-      });
+  build_steps_.push_back([input,
+                          output](xnn_subgraph_t subgraph) -> absl::Status {
+    RET_CHECK_EQ(xnn_status_success,
+                 xnn_define_unary(subgraph, xnn_unary_tanh, /*params=*/nullptr,
+                                  input->tensor_id(subgraph),
+                                  output->tensor_id(subgraph), /*flags=*/0));
+    return absl::OkStatus();
+  });
 
   return output;
 }
@@ -962,15 +1044,16 @@
   MP_ASSIGN_OR_RETURN(
       auto output, IntermediateTensor(lhs->dims, "squared_difference_output"));
 
-  build_steps_.push_back(
-      [lhs, rhs, output](xnn_subgraph_t subgraph) -> absl::Status {
-        RET_CHECK_EQ(xnn_status_success,
-                     xnn_define_squared_difference(
-                         subgraph, lhs->tensor_id(subgraph),
-                         rhs->tensor_id(subgraph), output->tensor_id(subgraph),
-                         /*flags=*/0));
-        return absl::OkStatus();
-      });
+  build_steps_.push_back([lhs, rhs,
+                          output](xnn_subgraph_t subgraph) -> absl::Status {
+    RET_CHECK_EQ(
+        xnn_status_success,
+        xnn_define_binary(subgraph, xnn_binary_squared_difference,
+                          /*params=*/nullptr, lhs->tensor_id(subgraph),
+                          rhs->tensor_id(subgraph), output->tensor_id(subgraph),
+                          /*flags=*/0));
+    return absl::OkStatus();
+  });
 
   return output;
 }
@@ -1175,8 +1258,11 @@
 
   build_steps_.push_back(
       [input, output, params](xnn_subgraph_t subgraph) -> absl::Status {
+        union xnn_unary_params unary_params;
+        unary_params.clamp.min = params.out_min;
+        unary_params.clamp.max = params.out_max;
         RET_CHECK_EQ(xnn_status_success,
-                     xnn_define_clamp(subgraph, params.out_min, params.out_max,
+                     xnn_define_unary(subgraph, xnn_unary_clamp, &unary_params,
                                       input->tensor_id(subgraph),
                                       output->tensor_id(subgraph),
                                       /*flags=*/0));
@@ -1190,14 +1276,15 @@
     std::shared_ptr<Tensor> input) {
   MP_ASSIGN_OR_RETURN(auto output,
                       IntermediateTensor(input->dims, "gelu_output"));
-  build_steps_.push_back(
-      [output, input](xnn_subgraph_t subgraph) -> absl::Status {
-        RET_CHECK_EQ(xnn_status_success,
-                     xnn_define_gelu(subgraph, input->tensor_id(subgraph),
-                                     output->tensor_id(subgraph),
-                                     /*flags=*/0));
-        return absl::Status();
-      });
+  build_steps_.push_back([output,
+                          input](xnn_subgraph_t subgraph) -> absl::Status {
+    RET_CHECK_EQ(xnn_status_success,
+                 xnn_define_unary(subgraph, xnn_unary_gelu, /*params=*/nullptr,
+                                  input->tensor_id(subgraph),
+                                  output->tensor_id(subgraph),
+                                  /*flags=*/0));
+    return absl::Status();
+  });
   return output;
 }
 
@@ -1205,14 +1292,15 @@
     std::shared_ptr<Tensor> input) {
   MP_ASSIGN_OR_RETURN(auto output,
                       IntermediateTensor(input->dims, "sigmoid_output"));
-  build_steps_.push_back(
-      [output, input](xnn_subgraph_t subgraph) -> absl::Status {
-        RET_CHECK_EQ(xnn_status_success,
-                     xnn_define_sigmoid(subgraph, input->tensor_id(subgraph),
-                                        output->tensor_id(subgraph),
-                                        /*flags=*/0));
-        return absl::Status();
-      });
+  build_steps_.push_back([output,
+                          input](xnn_subgraph_t subgraph) -> absl::Status {
+    RET_CHECK_EQ(xnn_status_success,
+                 xnn_define_unary(
+                     subgraph, xnn_unary_sigmoid, /*params=*/nullptr,
+                     input->tensor_id(subgraph), output->tensor_id(subgraph),
+                     /*flags=*/0));
+    return absl::Status();
+  });
   return output;
 }
 
@@ -1239,14 +1327,15 @@
   MP_ASSIGN_OR_RETURN(auto output,
                       IntermediateTensor(input->dims, "abs_output"));
 
-  build_steps_.push_back(
-      [input, output](xnn_subgraph_t subgraph) -> absl::Status {
-        RET_CHECK_EQ(xnn_status_success,
-                     xnn_define_abs(subgraph, input->tensor_id(subgraph),
-                                    output->tensor_id(subgraph),
-                                    /*flags=*/0));
-        return absl::OkStatus();
-      });
+  build_steps_.push_back([input,
+                          output](xnn_subgraph_t subgraph) -> absl::Status {
+    RET_CHECK_EQ(xnn_status_success,
+                 xnn_define_unary(subgraph, xnn_unary_abs, /*params=*/nullptr,
+                                  input->tensor_id(subgraph),
+                                  output->tensor_id(subgraph),
+                                  /*flags=*/0));
+    return absl::OkStatus();
+  });
   return output;
 }
 
@@ -1255,14 +1344,15 @@
   MP_ASSIGN_OR_RETURN(auto output,
                       IntermediateTensor(input->dims, "log_output"));
 
-  build_steps_.push_back(
-      [input, output](xnn_subgraph_t subgraph) -> absl::Status {
-        RET_CHECK_EQ(xnn_status_success,
-                     xnn_define_log(subgraph, input->tensor_id(subgraph),
-                                    output->tensor_id(subgraph),
-                                    /*flags=*/0));
-        return absl::OkStatus();
-      });
+  build_steps_.push_back([input,
+                          output](xnn_subgraph_t subgraph) -> absl::Status {
+    RET_CHECK_EQ(xnn_status_success,
+                 xnn_define_unary(subgraph, xnn_unary_log, /*params=*/nullptr,
+                                  input->tensor_id(subgraph),
+                                  output->tensor_id(subgraph),
+                                  /*flags=*/0));
+    return absl::OkStatus();
+  });
 
   return output;
 }
@@ -1273,15 +1363,16 @@
                       IntermediateTensor(OutDimsForElementwiseOp(*lhs, *rhs),
                                          "copysign_output"));
 
-  build_steps_.push_back(
-      [lhs, rhs, output](xnn_subgraph_t subgraph) -> absl::Status {
-        RET_CHECK_EQ(xnn_status_success,
-                     xnn_define_copysign(subgraph, lhs->tensor_id(subgraph),
-                                         rhs->tensor_id(subgraph),
-                                         output->tensor_id(subgraph),
-                                         /*flags=*/0));
-        return absl::OkStatus();
-      });
+  build_steps_.push_back([lhs, rhs,
+                          output](xnn_subgraph_t subgraph) -> absl::Status {
+    RET_CHECK_EQ(
+        xnn_status_success,
+        xnn_define_binary(subgraph, xnn_binary_copysign, /*params=*/nullptr,
+                          lhs->tensor_id(subgraph), rhs->tensor_id(subgraph),
+                          output->tensor_id(subgraph),
+                          /*flags=*/0));
+    return absl::OkStatus();
+  });
 
   return output;
 }
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/graph_builder.h b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/graph_builder.h
index c97dbc59..d9a432b 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/graph_builder.h
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/graph_builder.h
@@ -18,6 +18,7 @@
 #include <sys/types.h>
 
 #include <cstddef>
+#include <cstdint>
 #include <functional>
 #include <limits>
 #include <memory>
@@ -28,12 +29,12 @@
 
 #include "absl/container/flat_hash_map.h"
 #include "absl/container/flat_hash_set.h"
-#include "absl/log/absl_check.h"
 #include "absl/status/status.h"
 #include "absl/status/statusor.h"
 #include "absl/strings/string_view.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/xnn_utils/xnn_tensor.h"
-#include "xnnpack.h"  // from @XNNPACK
+#include "pthreadpool.h"  // from @pthreadpool
+#include "xnnpack.h"      // from @XNNPACK
 
 namespace mediapipe::tasks::genai {
 namespace xnn_utils {
@@ -91,9 +92,6 @@
   } activation_precision = ActivationPrecision::kFP32;
 };
 
-absl::StatusOr<std::shared_ptr<XnnWeightsCache>> CreateWeightsCache(
-    size_t buffer_size = /*XNN_DEFAULT_WEIGHTS_BUFFER_SIZE=*/1048576);
-
 class XnnGraph;
 
 // XnnGraphBuilder is used to construct XnnGraph (through Build()). Once a
@@ -210,7 +208,7 @@
   }
 
   absl::StatusOr<std::shared_ptr<Tensor>> BatchMatMul(
-      std::shared_ptr<Tensor> input, std::shared_ptr<Tensor> weight,
+      std::shared_ptr<Tensor> lhs, std::shared_ptr<Tensor> rhs,
       FullConnParams params = FullConnParams());
 
   absl::StatusOr<std::shared_ptr<Tensor>> FullConn(
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm.cc b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm.cc
index e53197d2..12394ae4 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm.cc
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm.cc
@@ -255,7 +255,7 @@
 }
 
 absl::Status Llm::LoadContext(
-    absl::Nullable<std::shared_ptr<Context>> context) {
+    /*absl_nullable - not yet supported*/ std::shared_ptr<Context> context) {
   if (!context || (context_ == context)) return absl::OkStatus();
   // There are some metadata we'd like to keep with existing context, also we'd
   // like to use pointer address to distinguish context. So the following logic
@@ -550,13 +550,61 @@
 absl::StatusOr<std::shared_ptr<Tensor>> LlmBuilder::SelfAttentionExcludeNorm(
     std::shared_ptr<Tensor> input, InputResource resource,
     const SelfAttentionWeights& sa_weights) {
+  // Dynamically quantize the input if requested.
+  const bool can_dquant_keys_proj =
+      sa_weights.k_weight->datatype == xnn_datatype_qcint8 ||
+      sa_weights.k_weight->datatype == xnn_datatype_qcint4;
+  const bool can_dquant_queries_proj =
+      sa_weights.q_weight->datatype == xnn_datatype_qcint8 ||
+      sa_weights.q_weight->datatype == xnn_datatype_qcint4;
+  const bool can_dquant_values_proj =
+      sa_weights.v_weight->datatype == xnn_datatype_qcint8 ||
+      sa_weights.v_weight->datatype == xnn_datatype_qcint4;
+  std::shared_ptr<Tensor> qd_input;
+  bool use_dynamic_quantization =
+      can_dquant_keys_proj || can_dquant_queries_proj || can_dquant_values_proj;
+  if (runtime_configs_->use_dynamic_quantization.has_value()) {
+    use_dynamic_quantization =
+        use_dynamic_quantization &&
+        runtime_configs_->use_dynamic_quantization.value();
+  }
+  VLOG(3) << "use_dynamic_quantization: " << use_dynamic_quantization;
+  if (use_dynamic_quantization) {
+    MP_ASSIGN_OR_RETURN(
+        qd_input, IntermediateTensor({input->dims.begin(), input->dims.end()},
+                                     xnn_datatype_qdint8));
+    build_steps_.push_back(
+        [input, qd_input](xnn_subgraph_t subgraph) -> absl::Status {
+          RET_CHECK_EQ(
+              xnn_status_success,
+              xnn_define_unary(subgraph, xnn_unary_convert, /*params=*/nullptr,
+                               input->tensor_id(subgraph),
+                               qd_input->tensor_id(subgraph), /*flags=*/0));
+          return absl::OkStatus();
+        });
+  }
+
   // [B, 1|T, N, H]
-  MP_ASSIGN_OR_RETURN(auto k_proj,
-                      SelfAttentionProj(input, sa_weights.k_weight));
-  MP_ASSIGN_OR_RETURN(auto q_proj,
-                      SelfAttentionProj(input, sa_weights.q_weight));
-  MP_ASSIGN_OR_RETURN(auto v_proj,
-                      SelfAttentionProj(input, sa_weights.v_weight));
+  MP_ASSIGN_OR_RETURN(
+      auto k_proj,
+      SelfAttentionProj(qd_input && can_dquant_keys_proj ? qd_input : input,
+                        sa_weights.k_weight));
+  MP_ASSIGN_OR_RETURN(
+      auto q_proj,
+      SelfAttentionProj(qd_input && can_dquant_queries_proj ? qd_input : input,
+                        sa_weights.q_weight));
+  MP_ASSIGN_OR_RETURN(
+      auto v_proj,
+      SelfAttentionProj(qd_input && can_dquant_values_proj ? qd_input : input,
+                        sa_weights.v_weight));
+
+  // Apply QK-Normalization.
+  if (llm_params_.sa_params.qk_norm) {
+    MP_ASSIGN_OR_RETURN(q_proj, ApplyNorm(q_proj, sa_weights.q_norm_weight,
+                                          LlmParams::Norm::RMS_NORM));
+    MP_ASSIGN_OR_RETURN(k_proj, ApplyNorm(k_proj, sa_weights.k_norm_weight,
+                                          LlmParams::Norm::RMS_NORM));
+  }
 
   MP_ASSIGN_OR_RETURN(auto query_proj_after_rope,
                       Rope(q_proj, resource.segment_pos));
@@ -875,6 +923,7 @@
                       Permute(query_after_scale, {0, 2, 1, 3}));
   // BSN'H -> BN'SH
   MP_ASSIGN_OR_RETURN(auto key_permuted, Permute(key_proj, {0, 2, 1, 3}));
+
   // einsum(BNTH.BN'SH -> BNTS)
   MP_ASSIGN_OR_RETURN(auto logits, QKVAttention(query_permuted, key_permuted,
                                                 {0, llm_params_.head_dim_H}));
@@ -912,6 +961,10 @@
       MP_ASSIGN_OR_RETURN(output, RmsNorm(input, weights_val));
       break;
     }
+    case LlmParams::Norm::RMS_NORM_NO_SCALE: {
+      MP_ASSIGN_OR_RETURN(output, RmsNorm(input, nullptr));
+      break;
+    }
     case LlmParams::Norm::LAYER_NORM: {
       const auto& layer_norm_weights =
           std::get<LayerNormWeights>(weights.value());
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm.h b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm.h
index 74b794e..726f04b 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm.h
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm.h
@@ -143,7 +143,7 @@
   // If `context` is non-null, and different from existing context_, load the
   // context into the model.
   virtual absl::Status LoadContext(
-      absl::Nullable<std::shared_ptr<Context>> context);
+      /*absl_nullable - not yet supported*/ std::shared_ptr<Context> context);
 
   // protected:
   friend class PrefixDecodeLlm;
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm_builder_factory.cc b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm_builder_factory.cc
index 4b23fcc9..f1da3ed 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm_builder_factory.cc
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm_builder_factory.cc
@@ -57,6 +57,10 @@
     case odml::infra::proto::LLM_MODEL_TYPE_GEMMA_2B:
       ABSL_FALLTHROUGH_INTENDED;
     case odml::infra::proto::LLM_MODEL_TYPE_GEMMA_7B:
+      ABSL_FALLTHROUGH_INTENDED;
+    case odml::infra::proto::LLM_MODEL_TYPE_GEMMA2_2B:
+      ABSL_FALLTHROUGH_INTENDED;
+    case odml::infra::proto::LLM_MODEL_TYPE_GEMMA3_1B:
       builder = std::make_unique<LlmBuilder>(llm_params, std::move(sampler),
                                              std::move(runtime_configs));
       break;
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm_weights.cc b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm_weights.cc
index 07259e6..204a80b 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm_weights.cc
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm_weights.cc
@@ -62,6 +62,8 @@
       return LlmParams::Norm::RMS_NORM;
     case TransformerParameters::LAYER_NORM:
       return LlmParams::Norm::LAYER_NORM;
+    case TransformerParameters::RMS_NORM_NO_SCALE:
+      return LlmParams::Norm::RMS_NORM_NO_SCALE;
     default:
       ABSL_LOG(DFATAL) << "Unknown norm type: " << norm_type;
   }
@@ -86,6 +88,9 @@
           weight_accessor.LoadWeight(absl::StrCat(basename, ".scale"), dims));
       return rms_norm_weights;
     }
+    case LlmParams::Norm::RMS_NORM_NO_SCALE: {
+      break;
+    }
     case LlmParams::Norm::LAYER_NORM: {
       RET_CHECK_EQ(dims.size(), 1);
       auto layer_norm_weights = LayerNormWeights();
@@ -188,6 +193,8 @@
           transformer_params.post_norm());
   params.sa_params.soft_cap_value =
       transformer_params.self_attention_parameters().soft_cap_value();
+  params.sa_params.qk_norm =
+      transformer_params.self_attention_parameters().qk_norm();
   params.ff_params.pre_norm =
       TransformerParametersProtoNormTypeToLlmParamsNormType(
           transformer_params.feed_forward_parameters().pre_norm());
@@ -382,6 +389,25 @@
 
   absl::StrAppend(&sa_file_prefix, ".self_attention.");
 
+  if (params.sa_params.qk_norm) {
+    MP_ASSIGN_OR_RETURN(self_attention.q_norm_weight,
+                        LoadNormWeights(LlmParams::Norm::RMS_NORM,
+                                        std::vector<size_t>{params.head_dim_H},
+                                        absl::StrCat(sa_file_prefix, "q_norm"),
+                                        *weight_accessor_));
+    MP_ASSIGN_OR_RETURN(self_attention.k_norm_weight,
+                        LoadNormWeights(LlmParams::Norm::RMS_NORM,
+                                        std::vector<size_t>{params.head_dim_H},
+                                        absl::StrCat(sa_file_prefix, "k_norm"),
+                                        *weight_accessor_));
+    RET_CHECK(std::get<RMSNormWeights>(self_attention.q_norm_weight.value())
+                  .norm_weight &&
+              std::get<RMSNormWeights>(self_attention.k_norm_weight.value())
+                  .norm_weight)
+        << "Expected qk_norm weights " << absl::StrCat(sa_file_prefix, "q_norm")
+        << " and " << absl::StrCat(sa_file_prefix, "k_norm") << " not found.";
+  }
+
   MP_ASSIGN_OR_RETURN(
       self_attention.k_weight,
       TryCacheThenLoadSelfAttention(absl::StrCat(sa_file_prefix, "k.w"),
@@ -491,15 +517,22 @@
 
 DefaultLlmWeightsLoader::DefaultLlmWeightsLoader(
     absl::string_view weight_path, const LlmParams& params,
-    std::shared_ptr<tflite::FlatBufferModel> flat_buffer_model)
+    std::shared_ptr<tflite::FlatBufferModel> flat_buffer_model,
+    std::shared_ptr<ScopedFile> scoped_cache_file)
     : LlmWeightsLoader(nullptr, params) {
-  xnn_weights_cache_ = std::make_shared<PackWeightsCache>(
-      params.cache_dir.empty()
-          ? absl::StrCat(weight_path, ".cache")
-          : mediapipe::file::JoinPath(
-                params.cache_dir,
-                absl::StrCat(mediapipe::file::Basename(weight_path),
-                             ".cache")));
+  // Prefer to load from the scoped cache file if provided.
+  if (scoped_cache_file && scoped_cache_file->IsValid()) {
+    xnn_weights_cache_ =
+        std::make_shared<PackWeightsCache>(std::move(scoped_cache_file));
+  } else {
+    xnn_weights_cache_ = std::make_shared<PackWeightsCache>(
+        params.cache_dir.empty()
+            ? absl::StrCat(weight_path, ".cache")
+            : mediapipe::file::JoinPath(
+                  params.cache_dir,
+                  absl::StrCat(mediapipe::file::Basename(weight_path),
+                               ".cache")));
+  }
   ABSL_CHECK_OK(xnn_weights_cache_->Initialize());
   if (flat_buffer_model != nullptr) {
     const tflite::Model* model = flat_buffer_model->GetModel();
@@ -511,6 +544,9 @@
         std::make_shared<TfLiteWeightAccessor>(tflite_model, data),
         xnn_weights_cache_.get());
   } else {
+    ABSL_CHECK(!scoped_cache_file)
+        << "loading the weight cache from a scoped file is currently only "
+           "supported if the model is passed as a FlatBufferModel";
     weight_accessor_ = std::make_unique<WeightAccessorCompositeWithCache>(
         std::make_shared<TfLiteWeightAccessor>(weight_path),
         xnn_weights_cache_.get());
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm_weights.h b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm_weights.h
index ae5fd1b33..8b75c11 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm_weights.h
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/llm_weights.h
@@ -85,6 +85,7 @@
     NO_NORM = 1,
     RMS_NORM = 2,
     LAYER_NORM = 3,
+    RMS_NORM_NO_SCALE = 4,
   };
 
   enum class AttentionScaleType {
@@ -111,6 +112,10 @@
     // applied.
     float soft_cap_value = 0.0f;
 
+    // If `true`, apply a scaled RMS normalization to the projected queries and
+    // keys.
+    bool qk_norm = false;
+
     // Attention scale type to be applied within the transformer.
     AttentionScaleType attention_scale_type;
   } sa_params;
@@ -173,6 +178,9 @@
     std::shared_ptr<Tensor> post_proj_weight;
     std::shared_ptr<Tensor> post_proj_bias;
 
+    std::optional<NormWeights> q_norm_weight;
+    std::optional<NormWeights> k_norm_weight;
+
     std::optional<NormWeights> post_norm_weight;
   };
 
@@ -261,7 +269,8 @@
       : LlmWeightsLoader(std::move(weight_accessor), params) {}
   DefaultLlmWeightsLoader(
       absl::string_view weight_path, const LlmParams& params,
-      std::shared_ptr<tflite::FlatBufferModel> flat_buffer_model = nullptr);
+      std::shared_ptr<tflite::FlatBufferModel> flat_buffer_model = nullptr,
+      std::shared_ptr<ScopedFile> scoped_cache_file = nullptr);
 
  private:
   std::shared_ptr<PackWeightsCache> xnn_weights_cache_;
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/pack_weights_cache.cc b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/pack_weights_cache.cc
index 5eb99c96..0a3b7c8f 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/pack_weights_cache.cc
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/pack_weights_cache.cc
@@ -14,7 +14,12 @@
 
 #include "mediapipe/tasks/cc/genai/inference/utils/xnn_utils/pack_weights_cache.h"
 
+#if defined(_WIN32)
+#include <Windows.h>
+#endif
+
 #include <algorithm>
+#include <cerrno>
 #include <cstddef>
 #include <cstdint>
 #include <cstdlib>
@@ -22,8 +27,10 @@
 #include <memory>
 #include <string>
 #include <utility>
+#include <variant>
 #include <vector>
 
+#include "absl/functional/overload.h"
 #include "absl/log/absl_check.h"
 #include "absl/log/absl_log.h"
 #include "absl/status/status.h"
@@ -35,32 +42,75 @@
 #include "mediapipe/framework/port/file_helpers.h"
 #include "mediapipe/framework/port/ret_check.h"
 #include "mediapipe/framework/port/status_macros.h"
-#include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/xnn_utils/named_buffer_generated.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/xnn_utils/xnn_tensor.h"
 #include "xnnpack.h"  // from @XNNPACK
+// clang-format off
+#include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file.h",
+#include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/scoped_file.h"
+// clang-format on
 
 namespace mediapipe::tasks::genai::xnn_utils {
 
 namespace {
 
+using ::mediapipe::tasks::genai::llm_utils::MemoryMappedFile;
+
 bool operator==(const xnn_weights_cache_look_up_key& lhs,
                 const xnn_weights_cache_look_up_key& rhs) {
   return lhs.kernel == rhs.kernel && lhs.bias == rhs.bias &&
          lhs.seed == rhs.seed;
 }
 
+// Writes `data` to the platform file descriptor. Returns the number of bytes
+// written or an error if the write failed.
+absl::StatusOr<size_t> WriteToPlatformFile(ScopedFile::PlatformFile file,
+                                           absl::string_view data) {
+#if defined(_WIN32)
+  DWORD bytes_written;
+  DWORD size = static_cast<DWORD>(data.size());
+  BOOL result = ::WriteFile(file, data.data(), size, &bytes_written, nullptr);
+  if (!result) {
+    return absl::UnknownError("Failed to write to file");
+  }
+#else
+  ssize_t bytes_written = -1;
+  do {
+    bytes_written = write(file, data.data(), data.size());
+  } while (bytes_written == -1 && errno == EINTR);
+  if (bytes_written < 0) {
+    return absl::ErrnoToStatus(errno, "Failed to write to file");
+  }
+#endif
+  return bytes_written;
+}
+
+absl::Status AppendToFileDescriptor(const ScopedFile& scoped_file,
+                                    absl::string_view data) {
+  while (!data.empty()) {
+    MP_ASSIGN_OR_RETURN(size_t bytes_written,
+                        WriteToPlatformFile(scoped_file.file(), data));
+    data = data.substr(bytes_written);
+  }
+  return absl::OkStatus();
+}
+
 }  // namespace
 
 PackWeightsCache::PackWeightsCache(absl::string_view cache_path)
-    : cache_path_(cache_path) {
+    : cache_file_(std::string(cache_path)) {
+  xnn_weights_cache = &cache_provider_;
+}
+
+PackWeightsCache::PackWeightsCache(std::shared_ptr<ScopedFile> scoped_file)
+    : cache_file_(std::move(scoped_file)) {
   xnn_weights_cache = &cache_provider_;
 }
 
 PackWeightsCache::~PackWeightsCache() { xnn_weights_cache = nullptr; }
 
 absl::Status PackWeightsCache::Initialize() {
-  mmap_file_ = GetMmapFile(cache_path_);
+  mmap_file_ = GetMmapFile();
   if (mmap_file_) {
     MP_RETURN_IF_ERROR(InitializeFromCache(mmap_file_));
   } else {
@@ -133,7 +183,7 @@
   MP_RETURN_IF_ERROR(Prepend(serialized));
   builder_.reset();
 
-  mmap_file_ = GetMmapFile(cache_path_);
+  mmap_file_ = GetMmapFile();
   RET_CHECK(mmap_file_);
 
   return InitializeFromCache(mmap_file_);
@@ -158,16 +208,26 @@
   return false;
 }
 
-std::shared_ptr<llm_utils::MemoryMappedFile> PackWeightsCache::GetMmapFile(
-    absl::string_view filename) {
-  return mediapipe::file::Exists(filename).ok()
-             ? llm_utils::MemoryMappedFile::CreateMutable(filename).value_or(
-                   nullptr)
-             : nullptr;
+std::shared_ptr<MemoryMappedFile> PackWeightsCache::GetMmapFile() {
+  return std::visit(
+      absl::Overload(
+          [](const std::string& filename) {
+            return mediapipe::file::Exists(filename).ok()
+                       ? MemoryMappedFile::CreateMutable(filename).value_or(
+                             nullptr)
+                       : nullptr;
+          },
+          [](const std::shared_ptr<ScopedFile>& scoped_file) {
+            return MemoryMappedFile::CreateMutable(scoped_file->file())
+                .value_or(nullptr);
+          }),
+      cache_file_);
 }
 
 absl::Status PackWeightsCache::InitializeFromCache(
-    std::shared_ptr<llm_utils::MemoryMappedFile> mmap_cache) {
+    std::shared_ptr<MemoryMappedFile> mmap_cache) {
+  // TODO: b/401011041 - Gracefully handle the case where the cache file is
+  // filled with junk and needs to be rebuilt.
   name_to_offset_size_.clear();
   named_buffers_ = std::shared_ptr<const NamedBuffers>(
       mmap_cache, GetNamedBuffers(mmap_cache->data()));
@@ -181,18 +241,24 @@
   return absl::OkStatus();
 }
 
-absl::Status PackWeightsCache::Append(absl::string_view filename,
-                                      absl::string_view data) {
-  return mediapipe::file::AppendStringToFile(filename, data);
+absl::Status PackWeightsCache::Append(absl::string_view data) {
+  return std::visit(
+      absl::Overload(
+          [&data](const std::string& filename) {
+            return mediapipe::file::AppendStringToFile(filename, data);
+          },
+          [&data](const std::shared_ptr<ScopedFile>& scoped_file) {
+            return AppendToFileDescriptor(*scoped_file, data);
+          }),
+      cache_file_);
 }
 
-absl::Status PackWeightsCache::Prepend(absl::string_view filename,
-                                       absl::string_view data) {
+absl::Status PackWeightsCache::Prepend(absl::string_view data) {
   // Append `data` to the end of the file to ensure the file is large enough.
   // Then move chunk_size of bytes towards the end of the file each time.
   // Finally copy `data` to position 0 of the file.
-  MP_RETURN_IF_ERROR(Append(filename, data));
-  auto mmap_file = GetMmapFile(filename);
+  MP_RETURN_IF_ERROR(Append(data));
+  auto mmap_file = GetMmapFile();
   RET_CHECK(mmap_file);
   size_t src_offset = mmap_file->length() - data.size();
   do {
@@ -205,14 +271,6 @@
   return absl::OkStatus();
 }
 
-absl::Status PackWeightsCache::Append(absl::string_view data) {
-  return Append(cache_path_, data);
-}
-
-absl::Status PackWeightsCache::Prepend(absl::string_view data) {
-  return Prepend(cache_path_, data);
-}
-
 size_t PackWeightsCache::look_up(
     PackWeightsCache* context, const xnn_weights_cache_look_up_key* cache_key) {
   ABSL_CHECK(cache_key);
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/pack_weights_cache.h b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/pack_weights_cache.h
index 24ebda4..0ca19ea 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/pack_weights_cache.h
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/pack_weights_cache.h
@@ -20,27 +20,41 @@
 #include <optional>
 #include <string>
 #include <utility>
+#include <variant>
 
 #include "absl/container/flat_hash_map.h"
 #include "absl/status/status.h"
 #include "absl/status/statusor.h"
 #include "absl/strings/string_view.h"
 #include "flatbuffers/flatbuffer_builder.h"
-#include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/xnn_utils/graph_builder.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/xnn_utils/named_buffer_generated.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/xnn_utils/xnn_tensor.h"
 #include "xnnpack.h"  // from @XNNPACK
+// clang-format off
+#include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file.h"
+#include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/scoped_file.h"
+// clang-format on
 
 namespace mediapipe::tasks::genai::xnn_utils {
 
+using ::mediapipe::tasks::genai::llm_utils::MemoryMappedFile;
+using ::mediapipe::tasks::genai::llm_utils::ScopedFile;
+
 // An implementation of XnnWeightsCache that allows cross-process packed weights
 // sharing. This implementation does not really support insertion, which means
 // either the cache is fully built already, or will be built from scratch.
 class PackWeightsCache : public XnnWeightsCache {
  public:
-  // `cache_path` is used in Initialize() and Finalize().
+  // File path to the weight cache. If the file exists, the
+  // cache will be loaded from the file. Otherwise, the weights cache will be
+  // built and written to the file.
   explicit PackWeightsCache(absl::string_view cache_path);
+  // File descriptor to write cache data to or read cache data from. Must be
+  // writable.
+  // TODO: b/401011041 - Consider supporting read-only file descriptors if the
+  // cache has already been built.
+  explicit PackWeightsCache(std::shared_ptr<ScopedFile> scoped_file);
   ~PackWeightsCache() override;
 
   // Initializes the cache. The default implementation loads the serialized
@@ -64,28 +78,18 @@
   virtual bool ShouldDoubleCheckCompatibility(
       const xnn_weights_cache_look_up_key*);
 
-  // Returns mapped memory of `filename`. Returns nullptr in case of any error.
-  // Inheritance classes can overwrite this function e.g. if there's no
-  // filesystem.
-  virtual std::shared_ptr<llm_utils::MemoryMappedFile> GetMmapFile(
-      absl::string_view filename);
-
-  // Appends `data` from the end of `filename`. Inheritance classes can
-  // overwrite this function e.g. if there's no filesystem.
-  virtual absl::Status Append(absl::string_view filename,
-                              absl::string_view data);
-
-  // Inserts `data` at the beginning of `filename`. Inheritance classes can
-  // overwrite this function e.g. if there's no filesystem.
-  virtual absl::Status Prepend(absl::string_view filename,
-                               absl::string_view data);
-
  private:
+  // Returns writable mapped memory of the cache file. Returns nullptr in case
+  // of any error.
+  // TODO: b/401011041 - Consider returning a readable memory mapping if the
+  // cache file has already been built.
+  std::shared_ptr<MemoryMappedFile> GetMmapFile();
+
   absl::Status Append(absl::string_view data);
   absl::Status Prepend(absl::string_view data);
 
   absl::Status InitializeFromCache(
-      std::shared_ptr<llm_utils::MemoryMappedFile> mmap_cache);
+      std::shared_ptr<MemoryMappedFile> mmap_cache);
 
   // A series of functions for `xnn_weights_cache_provider`. They need to be
   // static such that we can assign function pointers. They need to be class
@@ -111,8 +115,10 @@
 
   xnn_weights_cache_provider cache_provider_;
 
-  std::string cache_path_;
-  std::shared_ptr<llm_utils::MemoryMappedFile> mmap_file_;
+  // File path or descriptor to write the cache file to.
+  std::variant<std::string, std::shared_ptr<ScopedFile>> cache_file_;
+
+  std::shared_ptr<MemoryMappedFile> mmap_file_;
   // Immutable flatbuffer.
   std::shared_ptr<const NamedBuffers> named_buffers_;
 
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/tflite_weight_accessor.cc b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/tflite_weight_accessor.cc
index ab32a800..b573379 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/tflite_weight_accessor.cc
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/tflite_weight_accessor.cc
@@ -29,13 +29,17 @@
 #include "flatbuffers/buffer.h"
 #include "flatbuffers/vector.h"
 #include "mediapipe/framework/port/ret_check.h"
-#include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file.h"
 #include "mediapipe/tasks/cc/genai/inference/utils/xnn_utils/xnn_tensor.h"
-#include "tensorflow/lite/schema/schema_generated.h"
 #include "xnnpack.h"  // from @XNNPACK
+// clang-format off
+#include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file.h"
+// clang-format on
+#include "tensorflow/lite/schema/schema_generated.h"
 
 namespace mediapipe::tasks::genai::xnn_utils {
 
+using ::mediapipe::tasks::genai::llm_utils::MemoryMappedFile;
+
 TfLiteWeightAccessor::TfLiteWeightAccessor(
     std::shared_ptr<const tflite::Model> tflite_model, char* data)
     : tflite_model_(tflite_model) {
@@ -43,8 +47,8 @@
 }
 
 TfLiteWeightAccessor::TfLiteWeightAccessor(absl::string_view filename) {
-  std::shared_ptr<llm_utils::MemoryMappedFile> mmap_file =
-      llm_utils::MemoryMappedFile::Create(filename).value_or(nullptr);
+  std::shared_ptr<MemoryMappedFile> mmap_file =
+      MemoryMappedFile::Create(filename).value_or(nullptr);
   if (mmap_file) {
     tflite_model_ = std::shared_ptr<const ::tflite::Model>(
         mmap_file, ::tflite::GetModel(mmap_file->data()));
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/utils.h b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/utils.h
index 965fc0f..ab131d10 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/utils.h
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/genai/inference/utils/xnn_utils/utils.h
@@ -29,11 +29,14 @@
 #include "absl/types/span.h"
 #include "mediapipe/framework/port/file_helpers.h"
 #include "mediapipe/framework/port/ret_check.h"
+// clang-format off
 #include "mediapipe/tasks/cc/genai/inference/utils/llm_utils/memory_mapped_file.h"
-
+// clang-format on
 namespace mediapipe::tasks::genai {
 namespace xnn_utils {
 
+using ::mediapipe::tasks::genai::llm_utils::MemoryMappedFile;
+
 static constexpr absl::string_view kKeySelfAttentionReshapedWeight{
     "self_attention_reshaped_weight_N"};
 // Usually fully connect is [K,M] dot [M,N] => [K,N]. Some code base by default
@@ -50,8 +53,7 @@
     size_t expect_size_bytes = 0) {
   RET_CHECK(buffer_size);
   if (use_mmap) {
-    MP_ASSIGN_OR_RETURN(auto mapped_file,
-                        llm_utils::MemoryMappedFile::Create(file_path));
+    MP_ASSIGN_OR_RETURN(auto mapped_file, MemoryMappedFile::Create(file_path));
     if (expect_size_bytes) {
       RET_CHECK_EQ(expect_size_bytes, mapped_file->length())
           << "File size " << mapped_file->length() << ", expected "
@@ -63,9 +65,8 @@
     // shared_ptr deleter must be copy constructible, so wrap the unique_ptr in
     // another shared_ptr.
     void* data = mapped_file->data();
-    auto file_deleter =
-        std::make_shared<std::unique_ptr<llm_utils::MemoryMappedFile>>(
-            std::move(mapped_file));
+    auto file_deleter = std::make_shared<std::unique_ptr<MemoryMappedFile>>(
+        std::move(mapped_file));
     return std::shared_ptr<element_type>(
         static_cast<element_type*>(data),
         [file_deleter](auto* p) { file_deleter->reset(); });
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/text/text_embedder/BUILD b/third_party/mediapipe/src/mediapipe/tasks/cc/text/text_embedder/BUILD
index 168bcc5..a216d14 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/text/text_embedder/BUILD
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/text/text_embedder/BUILD
@@ -92,7 +92,8 @@
         "@com_google_absl//absl/flags:flag",
         "@com_google_absl//absl/status",
         "@com_google_absl//absl/status:statusor",
-        "@com_google_sentencepiece//:sentencepiece_processor",
+        "@com_google_absl//absl/strings",
+        "@com_google_absl//absl/strings:cord",
         "@org_tensorflow//tensorflow/lite:test_util",
     ],
 )
diff --git a/third_party/mediapipe/src/mediapipe/tasks/cc/text/utils/text_model_utils.cc b/third_party/mediapipe/src/mediapipe/tasks/cc/text/utils/text_model_utils.cc
index 1100e83..1b3e90e 100644
--- a/third_party/mediapipe/src/mediapipe/tasks/cc/text/utils/text_model_utils.cc
+++ b/third_party/mediapipe/src/mediapipe/tasks/cc/text/utils/text_model_utils.cc
@@ -99,11 +99,13 @@
       *(*model_resources.GetTfLiteModel()->subgraphs())[0];
   bool all_int32_tensors =
       absl::c_all_of(*model_graph.inputs(), [&model_graph](int i) {
-        return (*model_graph.tensors())[i]->type() == tflite::TensorType_INT32;
+        return (*model_graph.tensors())[i] -> type() ==
+                                                  tflite::TensorType_INT32;
       });
   bool all_string_tensors =
       absl::c_all_of(*model_graph.inputs(), [&model_graph](int i) {
-        return (*model_graph.tensors())[i]->type() == tflite::TensorType_STRING;
+        return (*model_graph.tensors())[i] -> type() ==
+                                                  tflite::TensorType_STRING;
       });
   if (!all_int32_tensors && !all_string_tensors) {
     return CreateStatusWithPayload(
diff --git a/third_party/mediapipe/src/mediapipe/tasks/internal/release/android/BUILD b/third_party/mediapipe/src/mediapipe/tasks/internal/release/android/BUILD
deleted file mode 100644
index e93a9793..0000000
--- a/third_party/mediapipe/src/mediapipe/tasks/internal/release/android/BUILD
+++ /dev/null
@@ -1,160 +0,0 @@
-load("//mediapipe:version.bzl", "MEDIAPIPE_FULL_VERSION")
-load("//mediapipe/tasks/internal/release/android:maven_repo.bzl", "maven_artifact", "maven_repository")
-
-# To set the "last_updated" field in the maven artifact, build with:
-#
-#   --define MAVEN_ARTIFACT_LAST_UPDATED=$(date "+%Y%m%d000000")
-#
-# If not provided, the "last_updated" field will not be included in
-# the maven artifact.
-
-sh_binary(
-    name = "maven_artifact",
-    srcs = ["maven_artifact.sh"],
-)
-
-maven_artifact(
-    name = "tasks_core_maven_artifact",
-    src = "//mediapipe/tasks/java/com/google/mediapipe/tasks/core:tasks_core.aar",
-    artifact_deps = [
-        "com.google.flogger:flogger:0.6",
-        "com.google.flogger:flogger-system-backend:0.6",
-        "com.google.guava:guava:27.0.1-android",
-        "com.google.protobuf:protobuf-javalite:4.26.1",
-        "com.google.android.datatransport:transport-api:3.0.0",
-        "com.google.android.datatransport:transport-backend-cct:3.1.0",
-        "com.google.android.datatransport:transport-runtime:3.1.0",
-    ],
-    artifact_id = "tasks-core",
-    group_id = "com.google.mediapipe",
-    inception_year = "2022",
-    last_updated = "$(MAVEN_ARTIFACT_LAST_UPDATED)",
-    lib_description = "The MediaPipe Tasks core components.",
-    lib_name = "MediaPipe Taksks Core",
-    lib_url = "https://mediapipe.dev/",
-    version = MEDIAPIPE_FULL_VERSION,
-)
-
-maven_artifact(
-    name = "tasks_audio_maven_artifact",
-    src = "//mediapipe/tasks/java/com/google/mediapipe/tasks/audio:tasks_audio.aar",
-    artifact_deps = [
-        "androidx.annotation:annotation:1.1.0",
-        "com.google.auto.value:auto-value-annotations:1.8.1",
-        "com.google.auto.value:auto-value:1.8.1",
-        "com.google.guava:guava:27.0.1-android",
-        "com.google.mediapipe:tasks-core:" + MEDIAPIPE_FULL_VERSION,
-    ],
-    artifact_id = "tasks-audio",
-    group_id = "com.google.mediapipe",
-    inception_year = "2022",
-    last_updated = "$(MAVEN_ARTIFACT_LAST_UPDATED)",
-    lib_description = "The MediaPipe Tasks Audio APIs.",
-    lib_name = "MediaPipe Tasks Audio",
-    lib_url = "https://mediapipe.dev/",
-    version = MEDIAPIPE_FULL_VERSION,
-)
-
-maven_artifact(
-    name = "tasks_vision_maven_artifact",
-    src = "//mediapipe/tasks/java/com/google/mediapipe/tasks/vision:tasks_vision.aar",
-    artifact_deps = [
-        "androidx.annotation:annotation:1.1.0",
-        "com.google.auto.value:auto-value-annotations:1.8.1",
-        "com.google.auto.value:auto-value:1.8.1",
-        "com.google.guava:guava:27.0.1-android",
-        "com.google.mediapipe:tasks-core:" + MEDIAPIPE_FULL_VERSION,
-    ],
-    artifact_id = "tasks-vision",
-    group_id = "com.google.mediapipe",
-    inception_year = "2022",
-    last_updated = "$(MAVEN_ARTIFACT_LAST_UPDATED)",
-    lib_description = "The MediaPipe Tasks Vision APIs.",
-    lib_name = "MediaPipe Tasks Vision",
-    lib_url = "https://mediapipe.dev/",
-    version = MEDIAPIPE_FULL_VERSION,
-)
-
-maven_artifact(
-    name = "tasks_text_maven_artifact",
-    src = "//mediapipe/tasks/java/com/google/mediapipe/tasks/text:tasks_text.aar",
-    artifact_deps = [
-        "androidx.annotation:annotation:1.1.0",
-        "com.google.auto.value:auto-value-annotations:1.8.1",
-        "com.google.auto.value:auto-value:1.8.1",
-        "com.google.guava:guava:27.0.1-android",
-        "com.google.mediapipe:tasks-core:" + MEDIAPIPE_FULL_VERSION,
-    ],
-    artifact_id = "tasks-text",
-    group_id = "com.google.mediapipe",
-    inception_year = "2022",
-    last_updated = "$(MAVEN_ARTIFACT_LAST_UPDATED)",
-    lib_description = "The MediaPipe Tasks Text APIs.",
-    lib_name = "MediaPipe Tasks Text",
-    lib_url = "https://mediapipe.dev/",
-    version = MEDIAPIPE_FULL_VERSION,
-)
-
-maven_artifact(
-    name = "tasks_vision_image_generator_maven_artifact",
-    src = "//mediapipe/tasks/java/com/google/mediapipe/tasks/vision/imagegenerator:tasks_vision_image_generator.aar",
-    artifact_deps = [
-        "androidx.annotation:annotation:1.1.0",
-        "com.google.auto.value:auto-value-annotations:1.8.1",
-        "com.google.auto.value:auto-value:1.8.1",
-        "com.google.guava:guava:27.0.1-android",
-        "com.google.mediapipe:tasks-core:" + MEDIAPIPE_FULL_VERSION,
-    ],
-    artifact_id = "tasks-vision-image-generator",
-    group_id = "com.google.mediapipe",
-    inception_year = "2023",
-    last_updated = "$(MAVEN_ARTIFACT_LAST_UPDATED)",
-    lib_description = "The MediaPipe Tasks Vision Image Generator Android API.",
-    lib_name = "MediaPipe Tasks Vision Image Generator",
-    lib_url = "https://mediapipe.dev/",
-    version = MEDIAPIPE_FULL_VERSION,
-)
-
-maven_artifact(
-    name = "tasks_genai_maven_artifact",
-    src = "//mediapipe/tasks/java/com/google/mediapipe/tasks/genai:tasks_genai.aar",
-    artifact_deps = [
-        "androidx.annotation:annotation:1.1.0",
-        "com.google.auto.value:auto-value-annotations:1.8.1",
-        "com.google.auto.value:auto-value:1.8.1",
-        "com.google.guava:guava:27.0.1-android",
-        "com.google.mediapipe:tasks-core:" + MEDIAPIPE_FULL_VERSION,
-    ],
-    artifact_id = "tasks-genai",
-    group_id = "com.google.mediapipe",
-    inception_year = "2023",
-    last_updated = "$(MAVEN_ARTIFACT_LAST_UPDATED)",
-    lib_description = "The MediaPipe Tasks GenAI Android API.",
-    lib_name = "MediaPipe Tasks Text GenAI",
-    lib_url = "https://mediapipe.dev/",
-    version = MEDIAPIPE_FULL_VERSION,
-)
-
-maven_repository(
-    name = "image_generator_m2repository",
-    srcs = [
-        ":tasks_vision_image_generator_maven_artifact",
-    ],
-)
-
-maven_repository(
-    name = "genai_m2repository",
-    srcs = [
-        ":tasks_genai_maven_artifact",
-    ],
-)
-
-maven_repository(
-    name = "m2repository",
-    srcs = [
-        ":tasks_audio_maven_artifact",
-        ":tasks_core_maven_artifact",
-        ":tasks_text_maven_artifact",
-        ":tasks_vision_maven_artifact",
-    ],
-)
diff --git a/third_party/mediapipe/src/mediapipe/tasks/internal/release/android/maven_artifact.sh b/third_party/mediapipe/src/mediapipe/tasks/internal/release/android/maven_artifact.sh
deleted file mode 100755
index 697df3f..0000000
--- a/third_party/mediapipe/src/mediapipe/tasks/internal/release/android/maven_artifact.sh
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/bin/bash
-# Copyright 2021 The MediaPipe Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Shell script to package an artifact as a zipped maven repository.
-
-set -o errexit
-set -o pipefail
-
-#Parse out the flags
-POSITIONAL=()
-while [[ $# -gt 0 ]]
-do
-  flag="$(cut -d'=' -f1 <<< $1)"
-  value="$(cut -d'=' -f2 <<< $1)"
-
-  case $flag in
-    --group_path)
-    FLAGS_group_path="$value"
-    ;;
-
-    --artifact_id)
-    FLAGS_artifact_id="$value"
-    ;;
-
-    --version)
-    FLAGS_version="$value"
-    ;;
-
-    --artifact)
-    FLAGS_artifact="$value"
-    ;;
-
-    --source)
-    FLAGS_source="$value"
-    ;;
-
-    --pom)
-    FLAGS_pom="$value"
-    ;;
-
-    --metadata)
-    FLAGS_metadata="$value"
-    ;;
-
-    --output)
-    FLAGS_output="$value"
-    ;;
-  esac
-
-  shift
-done
-set -- "${POSITIONAL[@]}" # restore positional parameters in case we need that
-
-out_tmp="$(mktemp -d)"
-dirname="m2repository"
-repo="$out_tmp/$dirname"
-
-
-mkdir -p "$repo/$FLAGS_group_path/$FLAGS_artifact_id/$FLAGS_version"
-
-cp "$FLAGS_metadata" "$repo/$FLAGS_group_path/$FLAGS_artifact_id/"
-cp "$FLAGS_pom" "$repo/$FLAGS_group_path/$FLAGS_artifact_id/$FLAGS_version/"
-cp "$FLAGS_artifact" \
-    "$repo/$FLAGS_group_path/$FLAGS_artifact_id/$FLAGS_version/"
-
-for file in $(find "$repo" -type f); do
-  echo -n "$(sha1sum "$file" | cut -f 1 -d ' ')" > "$file.sha1"
-  echo -n "$(md5sum "$file" | cut -f 1 -d ' ')" > "$file.md5"
-done
-
-(
-  root_dir="$(pwd)"
-  cd "$out_tmp"
-  # Rare zip options:
-  #  -X  no extra file attributes
-  #  -0  means no compression
-  zip -X -q -r -0 "$root_dir/$FLAGS_output" "$dirname"
-)
diff --git a/third_party/mediapipe/src/mediapipe/tasks/internal/release/android/maven_repo.bzl b/third_party/mediapipe/src/mediapipe/tasks/internal/release/android/maven_repo.bzl
deleted file mode 100644
index ce1684e..0000000
--- a/third_party/mediapipe/src/mediapipe/tasks/internal/release/android/maven_repo.bzl
+++ /dev/null
@@ -1,200 +0,0 @@
-"""Starlark rule to create a maven repository from a single artifact."""
-
-_pom_tmpl = """
-<?xml version="1.0" encoding="UTF-8"?>
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
-    xmlns="http://maven.apache.org/POM/4.0.0"',
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">',
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>{group_id}</groupId>
-  <artifactId>{artifact_id}</artifactId>
-  <version>{version}</version>
-  <packaging>{packaging}</packaging>
-  {identity}
-  <licenses>
-    <license>
-      <name>The Apache Software License, Version 2.0</name>
-      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
-      <distribution>repo</distribution>
-    </license>
-  </licenses>
-  <developers>
-    <developer>
-      <name>The MediaPipe Authors</name>
-    </developer>
-  </developers>
-  <dependencies>
-    {dependencies}
-  </dependencies>
-</project>
-"""
-
-_identity_tmpl = """
-<name>{lib_name}</name>
-<description>{lib_description}</description>
-<url>{lib_url}</url>
-<inceptionYear>{inception_year}</inceptionYear>
-"""
-
-_dependency_tmpl = """
-<dependency>
-  <groupId>{group_id}</groupId>
-  <artifactId>{artifact_id}</artifactId>
-  <version>{version}</version>
-  <scope>compile</scope>
-</dependency>
-"""
-
-_metadata_tmpl = """
-<?xml version="1.0" encoding="UTF-8"?>
-<metadata>
-  <groupId>{group_id}</groupId>
-  <artifactId>{artifact_id}</artifactId>
-  <version>{version}</version>
-  <versioning>
-    <release>{version}</release>
-    <versions>
-      <version>{version}</version>
-    </versions>
-    {last_updated_xml}
-  </versioning>
-</metadata>
-"""
-
-def _packaging_type(f):
-    """Returns the packaging type used by the file f."""
-    if f.basename.endswith(".aar"):
-        return "aar"
-    elif f.basename.endswith(".jar"):
-        return "jar"
-    fail("Artifact has unknown packaging type: %s" % f.short_path)
-
-def _create_pom_string(ctx):
-    """Returns the contents of the pom file as a string."""
-    dependencies = []
-    for dep in ctx.attr.artifact_deps:
-        if dep.count(":") != 2:
-            fail("artifact_deps values must be of form: groupId:artifactId:version")
-
-        group_id, artifact_id, version = dep.split(":")
-        dependencies.append(_dependency_tmpl.format(
-            group_id = group_id,
-            artifact_id = artifact_id,
-            version = version,
-        ))
-
-    return _pom_tmpl.format(
-        group_id = ctx.attr.group_id,
-        artifact_id = ctx.attr.artifact_id,
-        version = ctx.attr.version,
-        packaging = _packaging_type(ctx.file.src),
-        identity = _identity_tmpl.format(
-            lib_name = ctx.attr.lib_name,
-            lib_description = ctx.attr.lib_description,
-            lib_url = ctx.attr.lib_url,
-            inception_year = ctx.attr.inception_year,
-        ),
-        dependencies = "\n".join(dependencies),
-    )
-
-def _create_metadata_string(ctx):
-    """Returns the string contents of maven-metadata.xml for the group."""
-
-    # Include the last_updated string only if provided.
-    last_updated_xml = ""
-    last_updated = ctx.var.get("MAVEN_ARTIFACT_LAST_UPDATED", "")
-    if last_updated != "":
-        last_updated_xml = "<lastUpdated>%s</lastUpdated>" % last_updated
-
-    return _metadata_tmpl.format(
-        group_id = ctx.attr.group_id,
-        artifact_id = ctx.attr.artifact_id,
-        version = ctx.attr.version,
-        last_updated_xml = last_updated_xml,
-    )
-
-def _maven_artifact_impl(ctx):
-    """Generates maven repository for a single artifact."""
-    pom = ctx.actions.declare_file(
-        "%s/%s-%s.pom" % (ctx.label.name, ctx.attr.artifact_id, ctx.attr.version),
-    )
-    ctx.actions.write(output = pom, content = _create_pom_string(ctx))
-
-    metadata = ctx.actions.declare_file("%s/maven-metadata.xml" % ctx.label.name)
-    ctx.actions.write(output = metadata, content = _create_metadata_string(ctx))
-
-    # Rename the artifact to match the naming required inside the repository.
-    artifact = ctx.actions.declare_file("%s/%s-%s.%s" % (
-        ctx.label.name,
-        ctx.attr.artifact_id,
-        ctx.attr.version,
-        _packaging_type(ctx.file.src),
-    ))
-    ctx.actions.run_shell(
-        inputs = [ctx.file.src],
-        outputs = [artifact],
-        command = "cp %s %s" % (ctx.file.src.path, artifact.path),
-    )
-
-    ctx.actions.run(
-        inputs = [pom, metadata, artifact],
-        outputs = [ctx.outputs.m2repository],
-        arguments = [
-            "--group_path=%s" % ctx.attr.group_id.replace(".", "/"),
-            "--artifact_id=%s" % ctx.attr.artifact_id,
-            "--version=%s" % ctx.attr.version,
-            "--artifact=%s" % artifact.path,
-            "--pom=%s" % pom.path,
-            "--metadata=%s" % metadata.path,
-            "--output=%s" % ctx.outputs.m2repository.path,
-        ],
-        executable = ctx.executable._maven_artifact,
-        progress_message = (
-            "Packaging repository: %s" % ctx.outputs.m2repository.short_path
-        ),
-    )
-
-maven_artifact = rule(
-    implementation = _maven_artifact_impl,
-    attrs = {
-        "src": attr.label(
-            mandatory = True,
-            allow_single_file = [".aar", ".jar"],
-        ),
-        "group_id": attr.string(mandatory = True),
-        "artifact_id": attr.string(mandatory = True),
-        "version": attr.string(mandatory = True),
-        "last_updated": attr.string(mandatory = True),
-        "artifact_deps": attr.string_list(),
-        "lib_name": attr.string(default = ""),
-        "lib_description": attr.string(default = ""),
-        "lib_url": attr.string(default = ""),
-        "inception_year": attr.string(default = ""),
-        "_maven_artifact": attr.label(
-            default = Label("//mediapipe/tasks/internal/release/android:maven_artifact"),
-            executable = True,
-            allow_files = True,
-            cfg = "exec",
-        ),
-    },
-    outputs = {
-        "m2repository": "%{name}.zip",
-    },
-)
-
-def maven_repository(name, srcs):
-    """Generates a zip file containing a maven repository."""
-    native.genrule(
-        name = name,
-        srcs = srcs,
-        outs = [name + ".zip"],
-        cmd = """
-        origdir=$$PWD
-        TEMP_DIR=$$(mktemp -d)
-        for FILE in $(SRCS); do
-          unzip $$FILE -d $$TEMP_DIR
-        done
-        cd $$TEMP_DIR
-        zip -r $$origdir/$@ ./
-        """,
-    )
diff --git a/third_party/mediapipe/src/mediapipe/util/BUILD b/third_party/mediapipe/src/mediapipe/util/BUILD
index ff5d913..7030d07 100644
--- a/third_party/mediapipe/src/mediapipe/util/BUILD
+++ b/third_party/mediapipe/src/mediapipe/util/BUILD
@@ -212,6 +212,7 @@
         "//mediapipe/framework/formats:unique_fd",
         "//mediapipe/framework/port:ret_check",
         "//mediapipe/framework/port:status",
+        "@com_google_absl//absl/log:absl_log",
         "@com_google_absl//absl/status",
         "@com_google_absl//absl/status:statusor",
         "@com_google_absl//absl/strings:str_format",
@@ -494,7 +495,6 @@
         "//mediapipe/framework/port:opencv_imgproc",
         "//mediapipe/gpu:gpu_buffer",
         "//mediapipe/gpu:gpu_buffer_format",
-        "//mediapipe/gpu:gpu_buffer_storage_image_frame",
         "@com_google_absl//absl/log:absl_log",
     ],
 )
diff --git a/third_party/mediapipe/src/mediapipe/version.bzl b/third_party/mediapipe/src/mediapipe/version.bzl
index 4adaf5f..afc27c2 100644
--- a/third_party/mediapipe/src/mediapipe/version.bzl
+++ b/third_party/mediapipe/src/mediapipe/version.bzl
@@ -2,4 +2,4 @@
 
 # The next version of MediaPipe (e.g. the version that is currently in development).
 # This version should be bumped after every release.
-MEDIAPIPE_FULL_VERSION = "0.10.22"
+MEDIAPIPE_FULL_VERSION = "0.10.24"
diff --git a/third_party/mediapipe/src/third_party/com_google_audio_tools/README.md b/third_party/mediapipe/src/third_party/com_google_audio_tools/README.md
index 2e00092..3d7f577 100644
--- a/third_party/mediapipe/src/third_party/com_google_audio_tools/README.md
+++ b/third_party/mediapipe/src/third_party/com_google_audio_tools/README.md
@@ -36,6 +36,6 @@
 bazel test -c opt --cxxopt="-fext-numeric-literals" \
                   --cxxopt="-Wno-sign-compare" \
                   --cxxopt="-fpermissive" \
-                  --cxxopt="-std=c++11" \
+                  --cxxopt="-std=c++17" \
                   audio/... \
 ```
diff --git a/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/number_util.cc b/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/number_util.cc
index 2a5a93336..38369459 100644
--- a/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/number_util.cc
+++ b/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/number_util.cc
@@ -16,7 +16,6 @@
 
 #include "audio/dsp/number_util.h"
 
-#include <algorithm>
 #include <cmath>
 #include <iomanip>
 #include <limits>
diff --git a/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/porting.cc b/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/porting.cc
index 753c286..e906d2d0 100644
--- a/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/porting.cc
+++ b/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/porting.cc
@@ -16,7 +16,6 @@
 
 #include "audio/dsp/porting.h"
 
-#include <algorithm>
 #include <cfloat>
 #include <cstdarg>
 
diff --git a/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/porting.h b/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/porting.h
index fab40f9..87231c5 100644
--- a/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/porting.h
+++ b/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/porting.h
@@ -17,7 +17,6 @@
 #ifndef AUDIO_DSP_OPEN_SOURCE_PORTING_H_
 #define AUDIO_DSP_OPEN_SOURCE_PORTING_H_
 
-#include <cstdint>
 #include <iostream>
 #include <cmath>
 #include <limits>
diff --git a/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/spectrogram/spectrogram.cc b/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/spectrogram/spectrogram.cc
index 1545b7ac..1d72e18 100644
--- a/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/spectrogram/spectrogram.cc
+++ b/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/spectrogram/spectrogram.cc
@@ -40,13 +40,14 @@
 }
 
 bool Spectrogram::Initialize(int window_length, int step_length,
-                             std::optional<int> fft_length) {
+  std::optional<int> fft_length) {
   std::vector<double> window;
   HannWindow().GetPeriodicSamples(window_length, &window);
   return Initialize(window, step_length, fft_length);
 }
 
-bool Spectrogram::Initialize(const std::vector<double>& window, int step_length,
+bool Spectrogram::Initialize(const std::vector<double>& window,
+                             int step_length,
                              std::optional<int> fft_length) {
   window_length_ = window.size();
   window_ = window;  // Copy window.
diff --git a/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/spectrogram/spectrogram.h b/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/spectrogram/spectrogram.h
index 0f6ada6..08d3cadd 100644
--- a/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/spectrogram/spectrogram.h
+++ b/third_party/mediapipe/src/third_party/com_google_audio_tools/audio/dsp/spectrogram/spectrogram.h
@@ -36,8 +36,8 @@
 #define AUDIO_DSP_SPECTROGRAM_SPECTROGRAM_H_
 
 #include <complex>
-#include <optional>
 #include <deque>
+#include <optional>
 #include <vector>
 
 #include "glog/logging.h"
diff --git a/third_party/mediapipe/src/third_party/com_google_audio_tools/third_party/eigen3/BUILD b/third_party/mediapipe/src/third_party/com_google_audio_tools/third_party/eigen3/BUILD
index de1c7f4..497c1f0 100644
--- a/third_party/mediapipe/src/third_party/com_google_audio_tools/third_party/eigen3/BUILD
+++ b/third_party/mediapipe/src/third_party/com_google_audio_tools/third_party/eigen3/BUILD
@@ -23,6 +23,6 @@
     ],
     visibility = ["//visibility:public"],
     deps = [
-        "@eigen_archive//:eigen3",
+        "@eigen_archive//:eigen",
     ],
 )
diff --git a/third_party/mediapipe/src/third_party/com_google_audio_tools_fixes.diff b/third_party/mediapipe/src/third_party/com_google_audio_tools_fixes.diff
index 0fd4a4d..fa86390 100644
--- a/third_party/mediapipe/src/third_party/com_google_audio_tools_fixes.diff
+++ b/third_party/mediapipe/src/third_party/com_google_audio_tools_fixes.diff
@@ -35,82 +35,6 @@
  #include <cmath>
  #include <limits>
  #include <string>
-diff --git a/audio/dsp/spectrogram/spectrogram.cc b/audio/dsp/spectrogram/spectrogram.cc
-index e52280d..13c45d0 100644
---- a/audio/dsp/spectrogram/spectrogram.cc
-+++ b/audio/dsp/spectrogram/spectrogram.cc
-@@ -18,6 +18,7 @@
- #include "audio/dsp/spectrogram/spectrogram.h"
- 
- #include <math.h>
-+#include <optional>
- 
- #include "audio/dsp/number_util.h"
- #include "audio/dsp/window_functions.h"
-@@ -38,14 +39,15 @@ bool Spectrogram::ResetSampleBuffer() {
-   return true;
- }
- 
--bool Spectrogram::Initialize(int window_length, int step_length) {
-+bool Spectrogram::Initialize(int window_length, int step_length,
-+                             std::optional<int> fft_length) {
-   std::vector<double> window;
-   HannWindow().GetPeriodicSamples(window_length, &window);
--  return Initialize(window, step_length);
-+  return Initialize(window, step_length, fft_length);
- }
- 
--bool Spectrogram::Initialize(const std::vector<double>& window,
--                             int step_length) {
-+bool Spectrogram::Initialize(const std::vector<double>& window, int step_length,
-+                             std::optional<int> fft_length) {
-   window_length_ = window.size();
-   window_ = window;  // Copy window.
-   if (window_length_ < 2) {
-@@ -61,7 +63,12 @@ bool Spectrogram::Initialize(const std::vector<double>& window,
-     return false;
-   }
- 
--  fft_length_ = NextPowerOfTwo(window_length_);
-+  if (fft_length.has_value() && !IsPowerOfTwoOrZero(fft_length.value())) {
-+    LOG(ERROR) << "FFT length must be a power of two.";
-+    initialized_ = false;
-+    return false;
-+  }
-+  fft_length_ = fft_length.value_or(NextPowerOfTwo(window_length_));
-   CHECK(fft_length_ >= window_length_);
-   output_frequency_channels_ = 1 + fft_length_ / 2;
- 
-diff --git a/audio/dsp/spectrogram/spectrogram.h b/audio/dsp/spectrogram/spectrogram.h
-index 1214422..0f6ada6 100644
---- a/audio/dsp/spectrogram/spectrogram.h
-+++ b/audio/dsp/spectrogram/spectrogram.h
-@@ -36,6 +36,7 @@
- #define AUDIO_DSP_SPECTROGRAM_SPECTROGRAM_H_
- 
- #include <complex>
-+#include <optional>
- #include <deque>
- #include <vector>
- 
-@@ -57,11 +58,14 @@ class Spectrogram {
-   // (both in samples). Internally a Hann window is used as the window
-   // function. Returns true on success, after which calls to Process()
-   // are possible. window_length must be greater than 1 and step
--  // length must be greater than 0.
--  bool Initialize(int window_length, int step_length);
-+  // length must be greater than 0. fft_length defines the fft length which must
-+  // be greater than window_length and a power of 2.
-+  bool Initialize(int window_length, int step_length,
-+                  std::optional<int> fft_length = std::nullopt);
- 
-   // Initialize with an explicit window instead of a length.
--  bool Initialize(const vector<double>& window, int step_length);
-+  bool Initialize(const std::vector<double>& window, int step_length,
-+                  std::optional<int> fft_length = std::nullopt);
- 
-   // Re-initializes/resets the internal sample buffer to the state before any
-   // samples have been passed to the Compute methods.
 diff --git a/third_party/eigen3/BUILD b/third_party/eigen3/BUILD
 index 497c1f0..de1c7f4 100644
 --- a/third_party/eigen3/BUILD
diff --git a/third_party/mediapipe/src/third_party/halide/halide.bzl b/third_party/mediapipe/src/third_party/halide/halide.bzl
index 5f9ef75..d968e848 100644
--- a/third_party/mediapipe/src/third_party/halide/halide.bzl
+++ b/third_party/mediapipe/src/third_party/halide/halide.bzl
@@ -487,7 +487,6 @@
         ),
         "halide_target_map": attr.string_list_dict(),
         "requested_outputs": attr.string_list(),
-        "_cc_toolchain": attr.label(default = "@bazel_tools//tools/cpp:current_cc_toolchain"),
     },
     fragments = ["cpp"],
     toolchains = use_cpp_toolchain(),
diff --git a/third_party/mediapipe/src/third_party/wasm_files.bzl b/third_party/mediapipe/src/third_party/wasm_files.bzl
index 4dfd1cf..ec19899 100644
--- a/third_party/mediapipe/src/third_party/wasm_files.bzl
+++ b/third_party/mediapipe/src/third_party/wasm_files.bzl
@@ -12,120 +12,120 @@
 
     http_file(
         name = "com_google_mediapipe_wasm_audio_wasm_internal_js",
-        sha256 = "9f8d59a241abaa0d3b69dad5a094b843e9f0fdf6d2b7349d3d40541e9679725e",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/audio_wasm_internal.js?generation=1733776155050960"],
+        sha256 = "941b66518727f28f1afb3178a85a19bd494932700e803f0a612820af64b00365",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/audio_wasm_internal.js?generation=1747275568136480"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_audio_wasm_internal_wasm",
-        sha256 = "a57c300fa8fe6756396c1718ddbe4d134e1361e973087ce192bcdab3eea528d1",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/audio_wasm_internal.wasm?generation=1733776156973681"],
+        sha256 = "f27751f01ffc5c3e3e942f048185b5e1c7aab710173e8c41803761a024c8e0da",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/audio_wasm_internal.wasm?generation=1747275570492470"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_audio_wasm_nosimd_internal_js",
-        sha256 = "b9cd5366d4b460d58f151b02ce0ec5784e13130ffb67396cbb532a52ad14c966",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/audio_wasm_nosimd_internal.js?generation=1733776158667129"],
+        sha256 = "8bb1880a37f87d374bee540f615c1ec7cc7e9222cdf7f54f5f431aaa3cd3bc37",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/audio_wasm_nosimd_internal.js?generation=1747275572540382"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_audio_wasm_nosimd_internal_wasm",
-        sha256 = "cdd5c603a5225d85dbb30944fa1e66c46a76790ec246682c4f3d88c571b5a3a6",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/audio_wasm_nosimd_internal.wasm?generation=1733776160452697"],
+        sha256 = "f5a3afccbc04b3049bdaa63755c9f3c0fc2e0f4db27959d24c74b60d422c3d09",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/audio_wasm_nosimd_internal.wasm?generation=1747275574905281"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_genai_experimental_wasm_internal_js",
-        sha256 = "d717a50336544581e619ef6470bef6b6cbb80419ba7628cb1d7894bcb78b134f",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/genai_experimental_wasm_internal.js?generation=1733776162207511"],
+        sha256 = "1f1c3e46898536b124f0da469ac2d9aa5b4954f6a4365266563255c2fb5559e8",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/genai_experimental_wasm_internal.js?generation=1747275576965354"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_genai_experimental_wasm_internal_wasm",
-        sha256 = "856430599596575fdde3418e87ab774bc5e5cb74fd2d258c167ef27eedf62f20",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/genai_experimental_wasm_internal.wasm?generation=1733776163952500"],
+        sha256 = "3a16fcd15fbe52c21a735055f3c8d054c92ca818fd239664313a9aa0c36bc89f",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/genai_experimental_wasm_internal.wasm?generation=1747275579511311"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_genai_experimental_wasm_nosimd_internal_js",
-        sha256 = "6cd43b71667383e643069365b5c76d3fa9a4684b7c53b0342501b2298a4acf36",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/genai_experimental_wasm_nosimd_internal.js?generation=1733776165676349"],
+        sha256 = "00d9060f9c7b286ef1f31bebbca6e39e55ecb9157ee9d5b5933f8321b397636a",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/genai_experimental_wasm_nosimd_internal.js?generation=1747275581542191"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_genai_experimental_wasm_nosimd_internal_wasm",
-        sha256 = "e22418a0e8f3b2781137d2f78bf03088f075512183149695d8d13109e2607e48",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/genai_experimental_wasm_nosimd_internal.wasm?generation=1733776167401717"],
+        sha256 = "aa9c0d916ca7e99b1b8dab57532640f8afcadac48abddc377dacacc817630193",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/genai_experimental_wasm_nosimd_internal.wasm?generation=1747275583843570"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_genai_wasm_internal_js",
-        sha256 = "762a2bdc0cf50598cfb136212e5f4ccd948dd1f8818328f18dc0d6954e34303c",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/genai_wasm_internal.js?generation=1733776169085687"],
+        sha256 = "5805496bf9b006664f6934eee13ce8120937e85807f0f4812324e55d49df9a41",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/genai_wasm_internal.js?generation=1747275585858717"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_genai_wasm_internal_wasm",
-        sha256 = "dc42f8170316ab700cadfc39c0dc65872ea20d72f610b634a1e7850ae2a5449b",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/genai_wasm_internal.wasm?generation=1733776170938658"],
+        sha256 = "777e96a3a4a7daa8ed8288f0b7f7c500a0523f0d753101dc6cc814113c96e0ec",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/genai_wasm_internal.wasm?generation=1747275588399493"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_genai_wasm_nosimd_internal_js",
-        sha256 = "7945ddee65bf96a7fc4d0ee0e12314cbf4da4c948ed11f874c627bb0aa69e10e",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/genai_wasm_nosimd_internal.js?generation=1733776172955953"],
+        sha256 = "afe95a4653d90b4abe31ff6c56a401dcd3090781f2c581e504b7a723d81cd762",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/genai_wasm_nosimd_internal.js?generation=1747275590434871"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_genai_wasm_nosimd_internal_wasm",
-        sha256 = "3bdecd9c4e978b9b912f40e8a174eadd3702eea55f1f7d4255c4e50cf021cbb3",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/genai_wasm_nosimd_internal.wasm?generation=1733776174810127"],
+        sha256 = "d062fa835fe6c9eb5744a678baa368590771b6dffaedff7829f8ab677f785ff7",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/genai_wasm_nosimd_internal.wasm?generation=1747275592866651"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_text_wasm_internal_js",
-        sha256 = "903ddd3412782ce598655b1c052156577da9918e6daf34b8958d730aca685d61",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/text_wasm_internal.js?generation=1733776176490879"],
+        sha256 = "9daa4197ce4cabb2c6bced8b23f2a59db8c829e06a32d005657e9644654650c7",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/text_wasm_internal.js?generation=1747275594913513"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_text_wasm_internal_wasm",
-        sha256 = "fc5e0e540e48e94b00d95f5d29228c2c087cc7e61e77c9b28cdae350d89fdd6b",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/text_wasm_internal.wasm?generation=1733776178221074"],
+        sha256 = "54ddd52a6695f3d95d7539a8ff27cf39a6c5225269caf3844ce72a34b77929c2",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/text_wasm_internal.wasm?generation=1747275597228622"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_text_wasm_nosimd_internal_js",
-        sha256 = "643302ccf7ae8bc455b7a67fe0ec726018a49a509395dbc50c5ec03784e69165",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/text_wasm_nosimd_internal.js?generation=1733776179901587"],
+        sha256 = "45a609e4bf23d9c48af9b8474682b5c73bf8c228aa6719c53b8e1b27155d9fe4",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/text_wasm_nosimd_internal.js?generation=1747275599316019"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_text_wasm_nosimd_internal_wasm",
-        sha256 = "e9cbe88bbb169a5afa1cea60d7f3bc08badc0bb192b3d20c51781827eec11210",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/text_wasm_nosimd_internal.wasm?generation=1733776181647902"],
+        sha256 = "bd4b99614249e6f6b49e5cfafe8e713cdee9d18d125840ebc135976857b8fd9e",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/text_wasm_nosimd_internal.wasm?generation=1747275601728329"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_vision_wasm_internal_js",
-        sha256 = "4a97e2520ba506c680ecd6ba6acfb146888afa0e2746d57f205352bc6ebb82eb",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/vision_wasm_internal.js?generation=1733776183245106"],
+        sha256 = "6edca29f89293197186428ee71e0a7573d6dff843fc9d0617ed73b4bd356ea9f",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/vision_wasm_internal.js?generation=1747275603896816"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_vision_wasm_internal_wasm",
-        sha256 = "f00ec4731faa23b3e714d00e88d4d10e2df5c0a427d3a2b4ae6e3526fdd14ef7",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/vision_wasm_internal.wasm?generation=1733776185044729"],
+        sha256 = "e90cf6af0b392b7b705e4c468fc7b82577dea0d78513418062e81607d9c5692a",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/vision_wasm_internal.wasm?generation=1747275606379153"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_vision_wasm_nosimd_internal_js",
-        sha256 = "927def7b465c51b86e4b3060f93646aca4e27121f4b8fc0483786e407ea9cf1f",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/vision_wasm_nosimd_internal.js?generation=1733776186780167"],
+        sha256 = "7ddac04088972cf641d9235b6f27497d24202de3a2ebdd3fba2225fb3b35d7b6",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/vision_wasm_nosimd_internal.js?generation=1747275608589791"],
     )
 
     http_file(
         name = "com_google_mediapipe_wasm_vision_wasm_nosimd_internal_wasm",
-        sha256 = "3821ea9b1f7fb8c549ef2a064ef5c85750bf375c545a49fd6eea0df44a95f1f4",
-        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/vision_wasm_nosimd_internal.wasm?generation=1733776188639956"],
+        sha256 = "2862ebb173981fd5872983878908d9d9d6e00c042919f7d4ec8d530b6e6cdfb2",
+        urls = ["https://storage.googleapis.com/mediapipe-assets/wasm/vision_wasm_nosimd_internal.wasm?generation=1747275610863577"],
     )
diff --git a/third_party/mediapipe/update.sh b/third_party/mediapipe/update.sh
index 7454292..9d0d6c3c 100755
--- a/third_party/mediapipe/update.sh
+++ b/third_party/mediapipe/update.sh
@@ -91,7 +91,7 @@
 echo "Downloading mediapipe third party dependencies..."
 for dep in "${THIRD_PARTY_DEPS[@]}" ; do
   echo "Downloading ${dep}..."
-  ARCHIVE=$(grep -Pzo "(?s)name = \"${dep}\".*?\)" WORKSPACE | grep -Eao "https://github.com.*?.zip" | sed "s/zip/tar\.gz/")
+  ARCHIVE=$(grep -Pzo "(?s)name = \"${dep}\".*?\)" WORKSPACE | grep -Eao 'https://github.com[^"]*' | sed "s/zip/tar\.gz/")
   if [ -z "${ARCHIVE}" ]; then
     echo "Failed to find ${dep} archive in WORKSPACE"
     exit 1
diff --git a/third_party/perfetto b/third_party/perfetto
index 5a66f76..a9b5b09 160000
--- a/third_party/perfetto
+++ b/third_party/perfetto
@@ -1 +1 @@
-Subproject commit 5a66f76326a04bf33f05433665cd77b7eb288fcc
+Subproject commit a9b5b095dac6ee69731e25683949fb181a57fa24
diff --git a/third_party/protobuf/proto_library.gni b/third_party/protobuf/proto_library.gni
index afd1bd83..f81d458 100644
--- a/third_party/protobuf/proto_library.gni
+++ b/third_party/protobuf/proto_library.gni
@@ -650,8 +650,8 @@
                              "defines",
                              "visibility",
                            ])
-    deps = [ ":$_action_name" ]
-    public_deps = []
+    deps = []
+    public_deps = [ ":$_action_name" ]
 
     # This will link any libraries in the deps (the use of invoker.deps in the
     # action won't link it).
diff --git a/third_party/skia b/third_party/skia
index 13a2999..3ead037d 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 13a299964c9f66e7af63defde83b9c03055fa304
+Subproject commit 3ead037d837c32c819d77607e01f208e91caca07
diff --git a/third_party/webgpu-cts/src b/third_party/webgpu-cts/src
index f5816ba..905c7cb 160000
--- a/third_party/webgpu-cts/src
+++ b/third_party/webgpu-cts/src
@@ -1 +1 @@
-Subproject commit f5816ba68bc2ec4a0c30ef4dcea0b104f81ceb9e
+Subproject commit 905c7cbfeaac1cf3feb4c6056dd6f3dbaa06b074
diff --git a/tools/metrics/histograms/metadata/accessibility/histograms.xml b/tools/metrics/histograms/metadata/accessibility/histograms.xml
index 081bfd12..cd4d888 100644
--- a/tools/metrics/histograms/metadata/accessibility/histograms.xml
+++ b/tools/metrics/histograms/metadata/accessibility/histograms.xml
@@ -374,7 +374,7 @@
 </histogram>
 
 <histogram name="Accessibility.Android.PageZoom.MainFrameZoomFactor"
-    units="zoom factor %" expires_after="2025-09-14">
+    units="zoom factor %" expires_after="2025-11-16">
   <owner>mschillaci@google.com</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
@@ -1590,7 +1590,7 @@
 </histogram>
 
 <histogram name="Accessibility.EngineUse.PageNavsUntilStart" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mschillaci@google.com</owner>
   <owner>aleventhal@chromium.org</owner>
   <owner>chrome-a11y-core@google.com</owner>
@@ -1602,7 +1602,7 @@
 </histogram>
 
 <histogram name="Accessibility.EngineUse.TimeUntilStart" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mschillaci@google.com</owner>
   <owner>aleventhal@chromium.org</owner>
   <owner>chrome-a11y-core@google.com</owner>
@@ -1800,7 +1800,7 @@
 </histogram>
 
 <histogram name="Accessibility.InactiveTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>aleventhal@chromium.org</owner>
   <owner>abigailbklein@chromium.org</owner>
   <owner>janewman@microsoft.com</owner>
@@ -1838,7 +1838,7 @@
 </histogram>
 
 <histogram name="Accessibility.iOS.NewLargerTextCategory" enum="BooleanHit"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>gambard@chromium.org</owner>
   <owner>rkgibson@google.com</owner>
   <summary>
@@ -2179,7 +2179,7 @@
 </histogram>
 
 <histogram name="Accessibility.ManuallyEnabled" enum="BooleanEnabled"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>aleventhal@chromium.org</owner>
   <owner>kenjibaheux@google.com</owner>
   <owner>chrome-a11y-core@google.com</owner>
@@ -2256,7 +2256,7 @@
 </histogram>
 
 <histogram name="Accessibility.PDF.IsPDFTagged" enum="BooleanExists"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dtseng@chromium.org</owner>
   <owner>kyungjunlee@google.com</owner>
   <owner>chrome-a11y-core@google.com</owner>
@@ -3406,7 +3406,7 @@
 </histogram>
 
 <histogram name="Accessibility.ScreenAI.{ServiceName}.InitializationLatency"
-    units="ms" expires_after="2025-09-07">
+    units="ms" expires_after="2025-11-16">
   <owner>rhalavati@chromium.org</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/account_manager/histograms.xml b/tools/metrics/histograms/metadata/account_manager/histograms.xml
index 04e8b16..10d87dcd 100644
--- a/tools/metrics/histograms/metadata/account_manager/histograms.xml
+++ b/tools/metrics/histograms/metadata/account_manager/histograms.xml
@@ -156,7 +156,7 @@
 </histogram>
 
 <histogram name="AccountManager.NumAccounts" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>sinhak@chromium.org</owner>
   <owner>emaamari@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index da71a0d..7e4eeb1 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -389,7 +389,7 @@
 </variants>
 
 <histogram name="Android.ActivityStop.NumberOfTabsUsed" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>gauravjj@google.com</owner>
   <owner>skavuluru@google.com</owner>
   <owner>clank-large-form-factors@google.com</owner>
@@ -405,7 +405,7 @@
 </histogram>
 
 <histogram name="Android.ActivityStop.PercentageOfTabsUsed" units="%"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>gauravjj@google.com</owner>
   <owner>skavuluru@google.com</owner>
   <owner>clank-large-form-factors@google.com</owner>
@@ -1648,7 +1648,7 @@
 </histogram>
 
 <histogram name="Android.DragDrop.Files.Count" units="files"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>joelhockey@chromium.org</owner>
   <owner>clank-large-form-factors@google.com</owner>
   <summary>
@@ -1690,7 +1690,7 @@
 </histogram>
 
 <histogram name="Android.DragDrop.FromWebContent.TargetType"
-    enum="AndroidDragTargetType" expires_after="2025-09-14">
+    enum="AndroidDragTargetType" expires_after="2025-11-16">
   <owner>wenyufu@chromium.org</owner>
   <owner>clank-large-form-factors@google.com</owner>
   <summary>
@@ -1702,7 +1702,7 @@
 </histogram>
 
 <histogram name="Android.DragDrop.Image.OpenFileTime.FirstAttempt" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>shuyng@google.com</owner>
   <owner>clank-large-form-factors@google.com</owner>
   <summary>
@@ -1716,7 +1716,7 @@
 </histogram>
 
 <histogram name="Android.DragDrop.Image.OpenFileTime.FirstExpired" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>shuyng@google.com</owner>
   <owner>clank-large-form-factors@google.com</owner>
   <summary>
@@ -1733,7 +1733,7 @@
 </histogram>
 
 <histogram name="Android.DragDrop.Image.OpenFileTime.LastAttempt" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>shuyng@google.com</owner>
   <owner>clank-large-form-factors@google.com</owner>
   <summary>
@@ -1749,7 +1749,7 @@
 </histogram>
 
 <histogram name="Android.DragDrop.Image.Size" units="KB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>shuyng@google.com</owner>
   <owner>clank-large-form-factors@google.com</owner>
   <summary>
@@ -1931,7 +1931,7 @@
 </histogram>
 
 <histogram name="Android.EdgeToEdge.Eligible" enum="Boolean"
-    expires_after="2025-08-24">
+    expires_after="2025-11-16">
   <owner>lazzzis@google.com</owner>
   <owner>edge-to-edge@chromium.org</owner>
   <summary>
@@ -1977,7 +1977,7 @@
 </histogram>
 
 <histogram name="Android.Event.ActionDown" enum="InputDeviceSource"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mvanouwerkerk@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <owner>src/chrome/android/OWNERS</owner>
@@ -2347,7 +2347,7 @@
 </histogram>
 
 <histogram name="Android.IncognitoReauth.AuthResult"
-    enum="DeviceAuthFinalResult" expires_after="2025-09-14">
+    enum="DeviceAuthFinalResult" expires_after="2025-11-16">
   <owner>roagarwal@chromium.org</owner>
   <owner>chrome-incognito@google.com</owner>
   <summary>
@@ -2357,7 +2357,7 @@
 </histogram>
 
 <histogram name="Android.IncognitoReauth.PrefToggledFromSettingPage"
-    enum="IncognitoReauthToggleValueType" expires_after="2025-09-14">
+    enum="IncognitoReauthToggleValueType" expires_after="2025-11-16">
   <owner>roagarwal@chromium.org</owner>
   <owner>chrome-incognito@google.com</owner>
   <summary>
@@ -2460,7 +2460,7 @@
 </histogram>
 
 <histogram name="Android.InputOnViz.Browser.EventsAfterTransfer"
-    enum="MotionEventAction" expires_after="2025-09-14">
+    enum="MotionEventAction" expires_after="2025-11-16">
   <owner>kartarsingh@google.com</owner>
   <owner>woa-performance-team@google.com</owner>
   <summary>
@@ -2512,7 +2512,7 @@
 </histogram>
 
 <histogram name="Android.InputOnViz.Browser.TouchMovesSeenAfterTransfer"
-    units="counts" expires_after="2025-09-14">
+    units="counts" expires_after="2025-11-16">
   <owner>kartarsingh@google.com</owner>
   <owner>woa-performance-team@google.com</owner>
   <summary>
@@ -2525,7 +2525,7 @@
 </histogram>
 
 <histogram name="Android.InputOnViz.Browser.TransferInputToVizResult"
-    enum="TransferInputToVizResult" expires_after="2025-09-14">
+    enum="TransferInputToVizResult" expires_after="2025-11-16">
   <owner>kartarsingh@google.com</owner>
   <owner>woa-performance-team@google.com</owner>
   <summary>
@@ -2539,7 +2539,7 @@
 </histogram>
 
 <histogram name="Android.InputOnViz.InputReceiverCreationResult"
-    enum="CreateAndroidInputReceiverResult" expires_after="2025-09-14">
+    enum="CreateAndroidInputReceiverResult" expires_after="2025-11-16">
   <owner>kartarsingh@google.com</owner>
   <owner>woa-performance-team@google.com</owner>
   <summary>
@@ -2551,7 +2551,7 @@
 </histogram>
 
 <histogram name="Android.InputOnViz.Viz.PendingStateTransfers.{CurrentState}"
-    units="counts" expires_after="2025-09-14">
+    units="counts" expires_after="2025-11-16">
   <owner>kartarsingh@google.com</owner>
   <owner>woa-performance-team@google.com</owner>
   <summary>
@@ -2656,7 +2656,7 @@
 </histogram>
 
 <histogram name="Android.Intent.MainFrameIntentLaunch"
-    enum="MainFrameIntentLaunch" expires_after="2025-09-14">
+    enum="MainFrameIntentLaunch" expires_after="2025-11-16">
   <owner>mthiesse@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
@@ -2678,7 +2678,7 @@
 </histogram>
 
 <histogram name="Android.Intent.ShareIntentUrlCount" units="URLs"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mthiesse@chromium.org</owner>
   <owner>tedchoc@google.com</owner>
   <summary>
@@ -2857,7 +2857,7 @@
 </histogram>
 
 <histogram name="Android.Messages.Dismissed{MessageIdentifier}"
-    enum="MessageDismissReason" expires_after="2025-09-14">
+    enum="MessageDismissReason" expires_after="2025-11-16">
   <owner>lazzzis@chromium.org</owner>
   <owner>src/components/messages/OWNERS</owner>
   <summary>
@@ -3040,7 +3040,7 @@
 </histogram>
 
 <histogram name="Android.Messages.TimeToAction{MessageIdentifier}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>lazzzis@chromium.org</owner>
   <owner>src/components/messages/OWNERS</owner>
   <summary>
@@ -3251,7 +3251,7 @@
 
 <histogram
     name="Android.MultiWindowMode.AssertIndicesMatch{ActivityIndexMismatchAssignmentState}"
-    enum="PreAssignedActivityState" expires_after="2025-09-14">
+    enum="PreAssignedActivityState" expires_after="2025-11-16">
   <owner>wenyufu@chromium.org</owner>
   <owner>aishwaryarj@google.com</owner>
   <owner>clank-large-form-factors@google.com</owner>
@@ -3284,7 +3284,7 @@
 </histogram>
 
 <histogram name="Android.MultiWindowMode.DraggedTabOpenedNewWindow"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>aishwaryarj@google.com</owner>
   <owner>wenyufu@chromium.org</owner>
   <owner>clank-large-form-factors@google.com</owner>
@@ -4253,7 +4253,7 @@
 </histogram>
 
 <histogram name="Android.Pdf.DocumentLoadTime.FirstPaired" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>shuyng@google.com</owner>
   <owner>clank-large-form-factors@google.com</owner>
   <summary>
@@ -5036,7 +5036,7 @@
 </histogram>
 
 <histogram name="Android.SpareTab.FinalStatus" enum="SpareTabFinalStatus"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>sreejakshetty@chromium.org</owner>
   <owner>chrome-brapp-loading@google.com</owner>
   <summary>
@@ -5180,7 +5180,7 @@
 </histogram>
 
 <histogram name="Android.Tab.CreateNewTabDuration.{TabLaunchType}2" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>sreejakshetty@chromium.org</owner>
   <owner>spelchat@chromium.org</owner>
   <owner>chrome-brapp-loading@google.com</owner>
@@ -5527,7 +5527,7 @@
 </histogram>
 
 <histogram name="Android.ThumbnailCache.InMemoryCacheSize" units="KiB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ckitagawa@chromium.org</owner>
   <owner>dtrainor@chromium.org</owner>
   <summary>
@@ -6225,7 +6225,7 @@
 </histogram>
 
 <histogram name="Android.WebView.Callback.Counts" enum="WebViewCallbackType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ntfschr@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>
@@ -6255,7 +6255,7 @@
 </histogram>
 
 <histogram name="Android.WebView.ComponentUpdater.GetFilesDuration" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>pbirk@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>
@@ -6266,7 +6266,7 @@
 </histogram>
 
 <histogram name="Android.WebView.ComponentUpdater.GetFilesResult"
-    enum="WebViewComponentUpdaterGetFilesResult" expires_after="2025-09-14">
+    enum="WebViewComponentUpdaterGetFilesResult" expires_after="2025-11-16">
   <owner>pbirk@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>
@@ -6288,7 +6288,7 @@
 </histogram>
 
 <histogram name="Android.WebView.ComponentUpdater.UnexpectedExit"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>pbirk@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>
@@ -6299,7 +6299,7 @@
 </histogram>
 
 <histogram name="Android.WebView.ComponentUpdater.UpdateJobDuration" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>pbirk@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>
@@ -6776,7 +6776,7 @@
 </histogram>
 
 <histogram name="Android.WebView.Gfx.HardwareDrawType"
-    enum="WebViewDrawAndSubmissionType" expires_after="2025-09-14">
+    enum="WebViewDrawAndSubmissionType" expires_after="2025-11-16">
   <owner>vasilyt@chromium.org</owner>
   <owner>boliu@chromium.org</owner>
   <summary>
@@ -7759,7 +7759,7 @@
 </histogram>
 
 <histogram name="Android.WebView.SecureCookieAction" enum="SecureCookieAction"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ntfschr@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index c95ca7f6..abca6ee 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -338,7 +338,7 @@
   <token key="AppInstallSurface" variants="AppInstallSurface"/>
 </histogram>
 
-<histogram name="Apps.AppLaunch" enum="AppLaunch" expires_after="2025-09-14">
+<histogram name="Apps.AppLaunch" enum="AppLaunch" expires_after="2025-11-16">
   <owner>tapted@chromium.org</owner>
   <owner>benwells@chromium.org</owner>
   <summary>
@@ -358,7 +358,7 @@
 </histogram>
 
 <histogram name="Apps.AppLaunchPerAppType" enum="AppType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ovn@google.com</owner>
   <owner>cros-web-apps-team@google.com</owner>
   <summary>
@@ -368,7 +368,7 @@
 </histogram>
 
 <histogram name="Apps.AppLaunchPerAppTypeV2" enum="AppTypeV2"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ovn@google.com</owner>
   <owner>cros-web-apps-team@google.com</owner>
   <summary>
@@ -378,7 +378,7 @@
 </histogram>
 
 <histogram name="Apps.AppLaunchSource" enum="LaunchSource"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ovn@google.com</owner>
   <owner>cros-web-apps-team@google.com</owner>
   <summary>Records an app launch grouped by launch source.</summary>
@@ -916,7 +916,7 @@
 </histogram>
 
 <histogram name="Apps.AppList.NumberOfApps" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>tbarzic@chromium.org</owner>
   <owner>mmourgos@chromium.org</owner>
   <owner>gzadina@google.com</owner>
@@ -1794,7 +1794,7 @@
 </histogram>
 
 <histogram name="Apps.AppListAppLaunchedV2{AppListState}"
-    enum="AppListLaunchedFrom" expires_after="2025-09-14">
+    enum="AppListLaunchedFrom" expires_after="2025-11-16">
   <owner>tbarzic@chromium.org</owner>
   <owner>mmourgos@chromium.org</owner>
   <owner>newcomer@chromium.org</owner>
@@ -2264,7 +2264,7 @@
 </histogram>
 
 <histogram name="Apps.AppShimSignatureValidationResult"
-    enum="WebAppShimSignatureValidationResult" expires_after="2025-09-14">
+    enum="WebAppShimSignatureValidationResult" expires_after="2025-11-16">
   <owner>markrowe@chromium.org</owner>
   <owner>chrome-platform-security-core@google.com</owner>
   <summary>
@@ -2382,7 +2382,7 @@
 </histogram>
 
 <histogram name="Apps.CreateShortcuts.Mac.Result2"
-    enum="WebAppCreateShortcutMacResult" expires_after="2025-09-14">
+    enum="WebAppCreateShortcutMacResult" expires_after="2025-11-16">
   <owner>mek@chromium.org</owner>
   <owner>pwa-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml
index 16ef93c..a55a4ec6 100644
--- a/tools/metrics/histograms/metadata/arc/histograms.xml
+++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -380,7 +380,7 @@
 </histogram>
 
 <histogram name="Arc.App.LowMemoryKills.{ArcAppKillType}Count10Minutes"
-    units="Apps" expires_after="2025-09-14">
+    units="Apps" expires_after="2025-11-16">
   <owner>cwd@google.com</owner>
   <owner>cros-vm-technology@google.com</owner>
   <summary>
@@ -392,7 +392,7 @@
 
 <histogram
     name="Arc.App.LowMemoryKills.{ArcBackgroundVms}.{ArcAppKillType}Count10Minutes"
-    units="Apps" expires_after="2025-09-14">
+    units="Apps" expires_after="2025-11-16">
   <owner>cwd@google.com</owner>
   <owner>cros-vm-technology@google.com</owner>
   <summary>
@@ -405,7 +405,7 @@
 
 <histogram
     name="Arc.App.LowMemoryKills{ArcAppKillDailyBackgroundVms}{ArcAppKillDailyType}"
-    units="Apps" expires_after="2025-09-14">
+    units="Apps" expires_after="2025-11-16">
   <owner>cwd@google.com</owner>
   <owner>cros-vm-technology@google.com</owner>
   <summary>
@@ -428,7 +428,7 @@
   </summary>
 </histogram>
 
-<histogram name="Arc.AppCount" units="units" expires_after="2025-09-14">
+<histogram name="Arc.AppCount" units="units" expires_after="2025-11-16">
   <owner>khmel@google.com</owner>
   <owner>fahdi@google.com</owner>
   <summary>
@@ -1108,7 +1108,7 @@
 </histogram>
 
 <histogram name="Arc.EngagementTime.ArcTotal" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mduggan@google.com</owner>
   <owner>yhanada@google.com</owner>
   <owner>arc-framework@google.com</owner>
@@ -1122,7 +1122,7 @@
 </histogram>
 
 <histogram name="Arc.EngagementTime.Background" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mduggan@google.com</owner>
   <owner>yhanada@google.com</owner>
   <owner>arc-framework@google.com</owner>
@@ -1134,7 +1134,7 @@
 </histogram>
 
 <histogram name="Arc.EngagementTime.Foreground" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mduggan@google.com</owner>
   <owner>yhanada@google.com</owner>
   <owner>arc-framework@google.com</owner>
@@ -1145,7 +1145,7 @@
 </histogram>
 
 <histogram name="Arc.EngagementTime.Total" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mduggan@google.com</owner>
   <owner>yhanada@google.com</owner>
   <owner>arc-framework@google.com</owner>
@@ -1665,7 +1665,7 @@
 </histogram>
 
 <histogram name="Arc.Notifications.IsCustomNotification"
-    enum="BooleanIsCustomNotification" expires_after="2025-09-14">
+    enum="BooleanIsCustomNotification" expires_after="2025-11-16">
   <owner>shuminghao@google.com</owner>
   <owner>arc-framework@google.com</owner>
   <summary>
@@ -2244,7 +2244,7 @@
 </histogram>
 
 <histogram name="Arc.SdkVersionUpgradeType" enum="ArcSdkVersionUpgradeType"
-    expires_after="2025-06-22">
+    expires_after="2026-06-22">
   <owner>niwa@google.com</owner>
   <owner>arcvm-eng@google.com</owner>
   <summary>
@@ -2345,7 +2345,7 @@
 </histogram>
 
 <histogram name="Arc.Supervision.Transition.Result"
-    enum="ArcSupervisionTransitionResult" expires_after="2025-09-14">
+    enum="ArcSupervisionTransitionResult" expires_after="2025-11-16">
   <owner>jhorwich@google.com</owner>
   <owner>arc-commercial@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/ash/enums.xml b/tools/metrics/histograms/metadata/ash/enums.xml
index 2b394eb..5478d69 100644
--- a/tools/metrics/histograms/metadata/ash/enums.xml
+++ b/tools/metrics/histograms/metadata/ash/enums.xml
@@ -3020,8 +3020,8 @@
       label="Window is snapped when updating a window in snap group"/>
   <int value="16" label="Window is snapped in test"/>
   <int value="17"
-      label="Window is snapped by long pressing lacros window caption button
-             or window layout menu"/>
+      label="(Obsolete) Window is snapped by long pressing lacros window
+             caption button or window layout menu"/>
   <int value="18"
       label="Window is snapped during the windows swapping in a Snap Group"/>
 </enum>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index c5b43011..79d16d3 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -1168,7 +1168,7 @@
 </histogram>
 
 <histogram name="Ash.Birch.Ranking{Time}" units="ranking"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jamescook@chromium.org</owner>
   <owner>chromeos-launcher@google.com</owner>
   <summary>
@@ -3346,7 +3346,7 @@
 </histogram>
 
 <histogram name="Ash.Display.{DisplayType}.ActiveEffectiveDPI" units="dpi"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>zhangwenyu@google.com</owner>
   <owner>cros-device-enablement@google.com</owner>
   <summary>
@@ -4959,7 +4959,7 @@
 </histogram>
 
 <histogram name="Ash.LoginAnimation.Duration2.{TabletOrClamshellMode}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>oshima@chromium.org</owner>
   <owner>zhzhliu@google.com</owner>
   <owner>cros-sw-perf@google.com</owner>
@@ -5572,7 +5572,7 @@
 </histogram>
 
 <histogram name="Ash.Notification.ImageMemorySizeInKB" units="KB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>andrewxu@chromium.org</owner>
   <owner>cros-status-area-eng@google.com</owner>
   <summary>
@@ -6157,7 +6157,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.AnimationSmoothness.Enter{OverviewAnimationMode}"
-    units="%" expires_after="2025-09-14">
+    units="%" expires_after="2025-11-16">
   <owner>achuith@chromium.org</owner>
   <owner>cros-sw-perf@google.com</owner>
   <summary>
@@ -6169,7 +6169,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.AnimationSmoothness.Exit{OverviewAnimationMode}"
-    units="%" expires_after="2025-09-14">
+    units="%" expires_after="2025-11-16">
   <owner>achuith@chromium.org</owner>
   <owner>cros-sw-perf@google.com</owner>
   <summary>
@@ -6241,7 +6241,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.EndAction" enum="OverviewEndAction"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>minch@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -6257,7 +6257,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.Enter.PresentationTime2.{OverviewStartReason}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>xdai@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>esum@google.com</owner>
@@ -6273,7 +6273,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.Exit.PresentationTime2" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>xdai@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>esum@google.com</owner>
@@ -6285,7 +6285,7 @@
   </summary>
 </histogram>
 
-<histogram name="Ash.Overview.Items" units="units" expires_after="2025-09-14">
+<histogram name="Ash.Overview.Items" units="units" expires_after="2025-11-16">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -6306,7 +6306,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.OverviewClosedItems" units="units"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -6337,7 +6337,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.SelectionDepth" units="items"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -6348,7 +6348,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.StartAction" enum="OverviewStartAction"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>minch@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -6364,7 +6364,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.TimeBetweenActiveWindowChanges" units="seconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -6387,7 +6387,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.TimeInOverview" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -7744,7 +7744,7 @@
 </histogram>
 
 <histogram name="Ash.SeaPen.Freeform.SamplePrompt.SampleClicked"
-    enum="SeaPenSamplePromptId" expires_after="2025-07-31">
+    enum="SeaPenSamplePromptId" expires_after="2025-11-16">
   <owner>ericamlee@google.com</owner>
   <owner>cros-p13n-eng@google.com</owner>
   <summary>
@@ -8120,7 +8120,7 @@
 </histogram>
 
 <histogram name="Ash.Shelf.NumberOfPinnedItems" units="Icons"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>anasalazar@chromium.org</owner>
   <owner>mmourgos@google.com</owner>
   <summary>
@@ -8304,7 +8304,7 @@
 </histogram>
 
 <histogram name="Ash.ShortcutCustomization.ModifyType.{ActionName}"
-    enum="ShortcutCustomizationModificationType" expires_after="2025-09-14">
+    enum="ShortcutCustomizationModificationType" expires_after="2025-11-16">
   <owner>jimmyxgong@chromium.org</owner>
   <owner>cros-device-enablement@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/ash_growth/histograms.xml b/tools/metrics/histograms/metadata/ash_growth/histograms.xml
index cec5afc8..6192a57 100644
--- a/tools/metrics/histograms/metadata/ash_growth/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash_growth/histograms.xml
@@ -74,7 +74,7 @@
 </histogram>
 
 <histogram name="Ash.Growth.CampaignsManager.GetCampaignBySlot"
-    enum="CampaignSlot" expires_after="2025-09-14">
+    enum="CampaignSlot" expires_after="2025-11-16">
   <owner>llin@google.com</owner>
   <owner>cros-growth@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/attribution_reporting/histograms.xml b/tools/metrics/histograms/metadata/attribution_reporting/histograms.xml
index b91ccde7..ff1f117d 100644
--- a/tools/metrics/histograms/metadata/attribution_reporting/histograms.xml
+++ b/tools/metrics/histograms/metadata/attribution_reporting/histograms.xml
@@ -149,7 +149,7 @@
 
 <histogram
     name="Conversions.AggregatableReport.ExtraReportDelayForSuccessfulSend"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>tquintanilla@chromium.org</owner>
   <owner>measurement-api-dev+metrics@google.com</owner>
   <summary>
@@ -700,7 +700,7 @@
 </histogram>
 
 <histogram name="Conversions.HeadersSize.Register{Type}" units="bytes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>tquintanilla@chromium.org</owner>
   <owner>linnan@chromium.org</owner>
   <owner>measurement-api-dev+metrics@google.com</owner>
@@ -890,7 +890,7 @@
 
 <histogram
     name="Conversions.NumDataHostsRegisteredOnClientBounce.{Interaction}.{Duration}"
-    units="data hosts" expires_after="2025-09-14">
+    units="data hosts" expires_after="2025-11-16">
   <owner>linnan@chromium.org</owner>
   <owner>measurement-api-dev+metrics@google.com</owner>
   <summary>
@@ -1264,7 +1264,7 @@
 </histogram>
 
 <histogram name="Conversions.Storage.FindMatchingSourceTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>apaseltiner@chromium.org</owner>
   <owner>measurement-api-dev+metrics@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml
index 6b952488..0821af4 100644
--- a/tools/metrics/histograms/metadata/autofill/histograms.xml
+++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -909,7 +909,7 @@
 </histogram>
 
 <histogram name="Autofill.Address.IsEnabled.PageLoad" enum="BooleanEnabled"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>koerber@google.com</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -919,7 +919,7 @@
 </histogram>
 
 <histogram name="Autofill.Address.IsEnabled.Startup" enum="BooleanEnabled"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>koerber@google.com</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -1380,7 +1380,7 @@
 
 <histogram
     name="Autofill.Autocomplete.PredictionCollisionType2.{PredictionType}.{AutocompleteState}"
-    enum="AutofillFieldType" expires_after="2025-09-14">
+    enum="AutofillFieldType" expires_after="2025-11-16">
   <owner>koerber@google.com</owner>
   <owner>fleimgruber@google.com</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
@@ -1536,7 +1536,7 @@
 </histogram>
 
 <histogram name="Autofill.BetterAuth.EnrollmentPromptOffered" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>vinnypersky@google.com</owner>
   <owner>payments-autofill-team@google.com</owner>
   <summary>
@@ -2019,7 +2019,7 @@
 
 <histogram
     name="Autofill.CreditCard.Seamless{AutofillSeamlessnessFillability}{AutofillSeamlessnessMeasurementTime}{AutofillSeamlessnessVisibility}"
-    enum="CreditCardSeamlessFill" expires_after="2025-09-14">
+    enum="CreditCardSeamlessFill" expires_after="2025-11-16">
   <owner>schwering@google.com</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -2063,7 +2063,7 @@
 
 <histogram
     name="Autofill.CreditCard.Seamless{AutofillSeamlessnessFillability}{AutofillSeamlessnessMeasurementTime}{AutofillSeamlessnessVisibility}.Bitmask"
-    enum="AutofillCreditCardSeamlessnessBitmask" expires_after="2025-09-14">
+    enum="AutofillCreditCardSeamlessnessBitmask" expires_after="2025-11-16">
   <owner>schwering@google.com</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -2927,7 +2927,7 @@
 </histogram>
 
 <histogram name="Autofill.FieldFillingStats{AutofillFormType}{FillingStatus}"
-    units="fields" expires_after="2025-09-14">
+    units="fields" expires_after="2025-11-16">
   <owner>koerber@google.com</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -3298,7 +3298,7 @@
 </histogram>
 
 <histogram name="Autofill.FormFillingScore{AutofillFormType}"
-    units="filling score" expires_after="2025-09-14">
+    units="filling score" expires_after="2025-11-16">
   <owner>koerber@google.com</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -3742,7 +3742,7 @@
 </histogram>
 
 <histogram name="Autofill.iOS.FormSubmission.IsProgrammatic" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>eic@google.com</owner>
   <owner>vincb@google.com</owner>
   <owner>bling-transactions@google.com</owner>
@@ -3757,7 +3757,7 @@
 </histogram>
 
 <histogram name="Autofill.iOS.FormSubmission.Outcome"
-    enum="FormSubmissionOutcomeIOS" expires_after="2025-09-14">
+    enum="FormSubmissionOutcomeIOS" expires_after="2025-11-16">
   <owner>eic@google.com</owner>
   <owner>vincb@google.com</owner>
   <owner>bling-transactions@google.com</owner>
@@ -3771,7 +3771,7 @@
 </histogram>
 
 <histogram name="Autofill.iOS.FormSubmission.Outcome.InvalidFormReason"
-    enum="InvalidSubmittedFormReasonIOS" expires_after="2025-09-14">
+    enum="InvalidSubmittedFormReasonIOS" expires_after="2025-11-16">
   <owner>eic@google.com</owner>
   <owner>vincb@google.com</owner>
   <owner>bling-transactions@google.com</owner>
@@ -3960,7 +3960,7 @@
 </histogram>
 
 <histogram name="Autofill.Leipzig.FillingAssistanceCategory"
-    enum="AutofillCategoryResolvedFillingAssistance" expires_after="2025-09-14">
+    enum="AutofillCategoryResolvedFillingAssistance" expires_after="2025-11-16">
   <owner>koerber@chromium.org</owner>
   <owner>fleimgruber@chromium.org</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
@@ -3971,7 +3971,7 @@
 </histogram>
 
 <histogram name="Autofill.Leipzig.FillingCorrectness.{Category}"
-    enum="BooleanAutofillFillingCorrectness" expires_after="2025-09-14">
+    enum="BooleanAutofillFillingCorrectness" expires_after="2025-11-16">
   <owner>koerber@chromium.org</owner>
   <owner>fleimgruber@chromium.org</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
@@ -4821,7 +4821,7 @@
 </histogram>
 
 <histogram name="Autofill.PerfectFilling.{FormType}" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>koerber@google.com</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -5255,7 +5255,7 @@
 </histogram>
 
 <histogram name="Autofill.ProfileTokenQuality.{Type}" units="Percents"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>fleimgruber@google.com</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -6001,7 +6001,7 @@
 </histogram>
 
 <histogram name="Autofill.StoredCreditCardCount.Server.WithVirtualCardMetadata"
-    units="units" expires_after="2025-09-14">
+    units="units" expires_after="2025-11-16">
   <owner>siyua@chromium.org</owner>
   <owner>payments-autofill-team@google.com</owner>
   <summary>
@@ -7296,7 +7296,7 @@
 
 <histogram
     name="Autofill.VirtualCardEnrollBubble.ConfirmationResult.{IsCardEnrolled}"
-    enum="AutofillVirtualCardEnrollBubbleResult" expires_after="2025-09-14">
+    enum="AutofillVirtualCardEnrollBubbleResult" expires_after="2025-11-16">
   <owner>darwinyang@google.com</owner>
   <owner>kavitasoni@google.com</owner>
   <owner>chrome-payments-team@google.com</owner>
@@ -7750,7 +7750,7 @@
 </histogram>
 
 <histogram name="WebDatabase.AutofillAccountStorage"
-    enum="WebDatabaseAutofillAccountStorageResult" expires_after="2025-09-14">
+    enum="WebDatabaseAutofillAccountStorageResult" expires_after="2025-11-16">
   <owner>mastiz@chromium.org</owner>
   <owner>droger@chromium.org</owner>
   <summary>
@@ -7780,7 +7780,7 @@
 </histogram>
 
 <histogram name="WebDatabase.FailedMigrationToVersion" units="version"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>battre@chromium.org</owner>
   <owner>asully@chromium.org</owner>
   <summary>
@@ -7790,7 +7790,7 @@
 </histogram>
 
 <histogram name="WebDatabase.InitResult" enum="WebDatabaseInitResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>battre@chromium.org</owner>
   <owner>asully@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/background/histograms.xml b/tools/metrics/histograms/metadata/background/histograms.xml
index 11cc3eb1..1d68719b 100644
--- a/tools/metrics/histograms/metadata/background/histograms.xml
+++ b/tools/metrics/histograms/metadata/background/histograms.xml
@@ -80,7 +80,7 @@
 </histogram>
 
 <histogram name="BackgroundSync.Event.OneShotResultPattern"
-    enum="BackgroundSyncResultPattern" expires_after="2025-09-14">
+    enum="BackgroundSyncResultPattern" expires_after="2025-11-16">
   <owner>nator@chromium.org</owner>
   <owner>rayankans@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/blink/enums.xml b/tools/metrics/histograms/metadata/blink/enums.xml
index a2dd51a..35778ec 100644
--- a/tools/metrics/histograms/metadata/blink/enums.xml
+++ b/tools/metrics/histograms/metadata/blink/enums.xml
@@ -6209,6 +6209,11 @@
   <int value="5579" label="PopoverShown"/>
   <int value="5580" label="InputParsedParentOptionOrOptgroup"/>
   <int value="5581" label="NavigatorUAData_toJSON"/>
+  <int value="5582"
+      label="EditContextUpdateTextRangePrecedesOrOverlapsSelection"/>
+  <int value="5583" label="EditContextUpdateTextRangePrecedesCompositionRange"/>
+  <int value="5584" label="EditContextUpdateTextRangeOverlapsCompositionRange"/>
+  <int value="5585" label="EditContextUpdateSelectionDuringActiveComposition"/>
 </enum>
 
 <!-- LINT.ThenChange(//third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom:WebFeature) -->
diff --git a/tools/metrics/histograms/metadata/blink/histograms.xml b/tools/metrics/histograms/metadata/blink/histograms.xml
index 96416145..0e0e63f 100644
--- a/tools/metrics/histograms/metadata/blink/histograms.xml
+++ b/tools/metrics/histograms/metadata/blink/histograms.xml
@@ -274,7 +274,7 @@
 </histogram>
 
 <histogram name="Blink.Canvas.2DLayerBridge.Compression.DecompressionTime"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>lizeb@chromium.org</owner>
   <owner>jpgravel@chromium.org</owner>
   <summary>
@@ -284,7 +284,7 @@
 </histogram>
 
 <histogram name="Blink.Canvas.2DLayerBridge.Compression.Ratio" units="%"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>lizeb@chromium.org</owner>
   <owner>jpgravel@chromium.org</owner>
   <summary>
@@ -304,7 +304,7 @@
 </histogram>
 
 <histogram name="Blink.Canvas.2DLayerBridge.Compression.ThreadTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>lizeb@chromium.org</owner>
   <owner>jpgravel@chromium.org</owner>
   <summary>
@@ -839,6 +839,36 @@
   </summary>
 </histogram>
 
+<histogram name="Blink.CookiesTime.AblationDelay2" units="ms"
+    expires_after="2025-10-26">
+  <owner>elkurin@chromium.org</owner>
+  <owner>chrome-owp-storage@google.com</owner>
+  <summary>
+    Time (in ms) added to Cookies operation with IPC call from the CookieJar
+    used for ablation study purpose. This is incremented to 2 because the
+    Blink.CookiesTime.AblationDelay metrics also includes the metrics for the
+    operation without IPC call.
+  </summary>
+</histogram>
+
+<histogram name="Blink.CookiesTime.{IpcNeeded}" units="ms"
+    expires_after="2025-10-26">
+  <owner>elkurin@chromium.org</owner>
+  <owner>chrome-owp-storage@google.com</owner>
+  <summary>
+    Measures the time it takes to perform a Cookies operation with or without
+    IPC call from the CookieJar. IPC call can be skipped in case where the
+    cookie string is taken successfully and has not changed. In such case, the
+    metrics is recorded for the time to check shared memory and other tasks. The
+    metrics should be separated by whether it needs IPC as it extremely affects
+    the time.
+  </summary>
+  <token key="IpcNeeded">
+    <variant name="IpcNeeded"/>
+    <variant name="IpcNotNeeded"/>
+  </token>
+</histogram>
+
 <histogram name="Blink.CSSStyleSheetResource.ParseTime" units="microseconds"
     expires_after="2025-11-02">
   <owner>gjc@chromium.org</owner>
@@ -865,7 +895,7 @@
 </histogram>
 
 <histogram name="Blink.DecodedImage.AvifDensity.Count.{ImageArea}"
-    units="0.01 bits per pixel" expires_after="2025-09-14">
+    units="0.01 bits per pixel" expires_after="2025-11-16">
   <owner>wtc@google.com</owner>
   <owner>jzern@google.com</owner>
   <owner>
@@ -905,7 +935,7 @@
 </histogram>
 
 <histogram name="Blink.DecodedImage.AvifDensity.KiBWeighted2"
-    units="0.01 bits per pixel" expires_after="2025-09-14">
+    units="0.01 bits per pixel" expires_after="2025-11-16">
   <owner>wtc@google.com</owner>
   <owner>jzern@google.com</owner>
   <owner>
@@ -921,7 +951,7 @@
 </histogram>
 
 <histogram name="Blink.DecodedImage.JpegDensity.Count.{ImageArea}"
-    units="0.01 bits per pixel" expires_after="2025-09-14">
+    units="0.01 bits per pixel" expires_after="2025-11-16">
   <owner>wtc@google.com</owner>
   <owner>jzern@google.com</owner>
   <owner>src/third_party/blink/renderer/platform/image-decoders/OWNERS</owner>
@@ -971,7 +1001,7 @@
 </histogram>
 
 <histogram name="Blink.DecodedImage.WebPDensity.Count.{ImageArea}"
-    units="0.01 bits per pixel" expires_after="2025-09-14">
+    units="0.01 bits per pixel" expires_after="2025-11-16">
   <owner>wtc@google.com</owner>
   <owner>jzern@google.com</owner>
   <owner>src/third_party/blink/renderer/platform/image-decoders/OWNERS</owner>
@@ -1023,7 +1053,7 @@
 </histogram>
 
 <histogram name="Blink.DecodedImage.WebPFileFormat" enum="WebPFileFormat"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mcasas@chromium.org</owner>
   <owner>andrescj@chromium.org</owner>
   <summary>
@@ -1707,7 +1737,7 @@
 </histogram>
 
 <histogram name="Blink.FedCm.LifecycleStateFailureReason"
-    enum="FedCmLifecycleStateFailureReason" expires_after="2025-08-12">
+    enum="FedCmLifecycleStateFailureReason" expires_after="2025-11-16">
   <owner>cbiesinger@chromium.org</owner>
   <owner>web-identity-eng@google.com</owner>
   <summary>
@@ -2725,7 +2755,7 @@
 </histogram>
 
 <histogram name="Blink.HTMLParsing.ParsingTimeMax4" units="microseconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>masonf@chromium.org</owner>
   <owner>dom-dev@google.com</owner>
   <summary>
@@ -3223,7 +3253,7 @@
 </histogram>
 
 <histogram name="Blink.LCPP.DeferUnusedPreload.PredictionFailed{Trigger}"
-    enum="ResourceType" expires_after="2025-09-14">
+    enum="ResourceType" expires_after="2025-11-16">
   <owner>sisidovski@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -3986,7 +4016,7 @@
 </histogram>
 
 <histogram name="Blink.Network.ParseDataURLTime{Type}{CharacterCount}"
-    units="microseconds" expires_after="2025-09-14">
+    units="microseconds" expires_after="2025-11-16">
   <owner>nidhijaju@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -4270,7 +4300,7 @@
 </histogram>
 
 <histogram name="Blink.ResourceRequest.CompletionDelay2" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>horo@chromium.org</owner>
   <owner>net-dev@chromium.org</owner>
   <summary>
@@ -4305,7 +4335,7 @@
 </histogram>
 
 <histogram name="Blink.ResourceRequest.ResponseDelay2" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>horo@chromium.org</owner>
   <owner>net-dev@chromium.org</owner>
   <summary>
@@ -4316,7 +4346,7 @@
 </histogram>
 
 <histogram name="Blink.ResourceRequest.StartDelay2" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>horo@chromium.org</owner>
   <owner>net-dev@chromium.org</owner>
   <summary>
@@ -4850,6 +4880,16 @@
   </summary>
 </histogram>
 
+<histogram name="Blink.SetCookieTime.AblationDelay" units="ms"
+    expires_after="2025-10-26">
+  <owner>elkurin@chromium.org</owner>
+  <owner>chrome-owp-storage@google.com</owner>
+  <summary>
+    Time (in ms) added to SetCookie operation from the CookieJar used for
+    ablation study purpose.
+  </summary>
+</histogram>
+
 <histogram name="Blink.Sms.BackendAvailability"
     enum="WebOTPBackendAvailability" expires_after="2025-08-12">
   <owner>yigu@chromium.org</owner>
@@ -5229,7 +5269,7 @@
 </histogram>
 
 <histogram name="Blink.UseCounter.FeaturePolicy.Header"
-    enum="FeaturePolicyFeature" expires_after="2025-09-14">
+    enum="FeaturePolicyFeature" expires_after="2025-11-16">
   <owner>iclelland@chromium.org</owner>
   <owner>feature-control@chromium.org</owner>
   <summary>
@@ -5536,26 +5576,11 @@
     CookieJar. Logged on every operation from the CookieJar.
   </summary>
   <token key="CookieOperation">
-    <variant name="Cookies"/>
     <variant name="CookiesEnabled"/>
     <variant name="SetCookie"/>
   </token>
 </histogram>
 
-<histogram name="Blink.{CookieOperation}Time.AblationDelay" units="ms"
-    expires_after="2025-10-26">
-  <owner>elkurin@chromium.org</owner>
-  <owner>chrome-owp-storage@google.com</owner>
-  <summary>
-    Time (in ms) added to {CookieOperation} operation from the CookieJar used
-    for ablation study purpose.
-  </summary>
-  <token key="CookieOperation">
-    <variant name="Cookies"/>
-    <variant name="SetCookie"/>
-  </token>
-</histogram>
-
 <histogram name="Blink.{Host}.RenderTaskDuration.{Context}.{Filter}"
     units="microseconds" expires_after="2025-08-03">
   <owner>junov@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/bookmarks/histograms.xml b/tools/metrics/histograms/metadata/bookmarks/histograms.xml
index 9d234c72..cb19815b 100644
--- a/tools/metrics/histograms/metadata/bookmarks/histograms.xml
+++ b/tools/metrics/histograms/metadata/bookmarks/histograms.xml
@@ -166,7 +166,7 @@
 
 <histogram
     name="Bookmarks.BookmarkBar.NavigationOrActivationToFirstContentfulPaint"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>robertlin@chromium.org</owner>
   <owner>chrome-prerendering@google.com</owner>
   <summary>
@@ -191,7 +191,7 @@
 
 <histogram
     name="Bookmarks.BookmarkBar.NavigationOrActivationToLargestContentfulPaint"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>robertlin@chromium.org</owner>
   <owner>chrome-prerendering@google.com</owner>
   <summary>
@@ -213,7 +213,7 @@
 </histogram>
 
 <histogram name="Bookmarks.BookmarkBar.Shown" enum="BooleanShown"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>amelies@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
@@ -222,7 +222,7 @@
 </histogram>
 
 <histogram name="Bookmarks.BookmarksBar.DragDropType"
-    enum="BookmarkBarDragDropType" expires_after="2025-09-14">
+    enum="BookmarkBarDragDropType" expires_after="2025-11-16">
   <owner>dfried@chromium.org</owner>
   <owner>top-chrome-desktop-ui@google.com</owner>
   <summary>
@@ -287,7 +287,7 @@
 </histogram>
 
 <histogram name="Bookmarks.EditLocation" enum="BookmarkLaunchLocation"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dfried@chromium.org</owner>
   <owner>top-chrome-desktop-ui@google.com</owner>
   <summary>
@@ -305,7 +305,7 @@
 </histogram>
 
 <histogram name="Bookmarks.EntryPoint" enum="BookmarksEntryPoint"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ianwen@chromium.org</owner>
   <summary>How users add a new bookmark.</summary>
 </histogram>
@@ -503,7 +503,7 @@
 </histogram>
 
 <histogram name="Bookmarks.RemovedLocation" enum="BookmarkLaunchLocation"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dfried@chromium.org</owner>
   <owner>top-chrome-desktop-ui@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/browser/histograms.xml b/tools/metrics/histograms/metadata/browser/histograms.xml
index 0426e4d..3f303ec 100644
--- a/tools/metrics/histograms/metadata/browser/histograms.xml
+++ b/tools/metrics/histograms/metadata/browser/histograms.xml
@@ -423,7 +423,7 @@
 </histogram>
 
 <histogram name="Browser.ERP.SingleRequestPayloadSize" units="bytes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>lbaraz@chromium.org</owner>
   <owner>cros-reporting-team@google.com</owner>
   <summary>
@@ -1319,7 +1319,7 @@
 </histogram>
 
 <histogram name="BrowserRenderProcessHost.SpareProcessDelayTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kerenzhu@chromium.org</owner>
   <owner>dayeung@chromium.org</owner>
   <owner>robliao@chromium.org</owner>
@@ -1331,7 +1331,7 @@
 </histogram>
 
 <histogram name="BrowserRenderProcessHost.SpareProcessEvictedOtherSpare"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>jam@chromium.org</owner>
   <owner>cduvall@chromium.org</owner>
   <summary>
@@ -1342,7 +1342,7 @@
 </histogram>
 
 <histogram name="BrowserRenderProcessHost.SpareProcessMaybeTakeAction"
-    enum="SpareProcessMaybeTakeAction" expires_after="2025-09-14">
+    enum="SpareProcessMaybeTakeAction" expires_after="2025-11-16">
   <owner>alexmos@chromium.org</owner>
   <owner>lukasza@chromium.org</owner>
   <summary>
@@ -1390,7 +1390,7 @@
 </histogram>
 
 <histogram name="BrowserRenderProcessHost.SpareProcessStartupTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kerenzhu@chromium.org</owner>
   <owner>dayeung@chromium.org</owner>
   <owner>robliao@chromium.org</owner>
@@ -1874,7 +1874,7 @@
   <summary>Records true when the side panel combobox is opened.</summary>
 </histogram>
 
-<histogram name="SidePanel.OpenDuration" units="ms" expires_after="2025-09-14">
+<histogram name="SidePanel.OpenDuration" units="ms" expires_after="2025-11-16">
   <owner>corising@chromium.org</owner>
   <owner>top-chrome-desktop-ui@google.com</owner>
   <summary>
@@ -1897,7 +1897,7 @@
 </histogram>
 
 <histogram name="SidePanel.OpenTrigger" enum="SidePanelOpenTrigger"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>corising@chromium.org</owner>
   <owner>top-chrome-desktop-ui@google.com</owner>
   <summary>
@@ -1959,7 +1959,7 @@
 </histogram>
 
 <histogram name="SidePanel.{SidePanelEntry}.ShownDuration" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>corising@chromium.org</owner>
   <owner>top-chrome-desktop-ui@google.com</owner>
   <summary>
@@ -1971,7 +1971,7 @@
 </histogram>
 
 <histogram name="SidePanel.{SidePanelEntry}.ShowTriggered"
-    enum="SidePanelOpenTrigger" expires_after="2025-09-14">
+    enum="SidePanelOpenTrigger" expires_after="2025-11-16">
   <owner>corising@chromium.org</owner>
   <owner>top-chrome-desktop-ui@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/chrome/histograms.xml b/tools/metrics/histograms/metadata/chrome/histograms.xml
index 316e4343..06ab76d 100644
--- a/tools/metrics/histograms/metadata/chrome/histograms.xml
+++ b/tools/metrics/histograms/metadata/chrome/histograms.xml
@@ -55,7 +55,7 @@
 </histogram>
 
 <histogram name="Chrome.KAnonymityService.JoinSet.Action"
-    enum="KAnonymityServiceJoinSetAction" expires_after="2025-09-14">
+    enum="KAnonymityServiceJoinSetAction" expires_after="2025-11-16">
   <owner>behamilton@google.com</owner>
   <owner>pauljensen@chromium.org</owner>
   <summary>
@@ -79,7 +79,7 @@
 </histogram>
 
 <histogram name="Chrome.KAnonymityService.QuerySet.Action"
-    enum="KAnonymityServiceQuerySetAction" expires_after="2025-09-14">
+    enum="KAnonymityServiceQuerySetAction" expires_after="2025-11-16">
   <owner>behamilton@google.com</owner>
   <owner>pauljensen@chromium.org</owner>
   <summary>
@@ -104,7 +104,7 @@
 </histogram>
 
 <histogram name="Chrome.KAnonymityService.QuerySet.Size" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>behamilton@google.com</owner>
   <owner>pauljensen@chromium.org</owner>
   <summary>
@@ -333,7 +333,7 @@
 </histogram>
 
 <histogram name="ChromeColors.ColorOnLoad" enum="ChromeColorsInfo"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/chromeos/histograms.xml b/tools/metrics/histograms/metadata/chromeos/histograms.xml
index 8d0bb2a7..12bc464 100644
--- a/tools/metrics/histograms/metadata/chromeos/histograms.xml
+++ b/tools/metrics/histograms/metadata/chromeos/histograms.xml
@@ -1276,7 +1276,7 @@
 </histogram>
 
 <histogram name="ChromeOS.CWP.{PPath}.{PType}" units="failures"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>raging@google.com</owner>
   <owner>chromeos-memory@google.com</owner>
   <summary>
@@ -1993,7 +1993,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Inputs.AttachmentForm.{Type}" enum="AttachmentForm"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>wmahon@google.com</owner>
   <owner>chromeos-tango@google.com</owner>
   <owner>cros-device-enablement@google.com</owner>
@@ -2013,7 +2013,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Inputs.AttachmentType.{Form}" enum="AttachmentType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>wmahon@google.com</owner>
   <owner>chromeos-tango@google.com</owner>
   <owner>cros-device-enablement@google.com</owner>
@@ -2721,7 +2721,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Liveness.PingResult" enum="BooleanSuccess"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>iby@google.com</owner>
   <owner>xiyuan@google.com</owner>
   <summary>
@@ -2993,7 +2993,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Ownership.OwnerKeyUmaEvent" enum="OwnerKeyUmaEvent"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>miersh@google.com</owner>
   <owner>chromeos-commercial-networking@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml b/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml
index e87c33e..61859a81 100644
--- a/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml
+++ b/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml
@@ -362,7 +362,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Settings.Display.NewDisplayConnected"
-    enum="DisplayType" expires_after="2025-09-14">
+    enum="DisplayType" expires_after="2025-11-16">
   <owner>zhangwenyu@google.com</owner>
   <owner>cros-device-enablement@google.com</owner>
   <summary>
@@ -384,7 +384,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Settings.Display.{DisplayType}"
-    enum="DisplaySettingsType" expires_after="2025-09-14">
+    enum="DisplaySettingsType" expires_after="2025-11-16">
   <owner>zhangwenyu@google.com</owner>
   <owner>cros-device-enablement@google.com</owner>
   <summary>
@@ -770,7 +770,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Settings.PathVisited"
-    enum="WebUIOSSettingsPathHashes" expires_after="2025-09-14">
+    enum="WebUIOSSettingsPathHashes" expires_after="2025-11-16">
   <owner>wesokuhara@google.com</owner>
   <owner>xiaohuic@chromium.org</owner>
   <owner>cros-settings@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/commerce/histograms.xml b/tools/metrics/histograms/metadata/commerce/histograms.xml
index 019ba4ae..756e2647 100644
--- a/tools/metrics/histograms/metadata/commerce/histograms.xml
+++ b/tools/metrics/histograms/metadata/commerce/histograms.xml
@@ -228,7 +228,7 @@
 </histogram>
 
 <histogram name="Commerce.Discounts.DiscountBubble.SourceTypeOnShow"
-    enum="DiscountType" expires_after="2025-09-15">
+    enum="DiscountType" expires_after="2025-11-16">
   <owner>ihsuanchen@google.com</owner>
   <owner>chrome-shopping@google.com</owner>
   <summary>
@@ -248,7 +248,7 @@
 </histogram>
 
 <histogram name="Commerce.Discounts.DiscountsBubble.SourceTypeOnCopy"
-    enum="DiscountType" expires_after="2025-09-15">
+    enum="DiscountType" expires_after="2025-11-16">
   <owner>ihsuanchen@google.com</owner>
   <owner>chrome-shopping@google.com</owner>
   <summary>
@@ -313,7 +313,7 @@
 </histogram>
 
 <histogram name="Commerce.Discounts.PageActionIcon.SourceTypeOnShown"
-    enum="DiscountType" expires_after="2025-09-15">
+    enum="DiscountType" expires_after="2025-11-16">
   <owner>ihsuanchen@google.com</owner>
   <owner>chrome-shopping@google.com</owner>
   <summary>
@@ -470,7 +470,7 @@
 </histogram>
 
 <histogram name="Commerce.PDPNavigation.{FeatureName}.IneligibilityReason"
-    enum="ShoppingFeatureIneligibilityReason" expires_after="2025-07-27">
+    enum="ShoppingFeatureIneligibilityReason" expires_after="2025-11-16">
   <owner>ayman@chromium.org</owner>
   <owner>mdjones@chromium.org</owner>
   <owner>chrome-shopping@google.com</owner>
@@ -537,7 +537,7 @@
 </histogram>
 
 <histogram name="Commerce.PriceDrop.NotificationChannelCreated" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>zhiyuancai@chromium.org</owner>
   <owner>chrome-shopping@google.com</owner>
   <summary>
@@ -727,7 +727,7 @@
 </histogram>
 
 <histogram name="Commerce.PriceTracking.EmailNotificationsEnabled"
-    enum="PriceNotificationEmailState" expires_after="2025-09-14">
+    enum="PriceNotificationEmailState" expires_after="2025-11-16">
   <owner>ayman@chromium.org</owner>
   <owner>mdjones@chromium.org</owner>
   <owner>chrome-shopping@google.org</owner>
diff --git a/tools/metrics/histograms/metadata/compose/histograms.xml b/tools/metrics/histograms/metadata/compose/histograms.xml
index 0c72aa32..1395d39 100644
--- a/tools/metrics/histograms/metadata/compose/histograms.xml
+++ b/tools/metrics/histograms/metadata/compose/histograms.xml
@@ -38,7 +38,7 @@
 </variants>
 
 <histogram name="Compose.ContextMenu.CTR" enum="ComposeContextMenuCtrEvent"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>sophey@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
@@ -50,7 +50,7 @@
 </histogram>
 
 <histogram name="Compose.ContextMenu.OpenComposeDialogResult"
-    enum="OpenComposeDialogResult" expires_after="2025-09-14">
+    enum="OpenComposeDialogResult" expires_after="2025-11-16">
   <owner>carlosk@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
@@ -71,7 +71,7 @@
 </histogram>
 
 <histogram name="Compose.ContextMenu.ShowStatus" enum="ComposeShowStatus"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>sophey@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
@@ -136,7 +136,7 @@
 </histogram>
 
 <histogram name="Compose.EntryPoint.SessionResume" enum="ComposeEntryPoint"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>perrier@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
@@ -146,7 +146,7 @@
 </histogram>
 
 <histogram name="Compose.EntryPoint.SessionStart" enum="ComposeEntryPoint"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>perrier@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
@@ -156,7 +156,7 @@
 </histogram>
 
 <histogram name="Compose.ProactiveNudge.CTR" enum="ComposeNudgeCtrEvent"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>perrier@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
@@ -179,7 +179,7 @@
 </histogram>
 
 <histogram name="Compose.ProactiveNudge.ShowStatus" enum="ComposeShowStatus"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>perrier@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
@@ -296,7 +296,7 @@
 </histogram>
 
 <histogram name="Compose.{ComposeEvalLocation}Request.Duration.Ok" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>perrier@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
@@ -341,7 +341,7 @@
 </histogram>
 
 <histogram name="Compose.{ComposeEvalLocation}Request.Status"
-    enum="ComposeRequestStatus" expires_after="2025-09-14">
+    enum="ComposeRequestStatus" expires_after="2025-11-16">
   <owner>cuianthony@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
@@ -373,7 +373,7 @@
 </histogram>
 
 <histogram name="Compose.{ComposeEvalLocation}Session.CloseReason"
-    enum="ComposeSessionCloseReasonType" expires_after="2025-09-14">
+    enum="ComposeSessionCloseReasonType" expires_after="2025-11-16">
   <owner>petewil@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
@@ -388,7 +388,7 @@
 
 <histogram
     name="Compose.{ComposeEvalLocation}Session.ComposeCount.{FinalStatus}"
-    units="count" expires_after="2025-09-14">
+    units="count" expires_after="2025-11-16">
   <owner>perrier@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
@@ -403,7 +403,7 @@
 
 <histogram
     name="Compose.{ComposeEvalLocation}Session.DialogShownCount.{FinalStatus}"
-    units="count" expires_after="2025-09-14">
+    units="count" expires_after="2025-11-16">
   <owner>perrier@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
@@ -438,7 +438,7 @@
 </histogram>
 
 <histogram name="Compose.{ComposeEvalLocation}Session.EventCounts"
-    enum="ComposeSessionEventTypes" expires_after="2025-09-14">
+    enum="ComposeSessionEventTypes" expires_after="2025-11-16">
   <owner>perrier@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
@@ -473,7 +473,7 @@
 </histogram>
 
 <histogram name="Compose.{ComposeEvalLocation}Session.UndoCount.{FinalStatus}"
-    units="count" expires_after="2025-09-14">
+    units="count" expires_after="2025-11-16">
   <owner>perrier@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/compositing/histograms.xml b/tools/metrics/histograms/metadata/compositing/histograms.xml
index 2ba4ab4b..d2d76c3 100644
--- a/tools/metrics/histograms/metadata/compositing/histograms.xml
+++ b/tools/metrics/histograms/metadata/compositing/histograms.xml
@@ -98,7 +98,7 @@
 </histogram>
 
 <histogram name="Compositing.Browser.LayersUpdateTime" units="microseconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>pdr@chromium.org</owner>
   <owner>animations-dev@chromium.org</owner>
   <summary>
@@ -172,7 +172,7 @@
 </histogram>
 
 <histogram name="Compositing.DirectRenderer.OverlayProcessingUs"
-    units="microseconds" expires_after="2025-09-14">
+    units="microseconds" expires_after="2025-11-16">
   <owner>khaslett@chromium.org</owner>
   <owner>kylechar@chromium.org</owner>
   <summary>
@@ -376,7 +376,7 @@
 </histogram>
 
 <histogram name="Compositing.Display.Draw.Occlusion.Calculation.Time"
-    units="microseconds" expires_after="2025-09-14">
+    units="microseconds" expires_after="2025-11-16">
   <owner>yiyix@chromium.org</owner>
   <owner>chromeos-gfx@chromium.org</owner>
   <summary>
@@ -404,7 +404,7 @@
 </histogram>
 
 <histogram name="Compositing.Display.DrawToSwapUs" units="microseconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jonross@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
   <summary>
@@ -443,7 +443,7 @@
 </histogram>
 
 <histogram name="Compositing.Display.FlattenedRenderPassCount" units="units"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jonross@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
   <summary>
@@ -494,7 +494,7 @@
 
 <histogram
     name="Compositing.Display.OverlayProcessorUsingStrategy.FramesScalingRequiredOverlays"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>zoraiznaeem@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
   <summary>
@@ -520,7 +520,7 @@
 
 <histogram
     name="Compositing.Display.OverlayProcessorUsingStrategy.NumOverlays{Counted}"
-    units="overlay candidates" expires_after="2025-09-14">
+    units="overlay candidates" expires_after="2025-11-16">
   <owner>khaslett@chromium.org</owner>
   <owner>kylechar@chromium.org</owner>
   <owner>chromeos-gfx-compositor@chromium.org</owner>
@@ -578,7 +578,7 @@
 
 <histogram
     name="Compositing.Display.OverlayProcessorUsingStrategy.WorkingScaleFactorForRequiredOverlays"
-    units="scale_factor" expires_after="2025-09-14">
+    units="scale_factor" expires_after="2025-11-16">
   <owner>zoraiznaeem@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
   <summary>
@@ -669,7 +669,7 @@
 </histogram>
 
 <histogram name="Compositing.Renderer.CALayerResult" enum="CALayerResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ccameron@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/content/histograms.xml b/tools/metrics/histograms/metadata/content/histograms.xml
index 1ac4084..bd37378 100644
--- a/tools/metrics/histograms/metadata/content/histograms.xml
+++ b/tools/metrics/histograms/metadata/content/histograms.xml
@@ -398,7 +398,7 @@
 </histogram>
 
 <histogram name="ContentSettings.RegularProfile.DefaultBackgroundSyncSetting"
-    enum="ContentSetting" expires_after="2025-09-14">
+    enum="ContentSetting" expires_after="2025-11-16">
   <owner>tungnh@chromium.org</owner>
   <owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/contextual_cueing/histograms.xml b/tools/metrics/histograms/metadata/contextual_cueing/histograms.xml
index 444e059..aaee3b4 100644
--- a/tools/metrics/histograms/metadata/contextual_cueing/histograms.xml
+++ b/tools/metrics/histograms/metadata/contextual_cueing/histograms.xml
@@ -32,7 +32,7 @@
 <!-- LINT.ThenChange(//chrome/browser/contextual_cueing/contextual_cueing_helper.cc:OptType) -->
 
 <histogram name="ContextualCueing.GlicSuggestions.MesFetchLatency" units="ms"
-    expires_after="2025-08-30">
+    expires_after="2025-11-16">
   <owner>zekunjiang@google.com</owner>
   <owner>rajendrant@google.com</owner>
   <owner>sophiechang@chromium.org</owner>
@@ -45,7 +45,7 @@
 
 <histogram
     name="ContextualCueing.GlicSuggestions.PageContextFetchlatency.{PageContextType}"
-    units="ms" expires_after="2025-08-30">
+    units="ms" expires_after="2025-11-16">
   <owner>zekunjiang@google.com</owner>
   <owner>rajendrant@google.com</owner>
   <owner>sophiechang@chromium.org</owner>
@@ -68,7 +68,7 @@
 
 <histogram
     name="ContextualCueing.GlicSuggestions.SuggestionsFetchLatency.{ResultType}"
-    units="ms" expires_after="2025-08-30">
+    units="ms" expires_after="2025-11-16">
   <owner>zekunjiang@google.com</owner>
   <owner>rajendrant@google.com</owner>
   <owner>sophiechang@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/cookie/histograms.xml b/tools/metrics/histograms/metadata/cookie/histograms.xml
index 3d81e208..f433da8b 100644
--- a/tools/metrics/histograms/metadata/cookie/histograms.xml
+++ b/tools/metrics/histograms/metadata/cookie/histograms.xml
@@ -109,7 +109,7 @@
 </histogram>
 
 <histogram name="Cookie.CookieJarSize" units="kibibytes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dylancutler@google.com</owner>
   <owner>src/net/cookies/OWNERS</owner>
   <summary>
@@ -144,7 +144,7 @@
 </histogram>
 
 <histogram name="Cookie.CookieSchemeRequestScheme" enum="CookieRequestScheme"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bingler@chromium.org</owner>
   <owner>miketaylr@chromium.org</owner>
   <summary>
@@ -629,7 +629,7 @@
 </histogram>
 
 <histogram name="Cookie.MaxSameSiteNoneCookiesPerKey" units="units"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dylancutler@google.com</owner>
   <owner>src/net/cookies/OWNERS</owner>
   <summary>
@@ -688,7 +688,7 @@
 </histogram>
 
 <histogram name="Cookie.PartitionCount" units="partitions"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dylancutler@google.com</owner>
   <owner>src/net/cookies/OWNERS</owner>
   <summary>
@@ -711,7 +711,7 @@
 </histogram>
 
 <histogram name="Cookie.PartitionedCookieCount" units="cookies"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dylancutler@google.com</owner>
   <owner>src/net/cookies/OWNERS</owner>
   <summary>
@@ -737,7 +737,7 @@
 </histogram>
 
 <histogram name="Cookie.PartitionedCookieJarSizeKibibytes" units="kibibytes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dylancutler@google.com</owner>
   <owner>src/net/cookies/OWNERS</owner>
   <summary>
@@ -748,7 +748,7 @@
 </histogram>
 
 <histogram name="Cookie.PartitionedCookieJarSizeKibibytes.{NonceType}"
-    units="kibibytes" expires_after="2025-09-14">
+    units="kibibytes" expires_after="2025-11-16">
   <owner>dylancutler@google.com</owner>
   <owner>src/net/cookies/OWNERS</owner>
   <summary>
@@ -764,7 +764,7 @@
 </histogram>
 
 <histogram name="Cookie.PartitionedCookiesInRequest" units="cookies"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dylancutler@google.com</owner>
   <owner>src/net/cookies/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/cras/histograms.xml b/tools/metrics/histograms/metadata/cras/histograms.xml
index e70b1b7..b88a515 100644
--- a/tools/metrics/histograms/metadata/cras/histograms.xml
+++ b/tools/metrics/histograms/metadata/cras/histograms.xml
@@ -155,14 +155,14 @@
   </summary>
 </histogram>
 
-<histogram name="Cras.ApNcRuntime" units="seconds" expires_after="2025-09-14">
+<histogram name="Cras.ApNcRuntime" units="seconds" expires_after="2025-11-16">
   <owner>hunghsienchen@chromium.org</owner>
   <owner>chromeos-audio@google.com</owner>
   <summary>Tracks the runtime of the APM when AP NC is active.</summary>
 </histogram>
 
 <histogram name="Cras.ApNcStartStatus" enum="CrasApNcStartStatus"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>hunghsienchen@chromium.org</owner>
   <owner>chromeos-audio@google.com</owner>
   <summary>
@@ -1151,7 +1151,7 @@
 </histogram>
 
 <histogram name="Cras.StreamRuntime{Cras_Direction}" units="seconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
 <!-- Name completed by histogram_suffixes
      name="Cras.Direction" and
      name="Cras.ClientType" and
@@ -1226,7 +1226,7 @@
 </histogram>
 
 <histogram name="Cras.UnderrunsPerDevice{Device}" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>yuhsuan@chromium.org</owner>
   <owner>chromeos-audio@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/cros_federated/histograms.xml b/tools/metrics/histograms/metadata/cros_federated/histograms.xml
index a22a773e..3e98039 100644
--- a/tools/metrics/histograms/metadata/cros_federated/histograms.xml
+++ b/tools/metrics/histograms/metadata/cros_federated/histograms.xml
@@ -32,7 +32,7 @@
 </variants>
 
 <histogram name="FederatedService.ServiceEvent" enum="FederatedServiceEvent"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>alanlxl@chromium.org</owner>
   <owner>amoylan@chromium.org</owner>
   <owner>cros-federated-team@google.com</owner>
@@ -110,7 +110,7 @@
 </histogram>
 
 <histogram name="FederatedService.{Population}.Event"
-    enum="FederatedClientEvent" expires_after="2025-09-14">
+    enum="FederatedClientEvent" expires_after="2025-11-16">
   <owner>alanlxl@chromium.org</owner>
   <owner>amoylan@chromium.org</owner>
   <owner>cros-federated-team@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/cros_ml/histograms.xml b/tools/metrics/histograms/metadata/cros_ml/histograms.xml
index a9e4454..bb6303a 100644
--- a/tools/metrics/histograms/metadata/cros_ml/histograms.xml
+++ b/tools/metrics/histograms/metadata/cros_ml/histograms.xml
@@ -60,7 +60,7 @@
 </variants>
 
 <histogram name="MachineLearningService.CpuUsageMilliPercent"
-    units="1/1000ths of %" expires_after="2025-09-14">
+    units="1/1000ths of %" expires_after="2025-11-16">
   <owner>alanlxl@chromium.org</owner>
   <owner>amoylan@chromium.org</owner>
   <summary>
@@ -226,7 +226,7 @@
 </histogram>
 
 <histogram name="MachineLearningService.MojoConnectionEvent"
-    enum="MachineLearningServiceMojoConnectionEvent" expires_after="2025-09-14">
+    enum="MachineLearningServiceMojoConnectionEvent" expires_after="2025-11-16">
   <owner>alanlxl@chromium.org</owner>
   <owner>amoylan@chromium.org</owner>
   <summary>
@@ -256,7 +256,7 @@
 </histogram>
 
 <histogram name="MachineLearningService.ProcessError"
-    enum="MachineLearningServiceProcessError" expires_after="2025-09-14">
+    enum="MachineLearningServiceProcessError" expires_after="2025-11-16">
   <owner>amoylan@chromium.org</owner>
   <owner>alanlxl@chromium.org</owner>
   <summary>
@@ -315,7 +315,7 @@
 <histogram
     name="MachineLearningService.WebPlatformHandwritingModel.LoadModelResult.Event"
     enum="MachineLearningServiceLoadHandwritingModelResultEvent"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>amoylan@chromium.org</owner>
   <owner>alanlxl@chromium.org</owner>
   <summary>
@@ -336,7 +336,7 @@
 </histogram>
 
 <histogram name="MachineLearningService.WorkerProcessCleanUpTime"
-    units="microseconds" expires_after="2025-09-14">
+    units="microseconds" expires_after="2025-11-16">
   <owner>alanlxl@chromium.org</owner>
   <owner>amoylan@chromium.org</owner>
   <summary>
@@ -407,7 +407,7 @@
 </histogram>
 
 <histogram name="MachineLearningService.{RequestName}.CpuTimeMicrosec"
-    units="microseconds" expires_after="2025-09-14">
+    units="microseconds" expires_after="2025-11-16">
   <owner>amoylan@chromium.org</owner>
   <owner>alanlxl@chromium.org</owner>
   <summary>
@@ -419,7 +419,7 @@
 </histogram>
 
 <histogram name="MachineLearningService.{RequestName}.TotalMemoryDeltaKb"
-    units="KB" expires_after="2025-09-14">
+    units="KB" expires_after="2025-11-16">
   <owner>amoylan@chromium.org</owner>
   <owner>alanlxl@chromium.org</owner>
   <summary>Memory usage increase caused by {RequestName} request.</summary>
diff --git a/tools/metrics/histograms/metadata/crostini/histograms.xml b/tools/metrics/histograms/metadata/crostini/histograms.xml
index 38d5827..f6bab55d1 100644
--- a/tools/metrics/histograms/metadata/crostini/histograms.xml
+++ b/tools/metrics/histograms/metadata/crostini/histograms.xml
@@ -106,7 +106,7 @@
 </histogram>
 
 <histogram name="Crostini.Backup" enum="CrostiniExportContainerResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>denniskempin@google.com</owner>
   <owner>clumptini@google.com</owner>
   <summary>Result of crostini backup.</summary>
@@ -197,7 +197,7 @@
 </histogram>
 
 <histogram name="Crostini.DiskResize.Result" enum="CrostiniDiskImageStatus"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>denniskempin@google.com</owner>
   <owner>clumptini@google.com</owner>
   <summary>
@@ -264,7 +264,7 @@
 </histogram>
 
 <histogram name="Crostini.FilesystemCorruption" enum="CorruptionStates"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>sidereal@google.com</owner>
   <owner>denniskempin@google.com</owner>
   <owner>clumptini@google.com</owner>
@@ -428,7 +428,7 @@
 </histogram>
 
 <histogram name="Crostini.SetupResult" enum="CrostiniSetupResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>denniskempin@google.com</owner>
   <owner>clumptini@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/cryptohome/histograms.xml b/tools/metrics/histograms/metadata/cryptohome/histograms.xml
index 5a0650b..86da1f0 100644
--- a/tools/metrics/histograms/metadata/cryptohome/histograms.xml
+++ b/tools/metrics/histograms/metadata/cryptohome/histograms.xml
@@ -57,7 +57,7 @@
 </variants>
 
 <histogram name="Cryptohome.AuthFactorBackingStoreConfig"
-    enum="CryptohomeAuthFactorBackingStoreConfig" expires_after="2025-09-14">
+    enum="CryptohomeAuthFactorBackingStoreConfig" expires_after="2025-11-16">
   <owner>jadmanski@chromium.org</owner>
   <owner>cros-security-cryptohome+uma@google.com</owner>
   <summary>
@@ -150,7 +150,7 @@
 </histogram>
 
 <histogram name="Cryptohome.Errors" enum="CryptohomeError"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>apronin@chromium.org</owner>
   <owner>cros-hwsec+uma@google.com</owner>
   <summary>Cryptohome errors.</summary>
@@ -481,7 +481,7 @@
 </histogram>
 
 <histogram name="Cryptohome.TimeToGenerateEccAuthValue" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>yich@google.com</owner>
   <owner>cros-hwsec+uma@google.com</owner>
   <summary>
@@ -671,7 +671,7 @@
 </histogram>
 
 <histogram name="Cryptohome.{Action}AuthBlockType"
-    enum="CryptohomeAuthBlockType" expires_after="2025-09-14">
+    enum="CryptohomeAuthBlockType" expires_after="2025-11-16">
   <owner>yich@google.com</owner>
   <owner>cros-hwsec+uma@google.com</owner>
   <summary>
@@ -708,7 +708,7 @@
 </histogram>
 
 <histogram name="Cryptohome.{AuthSessionFunction}.{AuthBlockType}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>thomascedeno@google.com</owner>
   <owner>cros-security-cryptohome+uma@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/custom_tabs/enums.xml b/tools/metrics/histograms/metadata/custom_tabs/enums.xml
index 9356d31..fb9f2f565 100644
--- a/tools/metrics/histograms/metadata/custom_tabs/enums.xml
+++ b/tools/metrics/histograms/metadata/custom_tabs/enums.xml
@@ -303,6 +303,24 @@
   <int value="4" label="Session, Warmup"/>
 </enum>
 
+<enum name="WebAppBackButtonEvent">
+  <int value="0"
+      label="Invalid back event due to tab switching, e.g. re-parenting."/>
+  <int value="1"
+      label="Back event triggered by click or touch without meta keys."/>
+  <int value="2"
+      label="Open a history navigation popup after long pressing button."/>
+</enum>
+
+<enum name="WebAppReloadButtonEvent">
+  <int value="0"
+      label="Invalid reload type due to tab switching, e.g. re-parenting."/>
+  <int value="1" label="Stop reloading currently active tab."/>
+  <int value="2"
+      label="Reload currently active tab including checking the cache."/>
+  <int value="3" label="Reload currently active tab ignoring the cache."/>
+</enum>
+
 <enum name="WebContentsState">
   <int value="0" label="No WebContents"/>
   <int value="1" label="Prerendered WebContents"/>
diff --git a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
index c1393a02..4f51473 100644
--- a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
+++ b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
@@ -169,7 +169,7 @@
 </histogram>
 
 <histogram name="CustomTabs.ClientAppId" enum="ClientAppId"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>yusufo@chromium.org</owner>
   <summary>
     Android: AppId declared by the launching application in EXTRA_APPLICATION_ID
@@ -201,7 +201,7 @@
 </histogram>
 
 <histogram name="CustomTabs.CloseCause" enum="CustomTabsCloseCause"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jinsukkim@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <owner>cct-team@google.com</owner>
@@ -894,7 +894,7 @@
 </histogram>
 
 <histogram name="CustomTabs.WarmupStateOnLaunch" enum="WarmupStateOnLaunch"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>lizeb@chromium.org</owner>
   <summary>
     Recorded only on Android. Reports whether warmup() has been called when a
@@ -904,6 +904,26 @@
   </summary>
 </histogram>
 
+<histogram name="CustomTabs.WebAppHeader.BackButtonEvent"
+    enum="WebAppBackButtonEvent" expires_after="2026-05-31">
+  <owner>vkorotkevich@google.com</owner>
+  <owner>pwa-team@google.com</owner>
+  <summary>
+    Records the usage of back button when running a web app. This is recorded
+    only for minimal ui display mode in Trusted Web Activities and WebAPKs.
+  </summary>
+</histogram>
+
+<histogram name="CustomTabs.WebAppHeader.ReloadButtonEvent"
+    enum="WebAppReloadButtonEvent" expires_after="2026-05-31">
+  <owner>vkorotkevich@google.com</owner>
+  <owner>pwa-team@google.com</owner>
+  <summary>
+    Records the usage of reload button when running a web app. This is recorded
+    only for minimal ui display mode in Trusted Web Activities and WebAPKs.
+  </summary>
+</histogram>
+
 <histogram name="CustomTabs.WebContentsStateOnLaunch" enum="WebContentsState"
     expires_after="2026-04-13">
   <owner>lizeb@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/data/histograms.xml b/tools/metrics/histograms/metadata/data/histograms.xml
index 83a1962..f457201 100644
--- a/tools/metrics/histograms/metadata/data/histograms.xml
+++ b/tools/metrics/histograms/metadata/data/histograms.xml
@@ -117,7 +117,7 @@
 </histogram>
 
 <histogram name="DataUse.BytesSent3.Delegate" units="bytes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>curranmax@chromium.org</owner>
   <owner>ryansturm@chromium.org</owner>
   <owner>spelchat@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/dev/histograms.xml b/tools/metrics/histograms/metadata/dev/histograms.xml
index 54383f0..0781f531 100644
--- a/tools/metrics/histograms/metadata/dev/histograms.xml
+++ b/tools/metrics/histograms/metadata/dev/histograms.xml
@@ -23,7 +23,7 @@
 <histograms>
 
 <histogram name="DevTools.ActionTaken" enum="DevToolsAction"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>yangguo@google.com</owner>
   <owner>bmeurer@google.com</owner>
   <summary>Specified DevTools action has been taken.</summary>
@@ -58,7 +58,7 @@
 </histogram>
 
 <histogram name="DevTools.CDPCommandFrom{ClientType}" enum="CDPCommands"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>wolfi@google.com</owner>
   <owner>danilsomsikov@google.com</owner>
   <owner>yangguo@google.com</owner>
@@ -151,7 +151,7 @@
 </histogram>
 
 <histogram name="DevTools.ExperimentDisabled" enum="DevtoolsExperiments"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>yangguo@google.com</owner>
   <owner>changhaohan@google.com</owner>
   <summary>
@@ -169,7 +169,7 @@
 </histogram>
 
 <histogram name="DevTools.ExperimentEnabled" enum="DevtoolsExperiments"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>yangguo@google.com</owner>
   <owner>changhaohan@google.com</owner>
   <summary>
@@ -178,7 +178,7 @@
 </histogram>
 
 <histogram name="DevTools.ExperimentEnabledAtLaunch" enum="DevtoolsExperiments"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>yangguo@google.com</owner>
   <owner>changhaohan@google.com</owner>
   <summary>
@@ -205,7 +205,7 @@
   </summary>
 </histogram>
 
-<histogram name="DevTools.InspectElement" units="ms" expires_after="2025-09-14">
+<histogram name="DevTools.InspectElement" units="ms" expires_after="2025-11-16">
   <owner>yangguo@google.com</owner>
   <owner>bmeurer@google.com</owner>
   <summary>
@@ -352,7 +352,7 @@
 </histogram>
 
 <histogram name="DevTools.OpenedByAction" enum="DevToolsOpenedByAction"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>changhaohan@google.com</owner>
   <owner>yangguo@google.com</owner>
   <owner>mathiasb@google.com</owner>
@@ -362,7 +362,7 @@
 </histogram>
 
 <histogram name="DevTools.PanelShown" enum="DevToolsPanel"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>yangguo@google.com</owner>
   <owner>bmeurer@google.com</owner>
   <summary>Specified DevTools panel was shown.</summary>
@@ -489,7 +489,7 @@
 </histogram>
 
 <histogram name="DevTools.SwatchActivated" enum="DevToolsSwatchActivated"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ergunsh@google.com</owner>
   <owner>changhaohan@google.com</owner>
   <owner>bmeurer@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/disk/histograms.xml b/tools/metrics/histograms/metadata/disk/histograms.xml
index 816e5bf..678aa19 100644
--- a/tools/metrics/histograms/metadata/disk/histograms.xml
+++ b/tools/metrics/histograms/metadata/disk/histograms.xml
@@ -23,7 +23,7 @@
 <histograms>
 
 <histogram name="DiskCache.0.Error" enum="DiskCacheError"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>wfh@chromium.org</owner>
   <owner>src/net/disk_cache/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/download/histograms.xml b/tools/metrics/histograms/metadata/download/histograms.xml
index 60ac6e9..913cd718c 100644
--- a/tools/metrics/histograms/metadata/download/histograms.xml
+++ b/tools/metrics/histograms/metadata/download/histograms.xml
@@ -317,7 +317,7 @@
 </histogram>
 
 <histogram name="Download.Counts.{ParallelizableDownload}"
-    enum="DownloadCountType" expires_after="2025-09-14">
+    enum="DownloadCountType" expires_after="2025-11-16">
   <owner>shaktisahu@chromium.org</owner>
   <owner>clank-downloads@google.com</owner>
   <summary>
@@ -749,7 +749,7 @@
 </histogram>
 
 <histogram name="Download.Open.ContentType" enum="DownloadContentType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>drubery@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -772,7 +772,7 @@
 </histogram>
 
 <histogram name="Download.OpenDownloads.PerProfileType"
-    enum="BrowserProfileType" expires_after="2025-09-14">
+    enum="BrowserProfileType" expires_after="2025-11-16">
   <owner>sideyilmaz@chromium.org</owner>
   <owner>chrome-incognito@google.com</owner>
   <summary>
@@ -1262,7 +1262,7 @@
 </histogram>
 
 <histogram name="Download.WarningData.AddWarningActionEventOutcome2"
-    enum="DownloadAddWarningActionEventOutcome" expires_after="2025-09-14">
+    enum="DownloadAddWarningActionEventOutcome" expires_after="2025-11-16">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -1273,7 +1273,7 @@
 </histogram>
 
 <histogram name="Download.WarningData.SurfaceWithoutWarningShown"
-    enum="DownloadWarningSurface" expires_after="2025-09-14">
+    enum="DownloadWarningSurface" expires_after="2025-11-16">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/enterprise/histograms.xml b/tools/metrics/histograms/metadata/enterprise/histograms.xml
index bb86456..8b60f34 100644
--- a/tools/metrics/histograms/metadata/enterprise/histograms.xml
+++ b/tools/metrics/histograms/metadata/enterprise/histograms.xml
@@ -726,7 +726,7 @@
 </histogram>
 
 <histogram name="Enterprise.DeviceRemoteCommand.Crd.Result"
-    enum="EnterpriseCrdSessionResultCode" expires_after="2025-09-14">
+    enum="EnterpriseCrdSessionResultCode" expires_after="2025-11-16">
   <owner>macinashutosh@google.com</owner>
   <owner>chromeos-commercial-crd@google.com</owner>
   <summary>Reports success/failure when a session is attempted.</summary>
@@ -1647,7 +1647,7 @@
 </histogram>
 
 <histogram name="Enterprise.Dlp.ReportedBlockLevelRestriction"
-    enum="EnterpriseDlpPolicyRestriction" expires_after="2025-09-14">
+    enum="EnterpriseDlpPolicyRestriction" expires_after="2025-11-16">
   <owner>poromov@chromium.org</owner>
   <owner>chromeos-dlp@google.com</owner>
   <summary>
@@ -1657,7 +1657,7 @@
 </histogram>
 
 <histogram name="Enterprise.Dlp.ReportedEventStatus" enum="GoogleRpcCode"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>poromov@chromium.org</owner>
   <owner>chromeos-dlp@google.com</owner>
   <summary>
@@ -1666,7 +1666,7 @@
 </histogram>
 
 <histogram name="Enterprise.Dlp.ReportedReportLevelRestriction"
-    enum="EnterpriseDlpPolicyRestriction" expires_after="2025-09-14">
+    enum="EnterpriseDlpPolicyRestriction" expires_after="2025-11-16">
   <owner>poromov@chromium.org</owner>
   <owner>chromeos-dlp@google.com</owner>
   <summary>
@@ -1852,7 +1852,7 @@
 </histogram>
 
 <histogram name="Enterprise.DMServerRequestSuccess{EnterpriseDMServerRequest}"
-    enum="EnterpriseDMServerRequestSuccess" expires_after="2025-09-14">
+    enum="EnterpriseDMServerRequestSuccess" expires_after="2025-11-16">
   <owner>rbock@google.com</owner>
   <owner>chromeos-commercial-remote-management@google.com</owner>
   <owner>managed-devices@google.com</owner>
@@ -2185,7 +2185,7 @@
 </histogram>
 
 <histogram name="Enterprise.EnrollmentRollbackAttestation"
-    enum="EnterpriseEnrollmentType" expires_after="2025-09-14">
+    enum="EnterpriseEnrollmentType" expires_after="2025-11-16">
   <owner>crisguerrero@chromium.org</owner>
   <owner>mpolzer@google.com</owner>
   <owner>chromeos-commercial-remote-management@google.com</owner>
@@ -2949,7 +2949,7 @@
 </histogram>
 
 <histogram name="Enterprise.PublicSession.SessionLength" units="minutes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bfranz@chromium.org</owner>
   <owner>chromeos-kiosk-eng@google.com</owner>
   <summary>
@@ -3040,7 +3040,7 @@
 </histogram>
 
 <histogram name="Enterprise.SafeSites.Latency" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ftirelo@chromium.org</owner>
   <owner>ljjlee@google.com</owner>
   <owner>cbe-eng@google.com</owner>
@@ -3070,7 +3070,7 @@
 
 <histogram name="Enterprise.SecondaryGoogleAccountUsage.PolicyFetch.Status"
     enum="SecondaryGoogleAccountUsagePolicyFetchStatus"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>rodmartin@google.com</owner>
   <owner>chromeos-commercial-identity@google.com</owner>
   <summary>
@@ -3807,7 +3807,7 @@
 
 <histogram
     name="Enterprise.{ContentAnalysisProtocol}Request.{ContentAnalysisRequestType}.Result"
-    enum="SafeBrowsingBinaryUploadResult" expires_after="2025-09-14">
+    enum="SafeBrowsingBinaryUploadResult" expires_after="2025-11-16">
   <owner>nancylanxiao@google.com</owner>
   <owner>domfc@chromium.org</owner>
   <owner>cbe-cep-eng@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/event/histograms.xml b/tools/metrics/histograms/metadata/event/histograms.xml
index 3c92e64d..7191106 100644
--- a/tools/metrics/histograms/metadata/event/histograms.xml
+++ b/tools/metrics/histograms/metadata/event/histograms.xml
@@ -79,7 +79,7 @@
 <histogram
     name="Event.DownEventCount.PerInputFormFactorDestinationCombination2"
     enum="DownEventInputFormFactorDestinationCombination2"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>tbuckley@chromium.org</owner>
   <summary>
     The number of down events received per destination, input and form factor
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml
index aa386160..f3613ef 100644
--- a/tools/metrics/histograms/metadata/extensions/histograms.xml
+++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -751,7 +751,7 @@
 </histogram>
 
 <histogram name="Extensions.ContentVerification.VerifyJobResultMV2"
-    enum="ContentVerifyJobResult" expires_after="2025-08-10">
+    enum="ContentVerifyJobResult" expires_after="2025-11-16">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
@@ -762,7 +762,7 @@
 </histogram>
 
 <histogram name="Extensions.ContentVerification.VerifyJobResultMV3"
-    enum="ContentVerifyJobResult" expires_after="2025-08-10">
+    enum="ContentVerifyJobResult" expires_after="2025-11-16">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
@@ -2680,7 +2680,7 @@
 </histogram>
 
 <histogram name="Extensions.Functions.ExtensionMV3Calls"
-    enum="ExtensionFunctions" expires_after="2025-09-14">
+    enum="ExtensionFunctions" expires_after="2025-11-16">
   <owner>tjudkins@chromium.org</owner>
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
@@ -3832,7 +3832,7 @@
 </histogram>
 
 <histogram name="Extensions.LoadType2" enum="ExtensionType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
@@ -4818,7 +4818,7 @@
 </histogram>
 
 <histogram name="Extensions.ServiceWorkerBackground.StartWorkerStatus"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>jlulejian@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
@@ -5116,7 +5116,7 @@
 </histogram>
 
 <histogram name="Extensions.Toolbar.InvocationSource"
-    enum="ExtensionActionInvocationSource" expires_after="2025-09-14">
+    enum="ExtensionActionInvocationSource" expires_after="2025-11-16">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/facilitated_payments/histograms.xml b/tools/metrics/histograms/metadata/facilitated_payments/histograms.xml
index 9fc043b..651b8836 100644
--- a/tools/metrics/histograms/metadata/facilitated_payments/histograms.xml
+++ b/tools/metrics/histograms/metadata/facilitated_payments/histograms.xml
@@ -323,7 +323,7 @@
 </histogram>
 
 <histogram name="FacilitatedPayments.Pix.FopSelectorShown.LatencyAfterCopy"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>siashah@google.com</owner>
   <owner>vishwasuppoor@google.com</owner>
   <owner>rouslan@google.com</owner>
@@ -536,7 +536,7 @@
 
 <histogram
     name="FacilitatedPayments.{FacilitatedPaymentsType}.IsApiAvailable.{Result}.Latency"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>siashah@google.com</owner>
   <owner>vishwasuppoor@google.com</owner>
   <owner>rouslan@google.com</owner>
@@ -572,7 +572,7 @@
 </histogram>
 
 <histogram name="FacilitatedPayments.{FacilitatedPaymentsType}.UiScreenShown"
-    enum="FacilitatedPayments.UiScreen" expires_after="2025-09-14">
+    enum="FacilitatedPayments.UiScreen" expires_after="2025-11-16">
   <owner>siashah@google.com</owner>
   <owner>vishwasuppoor@google.com</owner>
   <owner>rouslan@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/families/histograms.xml b/tools/metrics/histograms/metadata/families/histograms.xml
index 93aa62f..345e0715 100644
--- a/tools/metrics/histograms/metadata/families/histograms.xml
+++ b/tools/metrics/histograms/metadata/families/histograms.xml
@@ -392,7 +392,7 @@
 </histogram>
 
 <histogram name="FamilyLinkUser.LocalWebApprovalCompleteRequestTotalDuration"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>anthie@google.com</owner>
   <owner>ljjlee@google.com</owner>
   <owner>chrome-kids-eng@google.com</owner>
@@ -417,7 +417,7 @@
 </histogram>
 
 <histogram name="FamilyLinkUser.LocalWebApprovalOutcome"
-    enum="FamilyLinkUserLocalWebApprovalOutcome" expires_after="2025-09-14">
+    enum="FamilyLinkUserLocalWebApprovalOutcome" expires_after="2025-11-16">
   <owner>anthie@google.com</owner>
   <owner>ljjlee@google.com</owner>
   <owner>chrome-kids-eng@google.com</owner>
@@ -429,7 +429,7 @@
 </histogram>
 
 <histogram name="FamilyLinkUser.LocalWebApprovalResult"
-    enum="FamilyLinkUserLocalWebApprovalResult" expires_after="2025-09-14">
+    enum="FamilyLinkUserLocalWebApprovalResult" expires_after="2025-11-16">
   <owner>agawronska@chromium.org</owner>
   <owner>cros-families-eng@google.com</owner>
   <owner>chrome-kids-eng@google.com</owner>
@@ -1128,7 +1128,7 @@
 </histogram>
 
 <histogram name="{RequestType}.AuthError" enum="GoogleServiceAuthError"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ljjlee@google.com</owner>
   <owner>chrome-kids-eng@google.com</owner>
   <summary>
@@ -1140,7 +1140,7 @@
 </histogram>
 
 <histogram name="{RequestType}.HttpStatusOrNetError"
-    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2025-09-14">
+    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2025-11-16">
   <owner>tju@google.com</owner>
   <owner>chrome-kids-eng@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
index 9df7665..27a6b6a 100644
--- a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
+++ b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
@@ -713,7 +713,7 @@
 </histogram>
 
 <histogram name="InProductHelp.Db.TotalEvents" units="events"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>nyquist@chromium.org</owner>
   <summary>
     Records the total number of event records in the database for in-product
@@ -750,7 +750,7 @@
 </histogram>
 
 <histogram name="InProductHelp.NotifyEventReadyState.{IPHFeature}"
-    enum="BooleanSuccess" expires_after="2025-09-14">
+    enum="BooleanSuccess" expires_after="2025-11-16">
   <owner>nyquist@chromium.org</owner>
   <summary>
     Records if the model is ready when in-product help event happens for
@@ -760,7 +760,7 @@
 </histogram>
 
 <histogram name="InProductHelp.ShouldTriggerHelpUI.{IPHFeature}"
-    enum="TriggerHelpUIResult" expires_after="2025-09-14">
+    enum="TriggerHelpUIResult" expires_after="2025-11-16">
   <owner>nyquist@chromium.org</owner>
   <summary>
     Records if in-product help for {IPHFeature} is shown to the user, and the
diff --git a/tools/metrics/histograms/metadata/file/histograms.xml b/tools/metrics/histograms/metadata/file/histograms.xml
index 16cb430..83927d97 100644
--- a/tools/metrics/histograms/metadata/file/histograms.xml
+++ b/tools/metrics/histograms/metadata/file/histograms.xml
@@ -1560,7 +1560,7 @@
 </histogram>
 
 <histogram name="FileBrowser.Search.RootType" enum="SearchRootType"
-    expires_after="2025-08-31">
+    expires_after="2025-11-16">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/gcm/histograms.xml b/tools/metrics/histograms/metadata/gcm/histograms.xml
index ade9406f..afea8ac 100644
--- a/tools/metrics/histograms/metadata/gcm/histograms.xml
+++ b/tools/metrics/histograms/metadata/gcm/histograms.xml
@@ -102,7 +102,7 @@
 </histogram>
 
 <histogram name="GCM.DeliveredToAppHandler{AppHandler}" enum="BooleanDelivered"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>peter@chromium.org</owner>
   <owner>rushans@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/geolocation/histograms.xml b/tools/metrics/histograms/metadata/geolocation/histograms.xml
index 2a14c767..46a81a5e 100644
--- a/tools/metrics/histograms/metadata/geolocation/histograms.xml
+++ b/tools/metrics/histograms/metadata/geolocation/histograms.xml
@@ -272,7 +272,7 @@
 </histogram>
 
 <histogram name="Geolocation.NetworkLocationRequest.ResponseCode"
-    enum="HttpResponseCode" expires_after="2025-09-14">
+    enum="HttpResponseCode" expires_after="2025-11-16">
   <owner>mattreynolds@chromium.org</owner>
   <owner>device-dev@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/gpu/histograms.xml b/tools/metrics/histograms/metadata/gpu/histograms.xml
index 4615812..e70b3a5 100644
--- a/tools/metrics/histograms/metadata/gpu/histograms.xml
+++ b/tools/metrics/histograms/metadata/gpu/histograms.xml
@@ -384,7 +384,7 @@
 </histogram>
 
 <histogram name="GPU.ANGLE.MetalShaderCompilationTimeUs" units="microseconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>geofflang@chromium.org</owner>
   <owner>angle-team@google.com</owner>
   <summary>
@@ -427,7 +427,7 @@
 </histogram>
 
 <histogram name="GPU.BlocklistFeatureTestResults.{GPUBlocklistPerFeature}"
-    enum="GPUBlocklistFeatureTestResults" expires_after="2025-09-14">
+    enum="GPUBlocklistFeatureTestResults" expires_after="2025-11-16">
   <owner>vmiura@chromium.org</owner>
   <owner>kylechar@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
@@ -506,7 +506,7 @@
 </histogram>
 
 <histogram name="GPU.D3D11FeatureLevel" enum="D3D11FeatureLevel"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>zmo@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
   <summary>
@@ -516,7 +516,7 @@
 </histogram>
 
 <histogram name="GPU.D3D12FeatureLevel" enum="D3D12FeatureLevel"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>magchen@chromium.org</owner>
   <owner>zmo@chromium.org</owner>
   <summary>
@@ -526,7 +526,7 @@
 </histogram>
 
 <histogram name="GPU.D3D12HighestShaderModel2" enum="D3DShaderModel"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>magchen@chromium.org</owner>
   <owner>zmo@chromium.org</owner>
   <owner>amaiorano@google.com</owner>
@@ -586,7 +586,7 @@
 </histogram>
 
 <histogram name="GPU.DirectComposition.DCLayerResult.Texture"
-    enum="DCLayerResult" expires_after="2025-09-14">
+    enum="DCLayerResult" expires_after="2025-11-16">
   <owner>sunnyps@chromium.org</owner>
   <owner>zmo@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
@@ -731,7 +731,7 @@
 </histogram>
 
 <histogram name="GPU.EnsureWorkVisibleDuration" units="microseconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>alemate@chromium.org</owner>
   <owner>magchen@chromium.org</owner>
   <owner>oshima@chromium.org</owner>
@@ -750,7 +750,7 @@
 </histogram>
 
 <histogram name="GPU.EnsureWorkVisibleDurationLowRes" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>alemate@chromium.org</owner>
   <owner>magchen@chromium.org</owner>
   <owner>oshima@chromium.org</owner>
@@ -782,7 +782,7 @@
 </histogram>
 
 <histogram name="GPU.EstablishGpuChannelSyncTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>cduvall@chromium.org</owner>
   <owner>jam@chromium.org</owner>
   <summary>
@@ -859,7 +859,7 @@
 </histogram>
 
 <histogram name="GPU.GPUInitializationTime.V4" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>magchen@chromium.org</owner>
   <owner>zmo@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
@@ -921,7 +921,7 @@
 </histogram>
 
 <histogram name="Gpu.Graphite.GraphiteImageProviderAccessHitInCache"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>blundell@chromium.org</owner>
   <owner>sunnyps@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
@@ -1052,7 +1052,7 @@
 </histogram>
 
 <histogram name="GPU.IOSurface.CreationTimeUs" units="microseconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>sunnyps@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
   <summary>
@@ -1130,7 +1130,7 @@
   </summary>
 </histogram>
 
-<histogram name="GPU.Output.HDR" enum="Boolean" expires_after="2025-09-14">
+<histogram name="GPU.Output.HDR" enum="Boolean" expires_after="2025-11-16">
   <owner>hubbe@chromium.org</owner>
   <owner>cassew@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
@@ -1422,7 +1422,7 @@
 </histogram>
 
 <histogram name="GPU.{GraphiteDawnOrWebGPU}.Create{Module}Success"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>enga@chromium.org</owner>
   <owner>mdb.webgpu-dev-team@google.com</owner>
   <summary>
@@ -1434,7 +1434,7 @@
 </histogram>
 
 <histogram name="GPU.{GraphiteDawnOrWebGPU}.Create{Module}US"
-    units="microseconds" expires_after="2025-09-14">
+    units="microseconds" expires_after="2025-11-16">
   <owner>enga@chromium.org</owner>
   <owner>mdb.webgpu-dev-team@google.com</owner>
   <summary>
@@ -1447,7 +1447,7 @@
 </histogram>
 
 <histogram name="GPU.{GraphiteDawnOrWebGPU}.HasGpuAdapter" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>cduvall@chromium.org</owner>
   <owner>mdb.webgpu-dev-team@google.com</owner>
   <summary>
@@ -1812,7 +1812,7 @@
 </histogram>
 
 <histogram name="Viz.DisplayCompositor.OverlayStrategy"
-    enum="OverlayStrategies" expires_after="2025-09-14">
+    enum="OverlayStrategies" expires_after="2025-11-16">
   <owner>kylechar@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/history/histograms.xml b/tools/metrics/histograms/metadata/history/histograms.xml
index 4b7eb7db..b28c3c7c 100644
--- a/tools/metrics/histograms/metadata/history/histograms.xml
+++ b/tools/metrics/histograms/metadata/history/histograms.xml
@@ -94,7 +94,7 @@
 </histogram>
 
 <histogram name="History.ClearBrowsingData.Duration.ChromeTask.{Task}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>dullweber@chromium.org</owner>
   <owner>msramek@chromium.org</owner>
   <component>1456716</component>
@@ -222,7 +222,7 @@
 </histogram>
 
 <histogram name="History.ClearBrowsingData.Duration.Task.{Task}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dullweber@chromium.org</owner>
   <owner>msramek@chromium.org</owner>
   <component>1456716</component>
@@ -431,7 +431,7 @@
 </histogram>
 
 <histogram name="History.Clusters.Actions.InitialState"
-    enum="HistoryClustersInitialState" expires_after="2025-09-14">
+    enum="HistoryClustersInitialState" expires_after="2025-11-16">
   <owner>mcrouse@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>1457319</component>
@@ -456,7 +456,7 @@
 </histogram>
 
 <histogram name="History.Clusters.Actions.NumQueries"
-    units="number queries made" expires_after="2025-09-14">
+    units="number queries made" expires_after="2025-11-16">
   <owner>mcrouse@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>1457319</component>
@@ -1555,7 +1555,7 @@
 </histogram>
 
 <histogram name="History.DomainCount28Day_V3" units="domains"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mpearson@chromium.org</owner>
   <owner>mjzhang@chromium.org</owner>
   <owner>chrome-analysis-team@google.com</owner>
@@ -1633,7 +1633,7 @@
 </histogram>
 
 <histogram name="History.DomainCount7Day_V3" units="domains"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mpearson@chromium.org</owner>
   <owner>mjzhang@chromium.org</owner>
   <owner>chrome-analysis-team@google.com</owner>
@@ -2549,7 +2549,7 @@
 </histogram>
 
 <histogram name="History.ForeignVisitsLegacy" units="visits"
-    expires_after="2025-09-17">
+    expires_after="2025-11-16">
   <owner>treib@chromium.org</owner>
   <component>1456716</component>
   <summary>
@@ -2562,7 +2562,7 @@
 </histogram>
 
 <histogram name="History.ForeignVisitsNotRemapped" units="visits"
-    expires_after="2025-09-17">
+    expires_after="2025-11-16">
   <owner>treib@chromium.org</owner>
   <component>1456716</component>
   <summary>
@@ -2575,7 +2575,7 @@
 </histogram>
 
 <histogram name="History.ForeignVisitsRemappableFrom" units="visits"
-    expires_after="2025-09-17">
+    expires_after="2025-11-16">
   <owner>treib@chromium.org</owner>
   <component>1456716</component>
   <summary>
@@ -2588,7 +2588,7 @@
 </histogram>
 
 <histogram name="History.ForeignVisitsRemappableOpener" units="visits"
-    expires_after="2025-09-17">
+    expires_after="2025-11-16">
   <owner>treib@chromium.org</owner>
   <component>1456716</component>
   <summary>
@@ -2601,7 +2601,7 @@
 </histogram>
 
 <histogram name="History.ForeignVisitsTotal" units="visits"
-    expires_after="2025-09-17">
+    expires_after="2025-11-16">
   <owner>treib@chromium.org</owner>
   <component>1456716</component>
   <summary>
@@ -2612,7 +2612,7 @@
 </histogram>
 
 <histogram name="History.HistoryPageView" enum="HistoryPageView"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>calamity@chromium.org</owner>
   <owner>src/chrome/browser/resources/history/OWNERS</owner>
   <component>1456716</component>
@@ -2924,7 +2924,7 @@
 </histogram>
 
 <histogram name="History.VisitedLinkTableCount" units="VisitedLinks"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kyraseevers@chromium.org</owner>
   <owner>janiceliu@chromium.org</owner>
   <component>1456589</component>
@@ -2935,7 +2935,7 @@
 </histogram>
 
 <histogram name="History.VisitTableCount" units="visits"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mpearson@chromium.org</owner>
   <owner>sky@chromium.org</owner>
   <component>1456716</component>
diff --git a/tools/metrics/histograms/metadata/image/histograms.xml b/tools/metrics/histograms/metadata/image/histograms.xml
index 928954e..ad25c89 100644
--- a/tools/metrics/histograms/metadata/image/histograms.xml
+++ b/tools/metrics/histograms/metadata/image/histograms.xml
@@ -416,7 +416,7 @@
 </histogram>
 
 <histogram name="ImageDecoder.Png.UiGfxIntoSkBitmap" units="microseconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>lukasza@chromium.org</owner>
   <owner>chrome-rust-experiments@google.com</owner>
   <summary>
@@ -434,7 +434,7 @@
 </histogram>
 
 <histogram name="ImageDecoder.Png.UiGfxIntoVector" units="microseconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>lukasza@chromium.org</owner>
   <owner>chrome-rust-experiments@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/input/histograms.xml b/tools/metrics/histograms/metadata/input/histograms.xml
index 8230cdc..a797c6f 100644
--- a/tools/metrics/histograms/metadata/input/histograms.xml
+++ b/tools/metrics/histograms/metadata/input/histograms.xml
@@ -2004,7 +2004,7 @@
 </histogram>
 
 <histogram name="InputMethod.TouchSelection.DragType"
-    enum="TouchSelectionDragType" expires_after="2025-09-14">
+    enum="TouchSelectionDragType" expires_after="2025-11-16">
   <owner>michellegc@google.com</owner>
   <owner>essential-inputs-team@google.com</owner>
   <summary>
@@ -2014,7 +2014,7 @@
 </histogram>
 
 <histogram name="InputMethod.TouchSelection.MenuAction"
-    enum="TouchSelectionMenuAction" expires_after="2025-09-14">
+    enum="TouchSelectionMenuAction" expires_after="2025-11-16">
   <owner>michellegc@google.com</owner>
   <owner>essential-inputs-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/installer/histograms.xml b/tools/metrics/histograms/metadata/installer/histograms.xml
index 504c61b..6abdd63 100644
--- a/tools/metrics/histograms/metadata/installer/histograms.xml
+++ b/tools/metrics/histograms/metadata/installer/histograms.xml
@@ -23,7 +23,7 @@
 <histograms>
 
 <histogram name="Installer.Postinstall.BiosType" enum="ChromeOSBiosType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>tbrandston@google.com</owner>
   <owner>chromeos-flex-eng@google.com</owner>
   <summary>
@@ -40,7 +40,7 @@
 </histogram>
 
 <histogram name="Installer.Postinstall.EfiBootEntryCount" units="entries"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>tbrandston@google.com</owner>
   <owner>chromeos-flex-eng@google.com</owner>
   <summary>
@@ -58,7 +58,7 @@
 </histogram>
 
 <histogram name="Installer.Postinstall.EfiBootEntryFailedLoad" units="entries"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>tbrandston@google.com</owner>
   <owner>chromeos-flex-eng@google.com</owner>
   <summary>
@@ -93,7 +93,7 @@
 </histogram>
 
 <histogram name="Installer.Postinstall.ESPMountRetries" units="retries"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>tbrandston@google.com</owner>
   <owner>chromeos-flex-eng@google.com</owner>
   <summary>
@@ -103,7 +103,7 @@
 </histogram>
 
 <histogram name="Installer.Postinstall.ManagedEfiBootEntryCount"
-    units="entries" expires_after="2025-09-14">
+    units="entries" expires_after="2025-11-16">
   <owner>tbrandston@google.com</owner>
   <owner>chromeos-flex-eng@google.com</owner>
   <summary>
@@ -148,7 +148,7 @@
 </histogram>
 
 <histogram name="Installer.PowerwashCount" units="powerwashes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kimjae@chromium.org</owner>
   <owner>chromeos-core-services@chromium.org</owner>
   <summary>
@@ -189,7 +189,7 @@
 </histogram>
 
 <histogram name="Installer.Recovery.Reason" enum="ChromeOSRecoveryReason"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kimjae@chromium.org</owner>
   <owner>chromeos-core-services@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/interstitial/histograms.xml b/tools/metrics/histograms/metadata/interstitial/histograms.xml
index e58f10e0..d87edc2 100644
--- a/tools/metrics/histograms/metadata/interstitial/histograms.xml
+++ b/tools/metrics/histograms/metadata/interstitial/histograms.xml
@@ -78,7 +78,7 @@
 </variants>
 
 <histogram name="interstitial.captive_portal"
-    enum="CaptivePortalBlockingPageEvent" expires_after="2025-09-14">
+    enum="CaptivePortalBlockingPageEvent" expires_after="2025-11-16">
   <owner>meacer@chromium.org</owner>
   <owner>michaeldo@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/ios/histograms.xml b/tools/metrics/histograms/metadata/ios/histograms.xml
index 83a7d527..f9d8f486 100644
--- a/tools/metrics/histograms/metadata/ios/histograms.xml
+++ b/tools/metrics/histograms/metadata/ios/histograms.xml
@@ -152,7 +152,7 @@
 </histogram>
 
 <histogram name="IOS.Annotations.Percentage" units="%"
-    expires_after="2025-09-12">
+    expires_after="2025-11-16">
   <owner>olivierrobin@chromium.org</owner>
   <owner>bling-squid-squad@google.com</owner>
   <summary>
@@ -173,7 +173,7 @@
 </histogram>
 
 <histogram name="IOS.Annotations.{Action}.Type" enum="IOSAnnotationType"
-    expires_after="2025-09-12">
+    expires_after="2025-11-16">
   <owner>olivierrobin@chromium.org</owner>
   <owner>bling-squid-squad@google.com</owner>
   <summary>The type of an annotation that is {Action}.</summary>
@@ -2496,7 +2496,7 @@
 </histogram>
 
 <histogram name="IOS.MagicStack.Module.Click" enum="IOSMagicStackModuleType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>thegreenfrog@chromium.org</owner>
   <owner>scottyoder@google.com</owner>
   <summary>
@@ -2571,7 +2571,7 @@
 </histogram>
 
 <histogram name="IOS.MagicStack.Module.Click.Shortcuts" units="index"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>thegreenfrog@chromium.org</owner>
   <owner>bling-get-set-up@google.com</owner>
   <summary>
@@ -2580,7 +2580,7 @@
 </histogram>
 
 <histogram name="IOS.MagicStack.Module.Click.TabResumption" units="index"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>thegreenfrog@chromium.org</owner>
   <owner>bling-get-set-up@google.com</owner>
   <summary>
@@ -2606,7 +2606,7 @@
 </histogram>
 
 <histogram name="IOS.MagicStack.Module.TopImpression"
-    enum="IOSMagicStackModuleType" expires_after="2025-09-14">
+    enum="IOSMagicStackModuleType" expires_after="2025-11-16">
   <owner>thegreenfrog@chromium.org</owner>
   <owner>scottyoder@google.com</owner>
   <summary>
@@ -2783,7 +2783,7 @@
 </histogram>
 
 <histogram name="IOS.MetricKit.{MXVersion}ApplicationResumeTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>justincohen@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>
@@ -2805,7 +2805,7 @@
 </histogram>
 
 <histogram name="IOS.MetricKit.{MXVersion}AverageSuspendedMemory" units="MB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>justincohen@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>
@@ -2981,7 +2981,7 @@
 </histogram>
 
 <histogram name="IOS.MetricKit.{MXVersion}ForegroundTimePerDay" units="s"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>justincohen@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>
@@ -3008,7 +3008,7 @@
 </histogram>
 
 <histogram name="IOS.MetricKit.{MXVersion}OptimizedTimeToFirstDraw" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>justincohen@chromium.org</owner>
   <owner>bling-fundamentals@google.com</owner>
   <summary>
@@ -3034,7 +3034,7 @@
 </histogram>
 
 <histogram name="IOS.MetricKit.{MXVersion}PeakMemoryUsage" units="MB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>justincohen@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>
@@ -3062,7 +3062,7 @@
 </histogram>
 
 <histogram name="IOS.MetricKit.{MXVersion}TimeToFirstDraw" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>justincohen@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>
@@ -3114,7 +3114,7 @@
 </histogram>
 
 <histogram name="IOS.MultiWindow.ConnectedScenesCount" units="scenes"
-    expires_after="2025-07-06">
+    expires_after="2025-11-16">
   <owner>fedegermi@google.com</owner>
   <owner>marq@chromium.org</owner>
   <summary>Records the number of connected scenes.</summary>
@@ -3169,7 +3169,7 @@
 </histogram>
 
 <histogram name="IOS.Notifications.SafetyCheck.Dismissed"
-    enum="IOSSafetyCheckNotificationType" expires_after="2025-09-17">
+    enum="IOSSafetyCheckNotificationType" expires_after="2025-11-16">
   <owner>bwwilliams@google.com</owner>
   <owner>scottyoder@google.com</owner>
   <owner>bling-get-set-up@google.com</owner>
@@ -3202,7 +3202,7 @@
 </histogram>
 
 <histogram name="IOS.Notifications.SafetyCheck.Requested"
-    enum="IOSSafetyCheckNotificationType" expires_after="2025-09-17">
+    enum="IOSSafetyCheckNotificationType" expires_after="2025-11-16">
   <owner>bwwilliams@google.com</owner>
   <owner>scottyoder@google.com</owner>
   <owner>bling-get-set-up@google.com</owner>
@@ -3214,7 +3214,7 @@
 </histogram>
 
 <histogram name="IOS.Notifications.SafetyCheck.Triggered"
-    enum="IOSSafetyCheckNotificationType" expires_after="2025-09-17">
+    enum="IOSSafetyCheckNotificationType" expires_after="2025-11-16">
   <owner>bwwilliams@google.com</owner>
   <owner>scottyoder@google.com</owner>
   <owner>bling-get-set-up@google.com</owner>
@@ -3248,7 +3248,7 @@
 </histogram>
 
 <histogram name="IOS.Notifications.Tips.ClientStatus.Enabled.ByProvider"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>hiramahmood@google.com</owner>
   <owner>scottyoder@google.com</owner>
   <summary>
@@ -3272,7 +3272,7 @@
 </histogram>
 
 <histogram name="IOS.Notifications.Tips.UserType"
-    enum="IOSTipsNotificationUserType" expires_after="2025-09-14">
+    enum="IOSTipsNotificationUserType" expires_after="2025-11-16">
   <owner>scottyoder@google.com</owner>
   <owner>hiramahmood@google.com</owner>
   <summary>
@@ -3351,7 +3351,7 @@
 </histogram>
 
 <histogram name="IOS.NTP.OverscrollAction" enum="IOSNTPOverscrollAction"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>guiperez@google.com</owner>
   <owner>bling-team@google.com</owner>
   <summary>
@@ -3529,7 +3529,7 @@
 </histogram>
 
 <histogram name="IOS.OverflowMenu.ActionType" enum="IOSOverflowMenuActionType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>rkgibson@google.com</owner>
   <owner>bling-team@google.com</owner>
   <summary>The type of action the user took in the overflow/tools menu</summary>
@@ -3550,7 +3550,7 @@
 </histogram>
 
 <histogram name="IOS.OverflowMenu.Customization.ActionsCustomized"
-    units="bitfield value" expires_after="2025-08-24">
+    units="bitfield value" expires_after="2025-11-16">
   <owner>rkgibson@google.com</owner>
   <owner>bling-mony-pod@google.com</owner>
   <summary>
@@ -3561,7 +3561,7 @@
 </histogram>
 
 <histogram name="IOS.OverflowMenu.Customization.ActionsReordered.FirstPosition"
-    enum="IOSOverflowMenuAction" expires_after="2025-08-24">
+    enum="IOSOverflowMenuAction" expires_after="2025-11-16">
   <owner>rkgibson@google.com</owner>
   <owner>bling-mony-pod@google.com</owner>
   <summary>The action in the first position after reordering the menu.</summary>
@@ -3579,7 +3579,7 @@
 
 <histogram
     name="IOS.OverflowMenu.Customization.ActionsReordered.SecondPosition"
-    enum="IOSOverflowMenuAction" expires_after="2025-08-24">
+    enum="IOSOverflowMenuAction" expires_after="2025-11-16">
   <owner>rkgibson@google.com</owner>
   <owner>bling-mony-pod@google.com</owner>
   <summary>
@@ -3588,7 +3588,7 @@
 </histogram>
 
 <histogram name="IOS.OverflowMenu.Customization.ActionsReordered.ThirdPosition"
-    enum="IOSOverflowMenuAction" expires_after="2025-08-24">
+    enum="IOSOverflowMenuAction" expires_after="2025-11-16">
   <owner>rkgibson@google.com</owner>
   <owner>bling-mony-pod@google.com</owner>
   <summary>
@@ -3680,7 +3680,7 @@
 </histogram>
 
 <histogram name="IOS.OverflowMenu.OverflowMenuVisited" units="bitfield value"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>rkgibson@google.com</owner>
   <owner>bling-mony-pod@google.com</owner>
   <summary>
@@ -3699,14 +3699,14 @@
 </histogram>
 
 <histogram name="IOS.OverflowMenu.TimeOpen" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>rkgibson@google.com</owner>
   <owner>bling-team@google.com</owner>
   <summary>The amount of time the overflow/tools menu is open.</summary>
 </histogram>
 
 <histogram name="IOS.OverflowMenu.TimeOpen.ActionChosen" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>rkgibson@google.com</owner>
   <owner>bling-mony-pod@google.com</owner>
   <summary>
@@ -3811,7 +3811,7 @@
 </histogram>
 
 <histogram name="IOS.PasswordBottomSheet.Activated" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>vincb@google.com</owner>
   <owner>tmartino@google.com</owner>
   <owner>bling-transactions@google.com</owner>
@@ -3823,7 +3823,7 @@
 </histogram>
 
 <histogram name="IOS.PasswordBottomSheet.ExitReason"
-    enum="PasswordSuggestionBottomSheetExitReason" expires_after="2025-09-14">
+    enum="PasswordSuggestionBottomSheetExitReason" expires_after="2025-11-16">
   <owner>sugoi@chromium.org</owner>
   <owner>tmartino@chromium.org</owner>
   <summary>
@@ -3867,7 +3867,7 @@
 </histogram>
 
 <histogram name="IOS.PasswordManager.WidgetPromo.Action"
-    enum="PromoWithInstructionsAction" expires_after="2025-09-07">
+    enum="PromoWithInstructionsAction" expires_after="2025-11-16">
   <owner>noemies@google.com</owner>
   <owner>bling-transactions@google.com</owner>
   <summary>
@@ -4073,7 +4073,7 @@
 </histogram>
 
 <histogram name="IOS.PromosManager.EligiblePromosInQueueCount" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>gayane@google.com</owner>
   <owner>bling-mony-pod@google.com</owner>
   <summary>
@@ -4084,7 +4084,7 @@
 </histogram>
 
 <histogram name="IOS.PromosManager.Promo" enum="IOSPromosManagerPromo"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bwwilliams@google.com</owner>
   <owner>rkgibson@google.com</owner>
   <owner>huitingyu@google.com</owner>
@@ -4121,7 +4121,7 @@
 </histogram>
 
 <histogram name="IOS.PromosManager.Promo.Type" enum="IOSPromosManagerPromoType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bwwilliams@google.com</owner>
   <owner>rkgibson@google.com</owner>
   <owner>huitingyu@google.com</owner>
@@ -4169,7 +4169,7 @@
 </histogram>
 
 <histogram name="IOS.PushNotification.Client.Disabled"
-    enum="PushNotificationClientId" expires_after="2025-09-14">
+    enum="PushNotificationClientId" expires_after="2025-11-16">
   <owner>scottyoder@google.com</owner>
   <owner>bling-get-set-up@google.com</owner>
   <summary>
@@ -4178,7 +4178,7 @@
 </histogram>
 
 <histogram name="IOS.PushNotification.Client.Enabled"
-    enum="PushNotificationClientId" expires_after="2025-09-14">
+    enum="PushNotificationClientId" expires_after="2025-11-16">
   <owner>scottyoder@google.com</owner>
   <owner>bling-get-set-up@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/lens/histograms.xml b/tools/metrics/histograms/metadata/lens/histograms.xml
index 245bb0a..0dade76 100644
--- a/tools/metrics/histograms/metadata/lens/histograms.xml
+++ b/tools/metrics/histograms/metadata/lens/histograms.xml
@@ -510,7 +510,7 @@
 </histogram>
 
 <histogram name="Lens.Overlay.GeneratedTab" enum="LensOverlayNewTabSource"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>christianxu@chromium.org</owner>
   <owner>lens-chrome@google.com</owner>
   <summary>
@@ -530,7 +530,7 @@
 </histogram>
 
 <histogram name="Lens.Overlay.InvocationResultedInSearch" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jdonnelly@chromium.org</owner>
   <owner>lens-chrome@google.com</owner>
   <summary>
@@ -568,7 +568,7 @@
 </histogram>
 
 <histogram name="Lens.Overlay.OcrDomSimilarity" units="%"
-    expires_after="2025-09-12">
+    expires_after="2025-11-16">
   <owner>mercerd@chromium.org</owner>
   <owner>lens-chrome@google.com</owner>
   <summary>
@@ -698,7 +698,7 @@
 </histogram>
 
 <histogram name="Lens.Overlay.Shown" enum="BooleanEnabled"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>erikchen@chromium.org</owner>
   <owner>mercerd@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/login/histograms.xml b/tools/metrics/histograms/metadata/login/histograms.xml
index f6e7d50a..68592da 100644
--- a/tools/metrics/histograms/metadata/login/histograms.xml
+++ b/tools/metrics/histograms/metadata/login/histograms.xml
@@ -183,7 +183,7 @@
 </histogram>
 
 <histogram name="Login.NumberOfUsersOnLoginScreen" units="units"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mslus@chromium.org</owner>
   <owner>chromeos-commercial-identity@google.com</owner>
   <summary>
@@ -288,7 +288,7 @@
 </histogram>
 
 <histogram name="Login.SessionExitType" enum="LoginSessionExitType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>iby@chromium.org</owner>
   <summary>
     Tracks whether a ChromeOS user was logged out because Chrome repeatedly
diff --git a/tools/metrics/histograms/metadata/magic_stack/histograms.xml b/tools/metrics/histograms/metadata/magic_stack/histograms.xml
index 4e747d6f..5251975 100644
--- a/tools/metrics/histograms/metadata/magic_stack/histograms.xml
+++ b/tools/metrics/histograms/metadata/magic_stack/histograms.xml
@@ -319,7 +319,7 @@
 
 <histogram name="MagicStack.Clank.TabResumption.ModuleNotShownReason"
     enum="MagicStack.Clank.TabResumption.ModuleNotShownReason"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>huangs@google.com</owner>
   <owner>hanxi@google.com</owner>
   <summary>
@@ -334,7 +334,7 @@
 
 <histogram name="MagicStack.Clank.TabResumption.ModuleShowConfig"
     enum="MagicStack.Clank.TabResumption.ModuleShowConfig"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>huangs@google.com</owner>
   <owner>hanxi@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index 4ed90bb..cf3fd4f 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -182,7 +182,7 @@
 </histogram>
 
 <histogram name="Cast.Channel.LaunchSession.Flags" enum="CastChannelFlag"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mfoltz@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
@@ -463,7 +463,7 @@
 </histogram>
 
 <histogram name="Media.AImageReaderGLOwner.HasFence" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>vasilyt@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
@@ -985,7 +985,7 @@
 </histogram>
 
 <histogram name="Media.Audio.InputStartupSuccessMac{MacAudioInputVariants}"
-    enum="BooleanSuccess" expires_after="2025-09-14">
+    enum="BooleanSuccess" expires_after="2025-11-16">
   <owner>henrika@chromium.org</owner>
   <owner>webrtc-audio-uma@google.com</owner>
   <summary>
@@ -1036,7 +1036,7 @@
 </histogram>
 
 <histogram name="Media.Audio.Mac.HardwareLatency.{Direction}.{Component}"
-    units="misses" expires_after="2025-09-14">
+    units="misses" expires_after="2025-11-16">
   <owner>tguilbert@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
@@ -1330,7 +1330,7 @@
 </histogram>
 
 <histogram name="Media.Audio.Render.OutputDeviceAuthorizationTimedOut"
-    enum="BooleanTimedOut" expires_after="2025-09-14">
+    enum="BooleanTimedOut" expires_after="2025-11-16">
   <owner>guidou@chromium.org</owner>
   <owner>olka@chromium.org</owner>
   <owner>webrtc-audio-uma@google.com</owner>
@@ -1568,7 +1568,7 @@
 </histogram>
 
 <histogram name="Media.AudioCapturerAudioGlitches" enum="AudioGlitchResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>olka@chromium.org</owner>
   <owner>gustaf@chromium.org</owner>
   <owner>webrtc-audio-uma@google.com</owner>
@@ -1607,7 +1607,7 @@
 </histogram>
 
 <histogram name="Media.AudioCapturerMissedReadDeadline10sIntervals"
-    units="misses" expires_after="2025-09-14">
+    units="misses" expires_after="2025-11-16">
   <owner>fhernqvist@google.com</owner>
   <owner>olka@chromium.org</owner>
   <owner>webrtc-audio-uma@google.com</owner>
@@ -1715,7 +1715,7 @@
 </histogram>
 
 <histogram name="Media.AudioInputDevice.AudioServiceDelay" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>fhernqvist@google.com</owner>
   <owner>olka@chromium.org</owner>
   <owner>webrtc-audio-uma@google.com</owner>
@@ -1726,7 +1726,7 @@
 </histogram>
 
 <histogram name="Media.AudioInputDevice.AudioServiceGlitchCount{Duration}"
-    units="glitches" expires_after="2025-09-14">
+    units="glitches" expires_after="2025-11-16">
   <owner>fhernqvist@google.com</owner>
   <owner>olka@chromium.org</owner>
   <owner>webrtc-audio-uma@google.com</owner>
@@ -1740,7 +1740,7 @@
 </histogram>
 
 <histogram name="Media.AudioInputDevice.AudioServiceGlitchDuration{Duration}"
-    units="permille" expires_after="2025-09-14">
+    units="permille" expires_after="2025-11-16">
   <owner>fhernqvist@google.com</owner>
   <owner>olka@chromium.org</owner>
   <owner>webrtc-audio-uma@google.com</owner>
@@ -1754,7 +1754,7 @@
 </histogram>
 
 <histogram name="Media.AudioOutputController.CallbackError" enum="BooleanError"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>olka@chromium.org</owner>
   <owner>guidou@chromium.org</owner>
   <owner>webrtc-audio-uma@google.com</owner>
@@ -1834,7 +1834,7 @@
 </histogram>
 
 <histogram name="Media.AudioOutputDevice.AudioServiceDelay{LatencyTag}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>fhernqvist@google.com</owner>
   <owner>olka@chromium.org</owner>
   <owner>dalecurtis@chromium.org</owner>
@@ -1849,7 +1849,7 @@
 
 <histogram
     name="Media.AudioOutputDevice.AudioServiceGlitchCount{Duration}{LatencyTag}"
-    units="glitches" expires_after="2025-09-14">
+    units="glitches" expires_after="2025-11-16">
   <owner>fhernqvist@google.com</owner>
   <owner>olka@chromium.org</owner>
   <owner>dalecurtis@chromium.org</owner>
@@ -1867,7 +1867,7 @@
 
 <histogram
     name="Media.AudioOutputDevice.AudioServiceGlitchDuration{Duration}{LatencyTag}"
-    units="permille" expires_after="2025-09-14">
+    units="permille" expires_after="2025-11-16">
   <owner>fhernqvist@google.com</owner>
   <owner>olka@chromium.org</owner>
   <owner>dalecurtis@chromium.org</owner>
@@ -1885,7 +1885,7 @@
 
 <histogram name="Media.AudioOutputResampler.OpenLowLatencyStream2"
     enum="AudioOutputResamplerLowLatencyOpenStreamResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>olka@chromium.org</owner>
   <owner>armax@chromium.org</owner>
   <owner>guidou@chromium.org</owner>
@@ -1913,7 +1913,7 @@
 </histogram>
 
 <histogram name="Media.AudioRendererAudioGlitches2.{LatencyTag}"
-    enum="AudioGlitchResult" expires_after="2025-09-14">
+    enum="AudioGlitchResult" expires_after="2025-11-16">
   <owner>dalecurtis@chromium.org</owner>
   <owner>olka@chromium.org</owner>
   <owner>tguilbert@chromium.org</owner>
@@ -1949,7 +1949,7 @@
 
 <histogram
     name="Media.AudioRendererMissedDeadline3{Mixing}{Duration}{LatencyTag}"
-    units="misses" expires_after="2025-09-14">
+    units="misses" expires_after="2025-11-16">
   <owner>fhernqvist@google.com</owner>
   <owner>olka@chromium.org</owner>
   <owner>dalecurtis@chromium.org</owner>
@@ -2017,7 +2017,7 @@
 
 <histogram
     name="Media.AutoPictureInPicture.EnterPictureInPicture.AutomaticReason.{AutomaticReason}.PromptResultV2"
-    enum="MediaAutoPictureInPicturePromptResult" expires_after="2025-09-14">
+    enum="MediaAutoPictureInPicturePromptResult" expires_after="2025-11-16">
   <owner>bkeen@google.com</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
@@ -2038,7 +2038,7 @@
 
 <histogram
     name="Media.AutoPictureInPicture.EnterPictureInPicture.AutomaticReason.{AutomaticReason}.TotalTime"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>bkeen@google.com</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
@@ -2058,7 +2058,7 @@
 
 <histogram
     name="Media.AutoPictureInPicture.EnterPictureInPicture.AutomaticReason.{AutomaticReason}.TotalTimeForSession"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>bkeen@google.com</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
@@ -2106,7 +2106,7 @@
 
 <histogram
     name="Media.AutoPictureInPicture.EnterPictureInPicture.AutomaticReason.{AutomaticReason}.TotalTimeV2"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>bkeen@google.com</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
@@ -2457,7 +2457,7 @@
 </histogram>
 
 <histogram name="Media.DocumentPictureInPicture.CloseReason"
-    enum="DocumentPictureInPictureCloseReason" expires_after="2025-09-14">
+    enum="DocumentPictureInPictureCloseReason" expires_after="2025-11-16">
   <owner>steimel@chromium.org</owner>
   <owner>liberato@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
@@ -2522,7 +2522,7 @@
 </histogram>
 
 <histogram name="Media.DroppedFrameCount2.{RendererType}.{ClearOrEncrypted}"
-    units="units" expires_after="2025-09-14">
+    units="units" expires_after="2025-11-16">
   <owner>dalecurtis@chromium.org</owner>
   <owner>frankli@microsoft.com</owner>
   <owner>media-dev-uma@chromium.org</owner>
@@ -3733,7 +3733,7 @@
 </histogram>
 
 <histogram name="Media.GlobalMediaControls.EntryPoint"
-    enum="GlobalMediaControlsEntryPoint" expires_after="2025-09-14">
+    enum="GlobalMediaControlsEntryPoint" expires_after="2025-11-16">
   <owner>muyaoxu@google.com</owner>
   <owner>openscreen-eng@google.com</owner>
   <owner>media-dev-uma@chromium.org</owner>
@@ -3793,7 +3793,7 @@
 </histogram>
 
 <histogram name="Media.GlobalMediaControls.RepeatUsage" enum="BooleanIsRepeat"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>steimel@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
@@ -3804,7 +3804,7 @@
 </histogram>
 
 <histogram name="Media.GlobalMediaControls.UserActionFocus"
-    enum="BooleanFocused" expires_after="2025-09-14">
+    enum="BooleanFocused" expires_after="2025-11-16">
   <owner>steimel@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
@@ -3815,7 +3815,7 @@
 </histogram>
 
 <histogram name="Media.GPU.OutputFormatHardwareGmb" enum="OutputFormat"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>hitawala@chromium.org</owner>
   <owner>vasilyt@chromium.org</owner>
   <owner>shared-image-team@google.com</owner>
@@ -3827,7 +3827,7 @@
 </histogram>
 
 <histogram name="Media.GPU.OutputFormatSoftwareGmb" enum="OutputFormat"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>hitawala@chromium.org</owner>
   <owner>vasilyt@chromium.org</owner>
   <owner>shared-image-team@google.com</owner>
@@ -3884,7 +3884,7 @@
 </histogram>
 
 <histogram name="Media.GpuMemoryBufferVideoFramePool.UnsupportedFormat"
-    enum="VideoPixelFormatUnion" expires_after="2025-09-14">
+    enum="VideoPixelFormatUnion" expires_after="2025-11-16">
   <owner>magchen@chromium.org</owner>
   <owner>mcasas@chromium.org</owner>
   <summary>
@@ -3921,7 +3921,7 @@
 </histogram>
 
 <histogram name="Media.HardwareKeyPressed" enum="MediaHardwareKeyAction"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>steimel@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
@@ -3934,7 +3934,7 @@
 </histogram>
 
 <histogram name="Media.HasAcceleratedVideoDecode.{CodecType}"
-    enum="BooleanSupported" expires_after="2025-09-14">
+    enum="BooleanSupported" expires_after="2025-11-16">
   <owner>dalecurtis@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
@@ -4166,7 +4166,7 @@
 </histogram>
 
 <histogram name="Media.MeanTimeBetweenRebuffers{MediaRebufferingCategories}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>dalecurtis@chromium.org</owner>
   <summary>
     The total watch time (see Media.WatchTime) of a given playback divided by
@@ -5693,7 +5693,7 @@
 </histogram>
 
 <histogram name="Media.ScreenCaptureKit.FullscreenModuleMode"
-    enum="ScreenCaptureKitFullscreenModuleMode" expires_after="2025-09-14">
+    enum="ScreenCaptureKitFullscreenModuleMode" expires_after="2025-11-16">
   <owner>kron@chromium.org</owner>
   <owner>webrtc-video@google.com</owner>
   <summary>
@@ -5728,7 +5728,7 @@
 </histogram>
 
 <histogram name="Media.Session.EnterPictureInPicture"
-    enum="MediaSessionEnterPictureInPictureType" expires_after="2025-09-14">
+    enum="MediaSessionEnterPictureInPictureType" expires_after="2025-11-16">
   <owner>steimel@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
@@ -5929,7 +5929,7 @@
 </histogram>
 
 <histogram name="Media.Ui.GetDisplayMedia.BasicFlow.SourceCount.{Type}"
-    units="count" expires_after="2025-09-14">
+    units="count" expires_after="2025-11-16">
   <owner>eladalon@chromium.org</owner>
   <owner>tovep@chromium.org</owner>
   <summary>
@@ -6102,7 +6102,7 @@
 </histogram>
 
 <histogram name="Media.V4l2VideoDecoder.VidiocIoctlError"
-    enum="VidiocIoctlRequests" expires_after="2025-08-24">
+    enum="VidiocIoctlRequests" expires_after="2025-11-16">
   <owner>stevecho@chromium.org</owner>
   <owner>chromeos-gfx-video@google.com</owner>
   <summary>
@@ -6125,7 +6125,7 @@
 </histogram>
 
 <histogram name="Media.VaapiVideoDecoder.DecodeError" enum="BooleanError"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mcasas@chromium.org</owner>
   <owner>chromeos-gfx@chromium.org</owner>
   <summary>
@@ -7001,7 +7001,7 @@
 </histogram>
 
 <histogram name="Media.WatchTime{MediaWatchTimeCategories}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dalecurtis@chromium.org</owner>
   <summary>
     Watch time is defined as the amount of elapsed media time for audio+video
@@ -7218,7 +7218,7 @@
 </histogram>
 
 <histogram name="Media.WebMediaPlayerImpl.HLS{Variant}.MimeType"
-    enum="MimeTypeOfHlsManifest" expires_after="2025-09-14">
+    enum="MimeTypeOfHlsManifest" expires_after="2025-11-16">
   <owner>tmathmeyer@chromium.org</owner>
   <owner>lukasza@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
@@ -7795,7 +7795,7 @@
 </histogram>
 
 <histogram name="MediaRouter.CastStreaming.Start.Success" enum="MirrorType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>muyaoxu@google.com</owner>
   <owner>openscreen-eng@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/memory/histograms.xml b/tools/metrics/histograms/metadata/memory/histograms.xml
index e346fe6..cc5aa85 100644
--- a/tools/metrics/histograms/metadata/memory/histograms.xml
+++ b/tools/metrics/histograms/metadata/memory/histograms.xml
@@ -918,7 +918,7 @@
 </histogram>
 
 <histogram name="HeapProfiling.InProcess.TotalSampledMemory{Process}"
-    units="MB" expires_after="2025-09-14">
+    units="MB" expires_after="2025-11-16">
   <owner>joenotcharles@google.com</owner>
   <owner>etienneb@chromium.org</owner>
   <owner>chrome-memory@google.com</owner>
@@ -1259,7 +1259,7 @@
 </histogram>
 
 <histogram name="Memory.Experimental.AvailableMemoryPercent" units="%"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>anthonyvd@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -1459,7 +1459,7 @@
 </histogram>
 
 <histogram name="Memory.Experimental.MacAvailableMemoryPercentFreePageCache2"
-    units="%" expires_after="2025-09-14">
+    units="%" expires_after="2025-11-16">
   <owner>anthonyvd@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -1863,7 +1863,7 @@
 </histogram>
 
 <histogram name="Memory.GPU.PeakMemoryAllocationSource2.{Usage}.{Source}"
-    units="MB" expires_after="2025-09-14">
+    units="MB" expires_after="2025-11-16">
   <owner>jonross@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
   <summary>
@@ -1883,7 +1883,7 @@
 </histogram>
 
 <histogram name="Memory.GPU.PeakMemoryUsage2.{Usage}" units="MB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jonross@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
   <summary>
@@ -2083,7 +2083,7 @@
 </histogram>
 
 <histogram name="Memory.NetworkService.PrivateMemoryFootprint" units="MiB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mmenke@chromium.org</owner>
   <owner>morlovich@chromium.org</owner>
   <owner>erikchen@chromium.org</owner>
@@ -2139,14 +2139,14 @@
 </histogram>
 
 <histogram name="Memory.OOMKills.Count" units="kills"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>vovoy@google.com</owner>
   <owner>wvk@google.com</owner>
   <summary>Cumulative count of OOM kills in one user session.</summary>
 </histogram>
 
 <histogram name="Memory.OOMKills.Daily" units="kills"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>vovoy@google.com</owner>
   <owner>src/chromeos/ash/components/memory/OWNERS</owner>
   <summary>
@@ -2389,7 +2389,7 @@
 </histogram>
 
 <histogram name="Memory.PartitionAlloc.MemoryReclaim" units="microseconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>yukishiino@chromium.org</owner>
   <owner>lizeb@chromium.org</owner>
   <summary>
@@ -2637,7 +2637,7 @@
 </histogram>
 
 <histogram name="Memory.RendererProcessCount2" units="processes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>creis@chromium.org</owner>
   <owner>nasko@chromium.org</owner>
   <summary>
@@ -2802,7 +2802,7 @@
 </histogram>
 
 <histogram name="Memory.Total.GpuMappedMemory" units="MB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>lizeb@chromium.org</owner>
   <owner>chrome-memory@chromium.org</owner>
   <summary>
@@ -2814,7 +2814,7 @@
 </histogram>
 
 <histogram name="Memory.Total.HibernatedCanvas.OriginalSize" units="MB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>lizeb@chromium.org</owner>
   <owner>chrome-memory@chromium.org</owner>
   <summary>
@@ -2827,7 +2827,7 @@
 </histogram>
 
 <histogram name="Memory.Total.HibernatedCanvas.Size" units="MB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>lizeb@chromium.org</owner>
   <owner>chrome-memory@chromium.org</owner>
   <summary>
@@ -2865,7 +2865,7 @@
 </histogram>
 
 <histogram name="Memory.Total.PrivateMemoryFootprintExcludingWaivedRenderers"
-    units="MB" expires_after="2025-09-14">
+    units="MB" expires_after="2025-11-16">
   <owner>ckitagawa@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
@@ -2879,7 +2879,7 @@
 
 <histogram
     name="Memory.Total.PrivateMemoryFootprintVisibleOrHigherPriorityRenderers"
-    units="MB" expires_after="2025-09-14">
+    units="MB" expires_after="2025-11-16">
   <owner>ckitagawa@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
@@ -2893,7 +2893,7 @@
 </histogram>
 
 <histogram name="Memory.Total.PrivateSwapFootprint" units="MB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>thiabaud@google.com</owner>
   <owner>lizeb@chromium.org</owner>
   <summary>
@@ -2905,7 +2905,7 @@
 </histogram>
 
 <histogram name="Memory.Total.RendererBlinkGC" units="MB"
-    expires_after="2025-09-15">
+    expires_after="2025-11-16">
   <owner>fdoray@chromium.org</owner>
   <owner>lizeb@chromium.org</owner>
   <summary>
@@ -2917,7 +2917,7 @@
 </histogram>
 
 <histogram name="Memory.Total.RendererBlinkGC.Fragmentation" units="MB"
-    expires_after="2025-09-15">
+    expires_after="2025-11-16">
   <owner>fdoray@chromium.org</owner>
   <owner>lizeb@chromium.org</owner>
   <summary>
@@ -2942,7 +2942,7 @@
 </histogram>
 
 <histogram name="Memory.Total.RendererPrivateMemoryFootprint" units="MB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>tommckee@chromium.org</owner>
   <summary>
     A rough estimate of the private memory footprint of all renderer processes.
@@ -2960,7 +2960,7 @@
 </histogram>
 
 <histogram name="Memory.Total.RendererPrivateMemoryFootprintExcludingWaived"
-    units="MB" expires_after="2025-09-14">
+    units="MB" expires_after="2025-11-16">
   <owner>ckitagawa@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
@@ -2974,7 +2974,7 @@
 
 <histogram
     name="Memory.Total.RendererPrivateMemoryFootprintVisibleOrHigherPriority"
-    units="MB" expires_after="2025-09-14">
+    units="MB" expires_after="2025-11-16">
   <owner>ckitagawa@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
@@ -2988,7 +2988,7 @@
 </histogram>
 
 <histogram name="Memory.Total.RendererPrivateSwapFootprint" units="MB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>thiabaud@google.com</owner>
   <owner>lizeb@chromium.org</owner>
   <summary>
@@ -3050,7 +3050,7 @@
   </summary>
 </histogram>
 
-<histogram name="Memory.Total.TileMemory" units="MB" expires_after="2025-09-14">
+<histogram name="Memory.Total.TileMemory" units="MB" expires_after="2025-11-16">
   <owner>lizeb@chromium.org</owner>
   <owner>chrome-gpu-memory@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/mobile/histograms.xml b/tools/metrics/histograms/metadata/mobile/histograms.xml
index 4d6db34..cd20e83 100644
--- a/tools/metrics/histograms/metadata/mobile/histograms.xml
+++ b/tools/metrics/histograms/metadata/mobile/histograms.xml
@@ -1058,7 +1058,7 @@
 </histogram>
 
 <histogram name="MobileFre.Progress.{MobileFreEntryType}"
-    enum="MobileFreProgress" expires_after="2025-09-14">
+    enum="MobileFreProgress" expires_after="2025-11-16">
   <owner>bsazonov@chromium.org</owner>
   <owner>samarchehade@google.com</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -1237,7 +1237,7 @@
 </histogram>
 
 <histogram name="MobileStartup.IntentToCreationTime{ActivityType}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>tedchoc@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index ccd2a62..e4f0d72 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -314,7 +314,7 @@
 
 <histogram
     name="BackForwardCache.Experimental.UnexpectedIPCMessagePostedToCachedFrame.MethodHash"
-    enum="MojoInterfaceName" expires_after="2025-09-14">
+    enum="MojoInterfaceName" expires_after="2025-11-16">
   <owner>fergal@chromium.org</owner>
   <owner>bfcache-dev@chromium.org</owner>
   <summary>
@@ -780,7 +780,7 @@
 
 <histogram
     name="Navigation.CommitNavigationWithParams.Time.IsStandardLoadType.IsHTTPOrHTTPS"
-    units="microseconds" expires_after="2025-09-14">
+    units="microseconds" expires_after="2025-11-16">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -804,7 +804,7 @@
 
 <histogram
     name="Navigation.CommitRenderFrame.OutermostMainFrame.NewNavigation.IsHTTPOrHTTPS"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>sisidovski@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -816,7 +816,7 @@
 </histogram>
 
 <histogram name="Navigation.CommitRenderFrame.{FrameType}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>sisidovski@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -877,7 +877,7 @@
 </histogram>
 
 <histogram name="Navigation.DidCommitSameDocumentNavigation.Duration"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>peilinwang@google.com</owner>
   <owner>woa-performance-bugs+jank@google.com</owner>
   <summary>
@@ -1174,7 +1174,7 @@
 
 <histogram
     name="Navigation.GetFrameHostForNavigationTime.InDidCreateNavigationRequest.IsHTTPOrHTTPS"
-    units="microseconds" expires_after="2025-09-14">
+    units="microseconds" expires_after="2025-11-16">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -1441,7 +1441,7 @@
 </histogram>
 
 <histogram name="Navigation.MainFrame.SiteEngagementLevel"
-    enum="SiteEngagementLevel" expires_after="2025-09-14">
+    enum="SiteEngagementLevel" expires_after="2025-11-16">
   <owner>meacer@chromium.org</owner>
   <owner>security-enamel@chromium.org</owner>
   <summary>
@@ -1451,7 +1451,7 @@
 </histogram>
 
 <histogram name="Navigation.MainFrame.ThirdPartyCookieBlockingEnabled"
-    enum="ThirdPartyCookieBlockState" expires_after="2025-09-14">
+    enum="ThirdPartyCookieBlockState" expires_after="2025-11-16">
   <owner>dullweber@chromium.org</owner>
   <owner>feuunk@chromium.org</owner>
   <summary>
@@ -1566,7 +1566,7 @@
 </histogram>
 
 <histogram name="Navigation.MainFrameSchemeDifferentPageOTR2"
-    enum="NavigationScheme" expires_after="2025-09-14">
+    enum="NavigationScheme" expires_after="2025-11-16">
   <owner>estark@chromium.org</owner>
   <owner>elawrence@chromium.org</owner>
   <owner>trusty-transport@chromium.org</owner>
@@ -1615,7 +1615,7 @@
 </histogram>
 
 <histogram name="Navigation.OnBeforeUnloadTotalTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -2646,7 +2646,7 @@
 </histogram>
 
 <histogram name="Navigation.TimeToActivatePrerender{PreloadingTriggerType}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>nhiroki@chromium.org</owner>
   <owner>sreejakshetty@chromium.org</owner>
   <owner>chrome-prerendering@chromium.org</owner>
@@ -2677,7 +2677,7 @@
 </histogram>
 
 <histogram name="Navigation.TpcdMitigations.MetadataCohortDistribution"
-    enum="TpcdMetadataCohort" expires_after="2025-09-14">
+    enum="TpcdMetadataCohort" expires_after="2025-11-16">
   <owner>njeunje@chromium.org</owner>
   <owner>src/chrome/browser/tpcd/OWNERS</owner>
   <summary>
@@ -3162,7 +3162,7 @@
 
 <histogram
     name="Prerender.Experimental.ActivationHeadersMismatch{PreloadingTriggerType}"
-    enum="PrerenderActivationHeaderMismatchType" expires_after="2025-09-14">
+    enum="PrerenderActivationHeaderMismatchType" expires_after="2025-11-16">
   <owner>lingqi@chromium.org</owner>
   <owner>chrome-prerendering@google.com</owner>
   <summary>
@@ -3283,7 +3283,7 @@
 </histogram>
 
 <histogram name="Prerender.Experimental.PredictionStatus.DefaultSearchEngine"
-    enum="PrerenderPredictionStatus" expires_after="2025-09-14">
+    enum="PrerenderPredictionStatus" expires_after="2025-11-16">
   <owner>nhiroki@chromium.org</owner>
   <owner>chrome-prerendering@google.com</owner>
   <summary>
@@ -3335,7 +3335,7 @@
 
 <histogram
     name="Prerender.Experimental.PrerenderCancelledUnknownInterface{PreloadingTriggerType}"
-    enum="PrerenderCancelledUnknownInterface" expires_after="2025-09-14">
+    enum="PrerenderCancelledUnknownInterface" expires_after="2025-11-16">
   <owner>nhiroki@chromium.org</owner>
   <owner>toyoshim@chromium.org</owner>
   <owner>lingqi@chromium.org</owner>
@@ -3387,7 +3387,7 @@
 
 <histogram
     name="Prerender.Experimental.PrerenderHostFinalStatus{PreloadingTriggerType}"
-    enum="PrerenderHostFinalStatus" expires_after="2025-09-14">
+    enum="PrerenderHostFinalStatus" expires_after="2025-11-16">
   <owner>nhiroki@chromium.org</owner>
   <owner>toyoshim@chromium.org</owner>
   <owner>lingqi@chromium.org</owner>
@@ -3494,7 +3494,7 @@
 </histogram>
 
 <histogram name="Prerender.IsPrerenderingSRPUrl.{PreloadingEmbedderType}"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>robertlin@chromium.org</owner>
   <owner>chrome-prerendering@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index c572268..a35ec01d 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -514,7 +514,7 @@
 </histogram>
 
 <histogram name="HttpCache.AccessToDone2{HttpCacheAccessToDoneCases}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>morlovich@chromium.org</owner>
   <owner>olivierli@chromium.org</owner>
   <summary>
@@ -544,7 +544,7 @@
 </histogram>
 
 <histogram name="HttpCache.BeforeSend{HttpCacheBeforeSendCases}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>morlovich@chromium.org</owner>
   <owner>yhirano@chromium.org</owner>
   <summary>
@@ -568,7 +568,7 @@
 </histogram>
 
 <histogram name="HttpCache.CreateDiskEntry" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>yhirano@chromium.org</owner>
   <owner>net-dev@chromium.org</owner>
   <summary>
@@ -859,7 +859,7 @@
   </summary>
 </histogram>
 
-<histogram name="HttpCache.OpenDiskEntry" units="ms" expires_after="2025-09-14">
+<histogram name="HttpCache.OpenDiskEntry" units="ms" expires_after="2025-11-16">
   <owner>yhirano@chromium.org</owner>
   <owner>net-dev@chromium.org</owner>
   <summary>
@@ -924,7 +924,7 @@
 </histogram>
 
 <histogram name="HttpCache.TotalDiskCacheTimePerTransaction.{AccessType}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>bashi@chromium.org</owner>
   <owner>blink-network-stack@google.com</owner>
   <summary>
@@ -948,7 +948,7 @@
 </histogram>
 
 <histogram name="Net.AlternateProtocolUsage" enum="AlternateProtocolUsage"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -958,7 +958,7 @@
 </histogram>
 
 <histogram name="Net.AlternateProtocolUsageGoogle"
-    enum="AlternateProtocolUsage" expires_after="2025-09-14">
+    enum="AlternateProtocolUsage" expires_after="2025-11-16">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -1122,7 +1122,7 @@
 </histogram>
 
 <histogram name="Net.CertificateTransparency.SCTOrigin" enum="SCTOrigin"
-    expires_after="2025-07-21">
+    expires_after="2025-11-16">
   <owner>estark@chromium.org</owner>
   <owner>trusty-transport@chromium.org</owner>
   <summary>
@@ -1413,7 +1413,7 @@
 </histogram>
 
 <histogram name="Net.ConnectionInfo.MainFrame" enum="ConnectionInfo"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -2678,7 +2678,7 @@
 
 <histogram
     name="Net.HttpJob.IpProtection.AllowListMatch.PrefilterBytesRead.Net"
-    units="bytes" expires_after="2025-09-14">
+    units="bytes" expires_after="2025-11-16">
   <owner>abhijithnair@chromium.org</owner>
   <owner>ashleynewson@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
@@ -3137,7 +3137,7 @@
 </histogram>
 
 <histogram name="Net.HttpRequestSSLUpgradeDecision"
-    enum="HttpRequestSSLUpgradeDecision" expires_after="2025-09-14">
+    enum="HttpRequestSSLUpgradeDecision" expires_after="2025-11-16">
   <owner>cthomp@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <owner>joenotcharles@google.com</owner>
@@ -3208,7 +3208,7 @@
 </histogram>
 
 <histogram name="Net.HttpStreamPool.InitialAttemptState2"
-    enum="HttpStreamPoolInitialAttemptState" expires_after="2025-09-14">
+    enum="HttpStreamPoolInitialAttemptState" expires_after="2025-11-16">
   <owner>bashi@chromium.org</owner>
   <owner>blink-network-stack@google.com</owner>
   <summary>
@@ -3219,7 +3219,7 @@
 </histogram>
 
 <histogram name="Net.HttpStreamPool.JobCompleteTime2.{Result}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bashi@chromium.org</owner>
   <owner>blink-network-stack@google.com</owner>
   <summary>
@@ -3237,7 +3237,7 @@
 </histogram>
 
 <histogram name="Net.HttpStreamPool.JobErrorCode" enum="NetErrorCodes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bashi@chromium.org</owner>
   <owner>blink-network-stack@google.com</owner>
   <summary>
@@ -3351,7 +3351,7 @@
 </histogram>
 
 <histogram name="Net.HttpStreamPool.TcpBasedAttemptDelay" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bashi@chromium.org</owner>
   <owner>blink-network-stack@google.com</owner>
   <summary>
@@ -3457,7 +3457,7 @@
 </histogram>
 
 <histogram name="Net.NetworkChangeNotifier.NewConnectionType"
-    enum="NetworkConnectionType" expires_after="2025-09-14">
+    enum="NetworkConnectionType" expires_after="2025-11-16">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -3493,7 +3493,7 @@
 
 <histogram
     name="Net.NetworkTransaction.Create{StreamType}Time{HostType}.{Protocol}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>bashi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -3657,7 +3657,7 @@
 
 <histogram
     name="Net.NetworkTransaction.StreamRequestCompleteTime{HostType}.{SuccessOrFailure}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>bashi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -3669,7 +3669,7 @@
 </histogram>
 
 <histogram name="Net.NetworkTransaction.StreamRequestErrorCode"
-    enum="NetErrorCodes" expires_after="2025-09-14">
+    enum="NetErrorCodes" expires_after="2025-11-16">
   <owner>bashi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -4666,7 +4666,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ConnectionMigration{ConnectionMigrationCause}"
-    enum="QuicConnectionMigrationStatus" expires_after="2025-09-14">
+    enum="QuicConnectionMigrationStatus" expires_after="2025-11-16">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -4790,7 +4790,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.EncryptionEstablishedTime"
-    units="Milliseconds" expires_after="2025-09-14">
+    units="Milliseconds" expires_after="2025-11-16">
   <owner>fayang@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -4868,7 +4868,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.HandshakeConfirmedTime" units="Milliseconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -5138,7 +5138,7 @@
   </summary>
 </histogram>
 
-<histogram name="Net.QuicSession.MinRTT" units="ms" expires_after="2025-09-14">
+<histogram name="Net.QuicSession.MinRTT" units="ms" expires_after="2025-11-16">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -5232,7 +5232,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.NumPingsSent{HostType}" units="pings"
-    expires_after="2025-08-24">
+    expires_after="2025-11-16">
   <owner>renjietang@chromium.org</owner>
   <owner>suzukikeita@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
@@ -5584,7 +5584,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.QuicVersion" units="units"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>Version of the QUIC protocol used for this connection.</summary>
@@ -5833,7 +5833,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.SmoothedRTT" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -6142,7 +6142,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ZeroRttReason{HostType}"
-    enum="SSLHandshakeEarlyDataReason" expires_after="2025-09-14">
+    enum="SSLHandshakeEarlyDataReason" expires_after="2025-11-16">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -6160,7 +6160,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ZeroRttState{HostType}" enum="ZeroRttState"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bashi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -6582,7 +6582,7 @@
 </histogram>
 
 <histogram name="Net.RestrictedPorts" units="connections"
-    expires_after="2025-09-01">
+    expires_after="2025-11-16">
   <owner>tov@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -7298,7 +7298,7 @@
 </histogram>
 
 <histogram name="Net.SSLHandshakeEarlyDataReason"
-    enum="SSLHandshakeEarlyDataReason" expires_after="2025-09-14">
+    enum="SSLHandshakeEarlyDataReason" expires_after="2025-11-16">
   <owner>bashi@chromium.org</owner>
   <owner>trusty-transport@chromium.org</owner>
   <summary>
@@ -7313,7 +7313,7 @@
 </histogram>
 
 <histogram name="Net.SSLHandshakeEarlyDataReason.Google"
-    enum="SSLHandshakeEarlyDataReason" expires_after="2025-09-14">
+    enum="SSLHandshakeEarlyDataReason" expires_after="2025-11-16">
   <owner>bashi@chromium.org</owner>
   <owner>trusty-transport@chromium.org</owner>
   <summary>
@@ -7340,7 +7340,7 @@
 </histogram>
 
 <histogram name="Net.SSLNegotiatedAlpnProtocol"
-    enum="SSLNegotiatedAlpnProtocol" expires_after="2025-09-14">
+    enum="SSLNegotiatedAlpnProtocol" expires_after="2025-11-16">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -7423,7 +7423,7 @@
 </histogram>
 
 <histogram name="Net.TcpConnectAttempt.Latency.Success" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bashi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -7531,7 +7531,7 @@
 
 <histogram
     name="Net.TrustTokens.RequestHelperFactoryOutcome.{TrustTokenOperationType}"
-    enum="TrustTokenRequestHelperFactoryOutcome" expires_after="2025-09-14">
+    enum="TrustTokenRequestHelperFactoryOutcome" expires_after="2025-11-16">
   <owner>svaldez@chromium.org</owner>
   <owner>timhuber@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml
index 9c5cc58..b8228ef 100644
--- a/tools/metrics/histograms/metadata/network/histograms.xml
+++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -5651,7 +5651,7 @@
 </histogram>
 
 <histogram name="NetworkService.MaskedDomainList.MatchesTime"
-    units="microseconds" expires_after="2025-09-14">
+    units="microseconds" expires_after="2025-11-16">
   <owner>djmitche@chromium.org</owner>
   <owner>src/chrome/browser/ip_protection/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
index 91d5e08..56a4b47 100644
--- a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
+++ b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
@@ -86,7 +86,7 @@
 </variants>
 
 <histogram name="NewTabPage.ActionAndroid2" enum="NewTabPageActionAndroid2"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>twellington@chromium.org</owner>
   <owner>finkm@chromium.org</owner>
   <summary>
@@ -110,7 +110,7 @@
 </histogram>
 
 <histogram name="NewTabPage.AsHomeSurface" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>hanxi@chromium.org</owner>
   <owner>xinyiji@chromium.org</owner>
   <summary>
@@ -121,7 +121,7 @@
 </histogram>
 
 <histogram name="NewTabPage.AsHomeSurface.ShownAtStartup" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>hanxi@chromium.org</owner>
   <owner>xinyiji@chromium.org</owner>
   <summary>
@@ -132,7 +132,7 @@
 </histogram>
 
 <histogram name="NewTabPage.BackgroundImageSource"
-    enum="NTPBackgroundImageSource" expires_after="2025-09-14">
+    enum="NTPBackgroundImageSource" expires_after="2025-11-16">
   <owner>danpeng@google.com</owner>
   <owner>pauladedeji@google.com</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -144,7 +144,7 @@
 
 <histogram
     name="NewTabPage.BackgroundService.Collections.RequestLatency{NewTabPage_BackgroundService_RequestLatency}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>pauladedeji@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -253,7 +253,7 @@
 </histogram>
 
 <histogram name="NewTabPage.ConcretePage" enum="NewTabPageConcretePage"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>romanarora@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -264,7 +264,7 @@
 </histogram>
 
 <histogram name="NewTabPage.ContentSuggestions.ArticlesListVisible"
-    enum="BooleanVisible" expires_after="2025-09-14">
+    enum="BooleanVisible" expires_after="2025-11-16">
   <owner>freedjm@chromium.org</owner>
   <owner>feed@chromium.org</owner>
   <summary>
@@ -378,7 +378,7 @@
 </histogram>
 
 <histogram name="NewTabPage.CustomizeChromeOpened"
-    enum="NTPCustomizeChromeEntryPoint" expires_after="2025-09-14">
+    enum="NTPCustomizeChromeEntryPoint" expires_after="2025-11-16">
   <owner>pauladedeji@google.com</owner>
   <owner>danpeng@google.com</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -416,7 +416,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Customized" enum="NTPCustomizedFeatures"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>romanarora@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -427,7 +427,7 @@
 </histogram>
 
 <histogram name="NewTabPage.CustomizedShortcuts"
-    enum="NTPCustomizedShortcutSettings" expires_after="2025-09-14">
+    enum="NTPCustomizedShortcutSettings" expires_after="2025-11-16">
   <owner>romanarora@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -573,7 +573,7 @@
   </summary>
 </histogram>
 
-<histogram name="NewTabPage.Height" units="pixels" expires_after="2025-09-14">
+<histogram name="NewTabPage.Height" units="pixels" expires_after="2025-11-16">
   <owner>romanarora@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -586,7 +586,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Images.ShownTime{ImageType}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>danpeng@google.com</owner>
   <owner>pauladedeji@google.com</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -641,7 +641,7 @@
 </histogram>
 
 <histogram name="NewTabPage.LoadTime{NewTabPageTimings}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>romanarora@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -958,7 +958,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Modules.Dismissed{NewTabPageModules}" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>romanarora@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -974,7 +974,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Modules.EnabledOnNTPLoad{NewTabPageModules}"
-    enum="BooleanEnabled" expires_after="2025-09-14">
+    enum="BooleanEnabled" expires_after="2025-11-16">
   <owner>romanarora@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -991,7 +991,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Modules.Enabled{Interaction}" enum="NtpModules"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>romanarora@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1049,7 +1049,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Modules.Impression{NewTabPageModules}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>romanarora@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1146,7 +1146,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Modules.LoadedWith.{NtpModule}" enum="NtpModules"
-    expires_after="2025-07-13">
+    expires_after="2025-11-16">
   <owner>romanarora@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1169,7 +1169,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Modules.Loaded{NewTabPageModules}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>romanarora@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -1228,7 +1228,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Modules.Restored{NewTabPageModules}" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>romanarora@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1255,7 +1255,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Modules.Usage{NewTabPageModules}" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>romanarora@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1275,7 +1275,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Modules.VisibleOnNTPLoad" enum="BooleanVisible"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>romanarora@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1758,7 +1758,7 @@
 </histogram>
 
 <histogram name="NewTabPage.SuggestTiles.DeletedTileType"
-    enum="SuggestTileType" expires_after="2025-09-14">
+    enum="SuggestTileType" expires_after="2025-11-16">
   <owner>ender@google.com</owner>
   <owner>mahmadi@chromium.org</owner>
   <owner>chrome-omnibox-team@google.com</owner>
@@ -1773,7 +1773,7 @@
 </histogram>
 
 <histogram name="NewTabPage.SuggestTiles.SelectedTileType"
-    enum="SuggestTileType" expires_after="2025-09-14">
+    enum="SuggestTileType" expires_after="2025-11-16">
   <owner>ender@google.com</owner>
   <owner>mahmadi@chromium.org</owner>
   <owner>chrome-omnibox-team@google.com</owner>
@@ -1788,7 +1788,7 @@
 </histogram>
 
 <histogram name="NewTabPage.TabResumption.ClickIndex" units="index"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mfacey@google.com</owner>
   <owner>romanarora@google.com</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1833,7 +1833,7 @@
 </histogram>
 
 <histogram name="NewTabPage.TabResumption.TimeElapsedSinceLastVisit" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mfacey@google.com</owner>
   <owner>romanarora@google.com</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1966,7 +1966,7 @@
   </summary>
 </histogram>
 
-<histogram name="NewTabPage.TimeSpent" units="ms" expires_after="2025-09-14">
+<histogram name="NewTabPage.TimeSpent" units="ms" expires_after="2025-11-16">
   <owner>freedjm@chromium.org</owner>
   <owner>feed@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
@@ -2054,7 +2054,7 @@
 
 <histogram
     name="NewTabPage.WallpaperSearch.SetInspirationThemeProcessingLatency"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>pauladedeji@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>rtatum@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/notifications/histograms.xml b/tools/metrics/histograms/metadata/notifications/histograms.xml
index f89f1d71..c3bcaae9 100644
--- a/tools/metrics/histograms/metadata/notifications/histograms.xml
+++ b/tools/metrics/histograms/metadata/notifications/histograms.xml
@@ -744,7 +744,7 @@
 <histogram
     name="Notifications.NotificationHelper.NotificationActivatorPrimaryStatus"
     enum="NotificationHelperNotificationActivatorPrimaryStatus"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>finnur@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -861,7 +861,7 @@
 </histogram>
 
 <histogram name="Notifications.PersistentNotificationActionCount"
-    units="buttons" expires_after="2025-09-14">
+    units="buttons" expires_after="2025-11-16">
   <owner>peter@chromium.org</owner>
   <summary>
     The number of action buttons the developer provided for a persistent Web
diff --git a/tools/metrics/histograms/metadata/omnibox/histograms.xml b/tools/metrics/histograms/metadata/omnibox/histograms.xml
index 9b84289..f7fa25b 100644
--- a/tools/metrics/histograms/metadata/omnibox/histograms.xml
+++ b/tools/metrics/histograms/metadata/omnibox/histograms.xml
@@ -271,7 +271,7 @@
 </variants>
 
 <histogram name="Omnibox.AcceptedKeywordSuggestion"
-    enum="OmniboxEnteredKeywordMode2" expires_after="2025-09-14">
+    enum="OmniboxEnteredKeywordMode2" expires_after="2025-11-16">
   <owner>yoangela@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
   <summary>
@@ -386,7 +386,7 @@
 </histogram>
 
 <histogram name="Omnibox.AnswerParseSuccess" enum="BooleanSuccess"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jdonnelly@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
   <summary>
@@ -396,7 +396,7 @@
 </histogram>
 
 <histogram name="Omnibox.AnswerParseType" enum="SuggestionAnswerType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jdonnelly@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
   <summary>
@@ -412,7 +412,7 @@
 
 <histogram
     name="Omnibox.AsyncAutocompletionTime2.Provider.{Provider}{Completed}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>manukh@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -463,7 +463,7 @@
 </histogram>
 
 <histogram name="Omnibox.AsyncAutocompletionTime2.{Change}{Completed}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>manukh@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -600,7 +600,7 @@
 </histogram>
 
 <histogram name="Omnibox.CharTypedToRepaintLatency" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>manukh@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
@@ -633,7 +633,7 @@
 </histogram>
 
 <histogram name="Omnibox.CharTypedToRepaintLatency.InsertToPresent" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>manukh@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
@@ -682,7 +682,7 @@
 </histogram>
 
 <histogram name="Omnibox.CharTypedToRepaintLatency.ToPaint" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>manukh@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
@@ -870,7 +870,7 @@
 </histogram>
 
 <histogram name="Omnibox.DocumentSuggest.HttpResponseCode"
-    enum="HttpResponseCode" expires_after="2025-09-14">
+    enum="HttpResponseCode" expires_after="2025-11-16">
   <owner>manukh@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <summary>
@@ -902,7 +902,7 @@
 </histogram>
 
 <histogram name="Omnibox.DocumentSuggest.ProviderAllowed"
-    enum="DocumentProviderAllowedReason" expires_after="2025-09-14">
+    enum="DocumentProviderAllowedReason" expires_after="2025-11-16">
   <owner>manukh@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <summary>
@@ -923,7 +923,7 @@
 </histogram>
 
 <histogram name="Omnibox.DocumentSuggest.Requests"
-    enum="DocumentSuggestRequestEvent" expires_after="2025-09-14">
+    enum="DocumentSuggestRequestEvent" expires_after="2025-11-16">
   <owner>manukh@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <summary>
@@ -933,7 +933,7 @@
 </histogram>
 
 <histogram name="Omnibox.DocumentSuggest.RequestTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>manukh@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <summary>
@@ -949,7 +949,7 @@
 </histogram>
 
 <histogram name="Omnibox.DocumentSuggest.RequestTime.Interrupted" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>manukh@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <summary>
@@ -968,7 +968,7 @@
 </histogram>
 
 <histogram name="Omnibox.DocumentSuggest.RequestTime.NotInterrupted" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>manukh@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <summary>
@@ -987,7 +987,7 @@
 </histogram>
 
 <histogram name="Omnibox.DocumentSuggest.ResultCount" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>manukh@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
@@ -999,7 +999,7 @@
 </histogram>
 
 <histogram name="Omnibox.DocumentSuggest.TotalTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>manukh@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <summary>
@@ -1048,7 +1048,7 @@
 </histogram>
 
 <histogram name="Omnibox.EnteredKeywordMode2" enum="OmniboxEnteredKeywordMode2"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jdonnelly@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -1114,7 +1114,7 @@
 </histogram>
 
 <histogram name="Omnibox.FocusToCutOrCopyAllTextTime" units="ms"
-    expires_after="2025-09-17">
+    expires_after="2025-11-16">
   <owner>khalidpeer@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
   <summary>
@@ -1133,7 +1133,7 @@
 
 <histogram
     name="Omnibox.FocusToCutOrCopyAllTextTime.ByPageContext.{OmniboxPageContext}"
-    units="ms" expires_after="2025-09-17">
+    units="ms" expires_after="2025-11-16">
   <owner>khalidpeer@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
   <summary>
@@ -1152,7 +1152,7 @@
 </histogram>
 
 <histogram name="Omnibox.FocusToCutOrCopyAllTextTime.{OmniboxZeroPrefixState}"
-    units="ms" expires_after="2025-09-17">
+    units="ms" expires_after="2025-11-16">
   <owner>khalidpeer@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
   <summary>
@@ -1172,7 +1172,7 @@
 
 <histogram
     name="Omnibox.FocusToCutOrCopyAllTextTime.{OmniboxZeroPrefixState}.ByPageContext.{OmniboxPageContext}"
-    units="ms" expires_after="2025-09-17">
+    units="ms" expires_after="2025-11-16">
   <owner>khalidpeer@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
   <summary>
@@ -1193,7 +1193,7 @@
 </histogram>
 
 <histogram name="Omnibox.FocusToOpenTimeAnyPopupState3" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jdonnelly@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -1522,7 +1522,7 @@
 </histogram>
 
 <histogram name="Omnibox.KeywordModeUsageByEngineType.{Usage}"
-    enum="OmniboxBuiltinEngineType" expires_after="2025-09-14">
+    enum="OmniboxBuiltinEngineType" expires_after="2025-11-16">
   <owner>yoangela@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
   <summary>
@@ -1681,7 +1681,7 @@
 
 <histogram
     name="Omnibox.MatchStability2.MatchChangeInAnyPosition{OmniboxAutocompleteUpdateSlice}"
-    enum="BooleanChanged" expires_after="2025-09-14">
+    enum="BooleanChanged" expires_after="2025-11-16">
   <owner>manukh@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <summary>
@@ -1728,7 +1728,7 @@
 
 <histogram
     name="Omnibox.MatchStability2.MatchChangeIndex{OmniboxAutocompleteUpdateSlice}"
-    units="position" expires_after="2025-09-14">
+    units="position" expires_after="2025-11-16">
   <owner>manukh@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <summary>
@@ -1873,7 +1873,7 @@
   </summary>
 </histogram>
 
-<histogram name="Omnibox.PaintTime" units="ms" expires_after="2025-09-14">
+<histogram name="Omnibox.PaintTime" units="ms" expires_after="2025-11-16">
   <owner>manukh@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
@@ -1894,7 +1894,7 @@
 </histogram>
 
 <histogram name="Omnibox.PedalShown" enum="SuggestionPedalType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jdonnelly@chromium.org</owner>
   <owner>orinj@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -1915,7 +1915,7 @@
 </histogram>
 
 <histogram name="Omnibox.ProviderTime2.{OmniboxProvider}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jdonnelly@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -1927,7 +1927,7 @@
 </histogram>
 
 <histogram name="Omnibox.QueryTime2{QueryTimeSuffix}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jdonnelly@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -2223,7 +2223,7 @@
 </histogram>
 
 <histogram name="Omnibox.SearchPreload.ForwardingResult.NotServedToPrerender"
-    enum="SearchPreloadForwardingResult" expires_after="2025-09-14">
+    enum="SearchPreloadForwardingResult" expires_after="2025-11-16">
   <owner>lingqi@chromium.org</owner>
   <owner>ryansturm@chromium.org</owner>
   <owner>chrome-prerendering@google.com</owner>
@@ -2237,7 +2237,7 @@
 </histogram>
 
 <histogram name="Omnibox.SearchPreload.ForwardingResult.WasServedToPrerender"
-    enum="SearchPreloadForwardingResult" expires_after="2025-09-14">
+    enum="SearchPreloadForwardingResult" expires_after="2025-11-16">
   <owner>lingqi@chromium.org</owner>
   <owner>ryansturm@chromium.org</owner>
   <owner>chrome-prerendering@google.com</owner>
@@ -2250,7 +2250,7 @@
 </histogram>
 
 <histogram name="Omnibox.SearchPreload.ResponseDataReaderFinalStatus.Prerender"
-    enum="SearchPrefetchResponseDataReaderStatus" expires_after="2025-09-14">
+    enum="SearchPrefetchResponseDataReaderStatus" expires_after="2025-11-16">
   <owner>lingqi@chromium.org</owner>
   <owner>ryansturm@chromium.org</owner>
   <owner>chrome-prerendering@google.com</owner>
@@ -2273,7 +2273,7 @@
 </histogram>
 
 <histogram name="Omnibox.Start.WantAsyncMatches" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jdonnelly@chromium.org</owner>
   <summary>
     Whether asynchronous matches are requested. Recorded every time
@@ -2419,7 +2419,7 @@
 </histogram>
 
 <histogram name="Omnibox.SuggestionUsed.OfferedTabMatch" enum="BooleanOffered"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>gangwu@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
@@ -2442,7 +2442,7 @@
 </histogram>
 
 <histogram name="Omnibox.SuggestionUsed.Pedal" enum="SuggestionPedalType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jdonnelly@chromium.org</owner>
   <owner>orinj@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -2579,7 +2579,7 @@
 
 <histogram
     name="Omnibox.SuggestionUsed.Search.Experimental.NavigationToFirstMeaningfulPaint"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>jdonnelly@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -2590,7 +2590,7 @@
 </histogram>
 
 <histogram name="Omnibox.SuggestionUsed.Search.InputToNavigationStart2"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>spelchat@chromium.org</owner>
   <owner>chrome-brapp-loading@google.com</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -2603,7 +2603,7 @@
 
 <histogram
     name="Omnibox.SuggestionUsed.Search.NavigationToFirstContentfulPaint"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>jdonnelly@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -2644,7 +2644,7 @@
 </histogram>
 
 <histogram name="Omnibox.SuggestionUsed.SelectedTabMatch"
-    enum="BooleanSelected" expires_after="2025-09-14">
+    enum="BooleanSelected" expires_after="2025-11-16">
   <owner>gangwu@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
@@ -2685,7 +2685,7 @@
 </histogram>
 
 <histogram name="Omnibox.SuggestionUsed.URL.InputToNavigationStart2" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>spelchat@chromium.org</owner>
   <owner>chrome-brapp-loading@google.com</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -2709,7 +2709,7 @@
 
 <histogram
     name="Omnibox.SuggestionUsed.URL.NavigationToLargestContentfulPaint2.1"
-    units="ms" expires_after="2025-06-29">
+    units="ms" expires_after="2025-12-29">
   <owner>robertlin@chromium.org</owner>
   <owner>chrome-prerendering@google.com</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -2732,7 +2732,7 @@
 </histogram>
 
 <histogram name="Omnibox.SuggestRequest.Success.GoogleResponseTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mpearson@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <owner>cch@chromium.org</owner>
@@ -3528,7 +3528,7 @@
 </histogram>
 
 <histogram name="Omnibox.ZeroSuggestProvider.Eligibility"
-    enum="ZeroSuggestEligibility" expires_after="2025-09-14">
+    enum="ZeroSuggestEligibility" expires_after="2025-11-16">
   <owner>mahmadi@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
   <summary>
@@ -3542,7 +3542,7 @@
 </histogram>
 
 <histogram name="Omnibox.ZeroSuggestProvider.{ResultType}.{RequestType}"
-    enum="ZeroSuggestRequestEvent" expires_after="2025-09-14">
+    enum="ZeroSuggestRequestEvent" expires_after="2025-11-16">
   <owner>mahmadi@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
   <summary>
@@ -3629,7 +3629,7 @@
 
 <histogram
     name="Omnibox.{SearchPrefetch}.NavigationInterceptedToForwardingComplete"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>spelchat@chromium.org</owner>
   <owner>chrome-brapp-loading@google.com</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -3648,7 +3648,7 @@
 
 <histogram
     name="Omnibox.{SearchPrefetch}.PrefetchEligibilityReason2.{NavigationOrSuggestionPrefetch}"
-    enum="SearchPrefetchEligibilityReason" expires_after="2025-09-14">
+    enum="SearchPrefetchEligibilityReason" expires_after="2025-11-16">
   <owner>ryansturm@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
   <summary>
@@ -3667,7 +3667,7 @@
 
 <histogram
     name="Omnibox.{SearchPrefetch}.PrefetchFinalStatus.{NavigationOrSuggestionPrefetch}"
-    enum="SearchPrefetchStatus" expires_after="2025-09-14">
+    enum="SearchPrefetchStatus" expires_after="2025-11-16">
   <owner>ryansturm@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
   <summary>
@@ -3685,7 +3685,7 @@
 
 <histogram
     name="Omnibox.{SearchPrefetch}.PrefetchServingReason2{PrerenderOrNavigation}"
-    enum="SearchPrefetchServingReason" expires_after="2025-09-14">
+    enum="SearchPrefetchServingReason" expires_after="2025-11-16">
   <owner>ryansturm@chromium.org</owner>
   <owner>lingqi@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -3709,7 +3709,7 @@
 
 <histogram
     name="Omnibox.{SearchPrefetch}.ReceivedServableResponse2.{FallbackOrInitial}.{NavigationOrSuggestionPrefetch}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>ryansturm@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
   <owner>chrome-prerendering@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/optimization/histograms.xml b/tools/metrics/histograms/metadata/optimization/histograms.xml
index b8a81ea..6f9c0718 100644
--- a/tools/metrics/histograms/metadata/optimization/histograms.xml
+++ b/tools/metrics/histograms/metadata/optimization/histograms.xml
@@ -767,7 +767,7 @@
 
 <histogram
     name="OptimizationGuide.HintsFetcher.GetHintsRequest.UrlCount.{RequestContext}"
-    units="total url count" expires_after="2025-09-14">
+    units="total url count" expires_after="2025-11-16">
   <owner>mcrouse@chromium.org</owner>
   <owner>sophiechang@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index cddedec..cf1b3f7 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -359,7 +359,7 @@
 </histogram>
 
 <histogram name="AccessCodeCast.Session.FreezeCount" units="instances"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bzielinski@google.com</owner>
   <owner>cros-edu-eng@google.com</owner>
   <summary>
@@ -474,7 +474,7 @@
 </histogram>
 
 <histogram name="AccessCodeCast.Ui.DialogLoadTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bzielinski@google.com</owner>
   <owner>cros-edu-eng@google.com</owner>
   <summary>
@@ -543,7 +543,7 @@
 </histogram>
 
 <histogram name="Ads.InterestGroup.Auction.AdComponentsCountForWinningBid"
-    units="NumComponents" expires_after="2025-09-14">
+    units="NumComponents" expires_after="2025-11-16">
   <owner>averge@chromium.org</owner>
   <owner>privacy-sandbox-dev@chromium.org</owner>
   <summary>
@@ -944,7 +944,7 @@
 </histogram>
 
 <histogram name="Ads.InterestGroup.Auction.IdleProcessExpired" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>abigailkatcoff@chromium.org</owner>
   <owner>privacy-sandbox-dev@chromium.org</owner>
   <summary>
@@ -1036,7 +1036,7 @@
 </histogram>
 
 <histogram name="Ads.InterestGroup.Auction.NonPremadeContextsCreated"
-    units="contexts" expires_after="2025-09-14">
+    units="contexts" expires_after="2025-11-16">
   <owner>abigailkatcoff@chromium.org</owner>
   <owner>privacy-sandbox-dev@chromium.org</owner>
   <summary>
@@ -1149,7 +1149,7 @@
 </histogram>
 
 <histogram name="Ads.InterestGroup.Auction.NumOwnerOriginsCachedForPreconnect"
-    units="owners" expires_after="2025-09-07">
+    units="owners" expires_after="2025-11-16">
   <owner>abigailkatcoff@chromium.org</owner>
   <owner>privacy-sandbox-dev@chromium.org</owner>
   <summary>
@@ -1300,7 +1300,7 @@
 </histogram>
 
 <histogram name="Ads.InterestGroup.Auction.PremadeContextsScheduledPerThread"
-    units="contexts" expires_after="2025-09-14">
+    units="contexts" expires_after="2025-11-16">
   <owner>abigailkatcoff@chromium.org</owner>
   <owner>privacy-sandbox-dev@chromium.org</owner>
   <summary>
@@ -1355,7 +1355,7 @@
 
 <histogram
     name="Ads.InterestGroup.Auction.SameSiteAdComponentsMaxCountForWinningBid"
-    units="NumComponents" expires_after="2025-09-14">
+    units="NumComponents" expires_after="2025-11-16">
   <owner>averge@chromium.org</owner>
   <owner>privacy-sandbox-dev@chromium.org</owner>
   <summary>
@@ -1488,7 +1488,7 @@
 </histogram>
 
 <histogram name="Ads.InterestGroup.Auction.TrustedBidderSignalsOriginRelation"
-    enum="BidderSignalsOriginRelation" expires_after="2025-09-14">
+    enum="BidderSignalsOriginRelation" expires_after="2025-11-16">
   <owner>morlovich@chromium.org</owner>
   <owner>privacy-sandbox-dev@chromium.org</owner>
   <summary>
@@ -1552,7 +1552,7 @@
 </histogram>
 
 <histogram name="Ads.InterestGroup.Auction.TrustedSellerSignalsOriginRelation"
-    enum="SellerSignalsOriginRelation" expires_after="2025-09-14">
+    enum="SellerSignalsOriginRelation" expires_after="2025-11-16">
   <owner>morlovich@chromium.org</owner>
   <owner>privacy-sandbox-dev@chromium.org</owner>
   <summary>
@@ -1565,7 +1565,7 @@
 </histogram>
 
 <histogram name="Ads.InterestGroup.Auction.UnusedPremadeContexts"
-    units="contexts" expires_after="2025-09-14">
+    units="contexts" expires_after="2025-11-16">
   <owner>abigailkatcoff@chromium.org</owner>
   <owner>privacy-sandbox-dev@chromium.org</owner>
   <summary>
@@ -1581,7 +1581,7 @@
 </histogram>
 
 <histogram name="Ads.InterestGroup.Auction.UsedPremadeContext" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>abigailkatcoff@chromium.org</owner>
   <owner>privacy-sandbox-dev@chromium.org</owner>
   <summary>
@@ -1665,7 +1665,7 @@
 </histogram>
 
 <histogram name="Ads.InterestGroup.BaDataSize2" units="bytes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>behamilton@google.com</owner>
   <owner>pauljensen@chromium.org</owner>
   <owner>privacy-sandbox-dev@chromium.org</owner>
@@ -2244,7 +2244,7 @@
 </histogram>
 
 <histogram name="Ads.InterestGroup.ServerAuction.PrevWinsArraySize"
-    units="bytes" expires_after="2025-09-14">
+    units="bytes" expires_after="2025-11-16">
   <owner>caraitto@chromium.org</owner>
   <owner>pauljensen@chromium.org</owner>
   <owner>privacy-sandbox-dev@chromium.org</owner>
@@ -2893,7 +2893,7 @@
   </summary>
 </histogram>
 
-<histogram name="BootTime.Chrome.{Type}" units="ms" expires_after="2025-09-12">
+<histogram name="BootTime.Chrome.{Type}" units="ms" expires_after="2025-11-16">
   <owner>takayas@google.com</owner>
   <owner>uekawa@google.com</owner>
   <summary>
@@ -2952,7 +2952,7 @@
   </summary>
 </histogram>
 
-<histogram name="BootTime.Kernel.{Type}" units="ms" expires_after="2025-09-12">
+<histogram name="BootTime.Kernel.{Type}" units="ms" expires_after="2025-11-16">
   <owner>takayas@google.com</owner>
   <owner>uekawa@google.com</owner>
   <summary>
@@ -3081,7 +3081,7 @@
   </summary>
 </histogram>
 
-<histogram name="BootTime.Total2.{Type}" units="ms" expires_after="2025-09-12">
+<histogram name="BootTime.Total2.{Type}" units="ms" expires_after="2025-11-16">
   <owner>takayas@google.com</owner>
   <owner>uekawa@google.com</owner>
   <summary>
@@ -3121,7 +3121,7 @@
 </histogram>
 
 <histogram name="BrotliFilter.CompressionPercent" units="%"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>eustas@chromium.org</owner>
   <summary>Compressed/Decompressed size ratio.</summary>
 </histogram>
@@ -4079,7 +4079,7 @@
 </histogram>
 
 <histogram name="DisplayManager.MirroringImplementation"
-    enum="DisplayMirroringImplementation" expires_after="2025-09-14">
+    enum="DisplayMirroringImplementation" expires_after="2025-11-16">
   <owner>jshargo@chromium.org</owner>
   <owner>oshima@chromium.org</owner>
   <owner>chromeos-gfx-compositor@google.com</owner>
@@ -4902,7 +4902,7 @@
 
 <histogram name="Feedback.HappinessTrackingSurvey.ShouldShowSurveyReason"
     enum="HappinessTrackingSurveyShouldShowSurveyReasons"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>sauski@google.com</owner>
   <owner>msramek@chromium.org</owner>
   <summary>
@@ -5646,7 +5646,7 @@
 </histogram>
 
 <histogram name="Hwsec.Attestation.Status{AttestationOps}"
-    enum="HwsecAttestationOpsStatus" expires_after="2025-09-14">
+    enum="HwsecAttestationOpsStatus" expires_after="2025-11-16">
   <owner>chingkang@chromium.org</owner>
   <owner>cros-hwsec-userland-eng+uma@google.com</owner>
   <summary>
@@ -5748,7 +5748,7 @@
 </histogram>
 
 <histogram name="ImportantFile.SerializationDuration{ImportantFileClients}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>battre@chromium.org</owner>
   <owner>gab@chromium.org</owner>
   <summary>
@@ -5762,7 +5762,7 @@
 </histogram>
 
 <histogram name="ImportantFile.WriteDuration{ImportantFileClients}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>wylieb@google.com</owner>
   <owner>chrome-collections@google.com</owner>
   <summary>
@@ -6025,7 +6025,7 @@
 </histogram>
 
 <histogram name="Manifest.HasProperty{ManifestProperties}" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mgiuca@chromium.org</owner>
   <summary>
     Tracks which properties of a Manifest were present when it was parsed. If a
@@ -6133,7 +6133,7 @@
 </histogram>
 
 <histogram name="Mojo.Channel.WriteMessageLatency" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>amistry@chromium.org</owner>
   <owner>bgeffon@chromium.org</owner>
   <owner>rockot@google.com</owner>
@@ -6328,7 +6328,7 @@
 </histogram>
 
 <histogram name="MPArch.ChildProcessLauncher.{Event}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ajgo@chromium.org</owner>
   <owner>src/sandbox/policy/win/OWNERS</owner>
   <summary>
@@ -6348,7 +6348,7 @@
 </histogram>
 
 <histogram name="MPArch.ChildProcessLaunchFirst" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>pasko@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
@@ -6367,7 +6367,7 @@
 </histogram>
 
 <histogram name="MultiProfile.UsersPerSessionIncremental" units="units"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>skuhne@chromium.org</owner>
   <owner>antrim@chromium.org</owner>
   <summary>
@@ -6546,7 +6546,7 @@
 </histogram>
 
 <histogram name="OAuth2Login.SessionRestore" enum="GaiaSessionRestoreOutcome"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>emaamari@google.com</owner>
   <owner>sinhak@chromium.org</owner>
   <summary>Outcome of Chrome OS GAIA cookie session restore process.</summary>
@@ -6978,7 +6978,7 @@
 </histogram>
 
 <histogram name="OSCrypt.AppBoundProvider.Decrypt.ResultCode" enum="Hresult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>wfh@chromium.org</owner>
   <owner>nparker@chromium.org</owner>
   <summary>
@@ -7003,7 +7003,7 @@
 </histogram>
 
 <histogram name="OSCrypt.AppBoundProvider.Encrypt.ResultCode" enum="Hresult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>wfh@chromium.org</owner>
   <owner>nparker@chromium.org</owner>
   <summary>
@@ -7073,7 +7073,7 @@
 </histogram>
 
 <histogram name="OSCrypt.DPAPIProvider.Status" enum="OSCryptDPAPIKeyStatus"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>wfh@chromium.org</owner>
   <owner>nparker@chromium.org</owner>
   <summary>
@@ -7642,7 +7642,7 @@
 </histogram>
 
 <histogram name="PLT.iOS.BrowserInitiatedPageLoadTime2" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>michaeldo@chromium.org</owner>
   <owner>bling-fundamentals@google.com</owner>
   <summary>
@@ -7688,7 +7688,7 @@
 </histogram>
 
 <histogram name="PLT.iOS.RendererInitiatedPageLoadTime2" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>michaeldo@chromium.org</owner>
   <owner>bling-fundamentals@google.com</owner>
   <summary>
@@ -7872,7 +7872,7 @@
 </histogram>
 
 <histogram name="Process.Sandbox.StartSandboxedWin.{Event}Duration"
-    units="microseconds" expires_after="2025-09-14">
+    units="microseconds" expires_after="2025-11-16">
   <owner>ajgo@chromium.org</owner>
   <owner>src/sandbox/policy/win/OWNERS</owner>
   <summary>
@@ -7961,7 +7961,7 @@
 </histogram>
 
 <histogram name="PushMessaging.UnregistrationReason"
-    enum="PushUnregistrationReason" expires_after="2025-09-14">
+    enum="PushUnregistrationReason" expires_after="2025-11-16">
   <owner>peter@chromium.org</owner>
   <owner>knollr@chromium.org</owner>
   <summary>
@@ -8417,7 +8417,7 @@
   </token>
 </histogram>
 
-<histogram name="SB2.RemoteCall.Elapsed" units="ms" expires_after="2025-09-14">
+<histogram name="SB2.RemoteCall.Elapsed" units="ms" expires_after="2025-11-16">
   <owner>vakh@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -8654,7 +8654,7 @@
 </histogram>
 
 <histogram name="Shutdown.OtherExit.Time2" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>etienneb@chromium.org</owner>
   <owner>gab@chromium.org</owner>
   <summary>
@@ -8742,7 +8742,7 @@
 </histogram>
 
 <histogram name="SignedExchange.LoadResult2" enum="SignedExchangeLoadResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ksakamoto@chromium.org</owner>
   <owner>webpackage-dev@chromium.org</owner>
   <summary>
@@ -9104,7 +9104,7 @@
 </histogram>
 
 <histogram name="SpellCheck.SpellingService.RequestHttpResponseCode"
-    enum="HttpResponseCode" expires_after="2025-09-14">
+    enum="HttpResponseCode" expires_after="2025-11-16">
   <owner>shend@chromium.org</owner>
   <owner>essential-inputs-team@google.com</owner>
   <summary>The HTTP code of Spelling service responses.</summary>
@@ -10013,7 +10013,7 @@
   </summary>
 </histogram>
 
-<histogram name="Uptime.Logout" units="ms" expires_after="2025-09-14">
+<histogram name="Uptime.Logout" units="ms" expires_after="2025-11-16">
   <owner>xiyuan@chromium.org</owner>
   <owner>cros-oac@google.com</owner>
   <summary>
@@ -10268,7 +10268,7 @@
 </histogram>
 
 <histogram name="WebFont.BlankTextShownTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kenjibaheux@chromium.org</owner>
   <owner>ksakamoto@chromium.org</owner>
   <summary>
@@ -10304,7 +10304,7 @@
 </histogram>
 
 <histogram name="WebFont.DownloadTime.LoadError" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kenjibaheux@chromium.org</owner>
   <owner>ksakamoto@chromium.org</owner>
   <summary>
@@ -10314,7 +10314,7 @@
 </histogram>
 
 <histogram name="WebFont.HadBlankText" enum="BooleanHadBlankText"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kenjibaheux@chromium.org</owner>
   <owner>ksakamoto@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml
index 3565355..9f0f44d 100644
--- a/tools/metrics/histograms/metadata/page/histograms.xml
+++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -1171,7 +1171,7 @@
 </histogram>
 
 <histogram name="PageLoad.Clients.GoogleSearch.CSI.{Event}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>sisidovski@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -1812,7 +1812,7 @@
 </histogram>
 
 <histogram name="PageLoad.Clients.LCPP.Subresource.Count.Precision" units="%"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>yoichio@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -1830,7 +1830,7 @@
 </histogram>
 
 <histogram name="PageLoad.Clients.LCPP.Subresource.Count.Recall" units="%"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>yoichio@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -1848,7 +1848,7 @@
 </histogram>
 
 <histogram name="PageLoad.Clients.LCPP.Subresource.Count.SameSiteRatio"
-    units="%" expires_after="2025-09-14">
+    units="%" expires_after="2025-11-16">
   <owner>yoichio@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -1864,7 +1864,7 @@
 </histogram>
 
 <histogram name="PageLoad.Clients.LCPP.Subresource.Count.Type"
-    enum="RequestDestination" expires_after="2025-09-14">
+    enum="RequestDestination" expires_after="2025-11-16">
   <owner>yoichio@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -1980,7 +1980,7 @@
 
 <histogram
     name="PageLoad.Clients.MultiTabLoading{OtherLoadingCount}.{Timing}{Background}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>{Timing} {OtherLoadingCount} {Background}</summary>
@@ -2162,7 +2162,7 @@
 
 <histogram
     name="PageLoad.Clients.Prerender.InteractiveTiming.FirstInputDelay4{PreloadingTriggerType}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>nhiroki@chromium.org</owner>
   <owner>src/content/browser/preloading/prerender/OWNERS</owner>
   <summary>
@@ -2175,7 +2175,7 @@
 
 <histogram
     name="PageLoad.Clients.Prerender.LayoutInstability.CumulativeShiftScore.MainFrame{PreloadingTriggerType}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>nhiroki@chromium.org</owner>
   <owner>src/content/browser/preloading/prerender/OWNERS</owner>
   <summary>
@@ -2189,7 +2189,7 @@
 
 <histogram
     name="PageLoad.Clients.Prerender.LayoutInstability.CumulativeShiftScore{PreloadingTriggerType}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>nhiroki@chromium.org</owner>
   <owner>src/content/browser/preloading/prerender/OWNERS</owner>
   <summary>
@@ -2216,7 +2216,7 @@
 
 <histogram
     name="PageLoad.Clients.Prerender.NavigationToActivation{PreloadingTriggerType}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>nhiroki@chromium.org</owner>
   <owner>src/content/browser/preloading/prerender/OWNERS</owner>
   <summary>
@@ -2230,7 +2230,7 @@
 
 <histogram
     name="PageLoad.Clients.Prerender.PaintTiming.ActivationToFirstContentfulPaint{PreloadingTriggerType}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>nhiroki@chromium.org</owner>
   <owner>src/content/browser/preloading/prerender/OWNERS</owner>
   <summary>
@@ -2245,7 +2245,7 @@
 
 <histogram
     name="PageLoad.Clients.Prerender.PaintTiming.ActivationToFirstPaint{PreloadingTriggerType}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>nhiroki@chromium.org</owner>
   <owner>src/content/browser/preloading/prerender/OWNERS</owner>
   <summary>
@@ -2259,7 +2259,7 @@
 
 <histogram
     name="PageLoad.Clients.Prerender.PaintTiming.ActivationToLargestContentfulPaint2{PreloadingTriggerType}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>nhiroki@chromium.org</owner>
   <owner>src/content/browser/preloading/prerender/OWNERS</owner>
   <summary>
@@ -2436,7 +2436,7 @@
 </histogram>
 
 <histogram name="PageLoad.Clients.TPCD.AdTPCAccess.BlockedByExperiment2"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>victortan@chromium.org</owner>
   <owner>src/chrome/browser/tpcd/OWNERS</owner>
   <summary>
@@ -2449,7 +2449,7 @@
 
 <histogram
     name="PageLoad.Clients.TPCD.CookieAccess.ThirdPartyCookieAllowMechanism3"
-    enum="ThirdPartyCookieAllowMechanism" expires_after="2025-09-14">
+    enum="ThirdPartyCookieAllowMechanism" expires_after="2025-11-16">
   <owner>victortan@chromium.org</owner>
   <owner>src/chrome/browser/tpcd/OWNERS</owner>
   <summary>
@@ -2464,7 +2464,7 @@
 
 <histogram
     name="PageLoad.Clients.TPCD.ThirdPartyCookieAccessBlockedByExperiment2"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>victortan@chromium.org</owner>
   <owner>src/chrome/browser/tpcd/OWNERS</owner>
   <summary>
@@ -2490,7 +2490,7 @@
 </histogram>
 
 <histogram name="PageLoad.Clients.TPCD.TPCAccess.CookieReadStatus2"
-    enum="CookieReadStatus" expires_after="2025-09-14">
+    enum="CookieReadStatus" expires_after="2025-11-16">
   <owner>linnan@chromium.org</owner>
   <owner>src/chrome/browser/tpcd/OWNERS</owner>
   <summary>
@@ -2829,7 +2829,7 @@
 </histogram>
 
 <histogram name="PageLoad.Cpu.TotalUsageForegrounded" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>alexmt@chromium.org</owner>
   <owner>chrome-ads-histograms@google.com</owner>
   <summary>
@@ -2862,7 +2862,7 @@
 </histogram>
 
 <histogram name="PageLoad.Experimental.ClickInputBurst" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dougarnett@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <owner>sullivan@chromium.org</owner>
@@ -3251,7 +3251,7 @@
 </histogram>
 
 <histogram name="PageLoad.Experimental.TotalForegroundDuration{PageVisitType}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>npm@chromium.org</owner>
   <owner>toyoshim@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
@@ -4183,7 +4183,7 @@
 </histogram>
 
 <histogram name="PageLoad.PaintTiming.NavigationToFirstImagePaint" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>sullivan@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
@@ -4270,7 +4270,7 @@
 </histogram>
 
 <histogram name="PageLoad.PaintTiming.NavigationToLargestContentfulPaint2"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>iclelland@chromium.org</owner>
   <owner>sullivan@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
@@ -4365,7 +4365,7 @@
 
 <histogram
     name="PageLoad.PaintTiming.NavigationToLargestContentfulPaint2.MainFrame"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>iclelland@chromium.org</owner>
   <owner>sullivan@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
@@ -4394,7 +4394,7 @@
 
 <histogram
     name="PageLoad.PaintTiming.NavigationToLargestContentfulPaint2.SetSpeculationRulesPrerender"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>yoichio@chromium.org</owner>
   <owner>loading-dev@chromium.org</owner>
   <summary>
@@ -4459,7 +4459,7 @@
 </histogram>
 
 <histogram name="PageLoad.PaintTiming.ParseStartToFirstContentfulPaint"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>bmcquade@chromium.org</owner>
   <owner>csharrison@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml
index 79b541e..ece1e63 100644
--- a/tools/metrics/histograms/metadata/password/histograms.xml
+++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -396,7 +396,7 @@
 </histogram>
 
 <histogram name="PasswordGeneration.GeneratedPasswordWasEdited"
-    enum="BooleanGeneratedPasswordWasEdited" expires_after="2025-09-14">
+    enum="BooleanGeneratedPasswordWasEdited" expires_after="2025-11-16">
   <owner>kazinova@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -419,7 +419,7 @@
 </histogram>
 
 <histogram name="PasswordGeneration.iOS.AcceptedGeneratedPasswordSource"
-    enum="AcceptedGeneratedPasswordSourceType" expires_after="2025-09-14">
+    enum="AcceptedGeneratedPasswordSourceType" expires_after="2025-11-16">
   <owner>cloutierc@google.com</owner>
   <owner>vincb@google.com</owner>
   <owner>bling-transactions@google.com</owner>
@@ -475,7 +475,7 @@
 </histogram>
 
 <histogram name="PasswordGeneration.SubmissionEvent"
-    enum="PasswordSubmissionEvent" expires_after="2025-09-14">
+    enum="PasswordSubmissionEvent" expires_after="2025-11-16">
   <owner>kazinova@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -529,7 +529,7 @@
 
 <histogram
     name="PasswordManager.AccountStorage.MoveToAccountStoreFlowAccepted2"
-    enum="PasswordManager.MoveToAccountStoreTrigger" expires_after="2025-09-14">
+    enum="PasswordManager.MoveToAccountStoreTrigger" expires_after="2025-11-16">
   <owner>treib@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
   <summary>
@@ -542,7 +542,7 @@
 </histogram>
 
 <histogram name="PasswordManager.AccountStorage.MoveToAccountStoreFlowOffered"
-    enum="PasswordManager.MoveToAccountStoreTrigger" expires_after="2025-09-14">
+    enum="PasswordManager.MoveToAccountStoreTrigger" expires_after="2025-11-16">
   <owner>treib@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
   <summary>
@@ -554,7 +554,7 @@
 
 <histogram
     name="PasswordManager.AccountStorage.UnsyncedPasswordsFoundDuringSignOut"
-    units="passwords" expires_after="2025-09-14">
+    units="passwords" expires_after="2025-11-16">
   <owner>treib@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
   <summary>
@@ -566,7 +566,7 @@
 
 <histogram
     name="PasswordManager.AccountStorageUserStateDuration{UserSyncingType}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -717,7 +717,7 @@
 </histogram>
 
 <histogram name="PasswordManager.AffiliationDatabase.DatabaseSize" units="KB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>vsemeniuk@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -932,7 +932,7 @@
 </histogram>
 
 <histogram name="PasswordManager.BiometricAuthBeforeFillingEnabled2"
-    enum="BooleanEnabled" expires_after="2025-09-14">
+    enum="BooleanEnabled" expires_after="2025-11-16">
   <owner>kazinova@google.com</owner>
   <owner>vsemeniuk@google.com</owner>
   <summary>
@@ -1101,7 +1101,7 @@
 </histogram>
 
 <histogram name="PasswordManager.BulkCheck.UserAction"
-    enum="PasswordCheckInteraction" expires_after="2025-09-14">
+    enum="PasswordCheckInteraction" expires_after="2025-11-16">
   <owner>vsemeniuk@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -1293,7 +1293,7 @@
 </histogram>
 
 <histogram name="PasswordManager.CompromisedCredentials3.{Issue}"
-    units="credentials" expires_after="2025-09-14">
+    units="credentials" expires_after="2025-11-16">
   <owner>vasilii@chromium.org</owner>
   <owner>vsemeniuk@google.com</owner>
   <summary>
@@ -1306,7 +1306,7 @@
 </histogram>
 
 <histogram name="PasswordManager.CredentialEntryActions.{CredentialEntryType}"
-    enum="CredentialEntryAction" expires_after="2025-07-06">
+    enum="CredentialEntryAction" expires_after="2025-11-16">
   <owner>ioanap@chromium.org</owner>
   <owner>friedrichh@chromium.org</owner>
   <summary>
@@ -1483,7 +1483,7 @@
 </histogram>
 
 <histogram name="PasswordManager.EnableState" enum="PasswordManagerEnableState"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>markusheintz@google.com</owner>
   <owner>mamir@chromium.org</owner>
   <summary>
@@ -1495,7 +1495,7 @@
 
 <histogram
     name="PasswordManager.ErrorMessageDismissalReason.{ErrorMessageType}"
-    enum="MessageDismissReason" expires_after="2025-09-14">
+    enum="MessageDismissReason" expires_after="2025-11-16">
   <owner>izuzic@google.com</owner>
   <owner>ioanap@chromium.org</owner>
   <summary>
@@ -1524,7 +1524,7 @@
 </histogram>
 
 <histogram name="PasswordManager.ErrorMessageDisplayReason"
-    enum="PasswordStoreBackendErrorType" expires_after="2025-09-14">
+    enum="PasswordStoreBackendErrorType" expires_after="2025-11-16">
   <owner>izuzic@google.com</owner>
   <owner>ioanap@chromium.org</owner>
   <summary>
@@ -1596,7 +1596,7 @@
 </histogram>
 
 <histogram name="PasswordManager.FillingAssistanceForSingleUsername"
-    enum="SingleUsernameFillingAssistance" expires_after="2025-09-14">
+    enum="SingleUsernameFillingAssistance" expires_after="2025-11-16">
   <owner>vincb@google.com</owner>
   <owner>eic@google.com</owner>
   <owner>bling-transactions@google.com</owner>
@@ -1660,7 +1660,7 @@
 </histogram>
 
 <histogram name="PasswordManager.FillingSource"
-    enum="PasswordManagerFillingSource" expires_after="2025-09-14">
+    enum="PasswordManagerFillingSource" expires_after="2025-11-16">
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -1682,7 +1682,7 @@
 </histogram>
 
 <histogram name="PasswordManager.FillSuggestionsGroupedMatchAccepted"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>atsvirchkova@google.com</owner>
   <owner>src/components/password_manager/OWNERS</owner>
   <summary>
@@ -1693,7 +1693,7 @@
 </histogram>
 
 <histogram name="PasswordManager.FillSuggestionsHasGroupedMatch" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>atsvirchkova@google.com</owner>
   <owner>src/components/password_manager/OWNERS</owner>
   <summary>
@@ -1830,7 +1830,7 @@
 </histogram>
 
 <histogram name="PasswordManager.Import.DesktopInteractions"
-    enum="PasswordsImportDesktopInteractions" expires_after="2025-09-14">
+    enum="PasswordsImportDesktopInteractions" expires_after="2025-11-16">
   <owner>natiahlyi@google.com</owner>
   <owner>markusheintz@google.com</owner>
   <summary>
@@ -2092,7 +2092,7 @@
 </histogram>
 
 <histogram name="PasswordManager.LeakDetection.AnalyzeSingleLeakResponseResult"
-    enum="PasswordAnalyzeLeakResponseResult" expires_after="2025-09-14">
+    enum="PasswordAnalyzeLeakResponseResult" expires_after="2025-11-16">
   <owner>vsemeniuk@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>Result of analyzing a single leak response.</summary>
@@ -2124,7 +2124,7 @@
 </histogram>
 
 <histogram name="PasswordManager.LeakDetection.Error"
-    enum="PasswordLeakDetectionError" expires_after="2025-09-14">
+    enum="PasswordLeakDetectionError" expires_after="2025-11-16">
   <owner>vsemeniuk@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -2281,7 +2281,7 @@
 </histogram>
 
 <histogram name="PasswordManager.LoginDatabaseInit2"
-    enum="LoginDatabaseInitError" expires_after="2025-09-14">
+    enum="LoginDatabaseInitError" expires_after="2025-11-16">
   <owner>vasilii@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
   <summary>
@@ -2452,7 +2452,7 @@
 </histogram>
 
 <histogram name="PasswordManager.MoveUIDismissalReason{UserSyncingType}"
-    enum="PasswordManagerUIDismissalReason" expires_after="2025-08-24">
+    enum="PasswordManagerUIDismissalReason" expires_after="2025-11-16">
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -2465,7 +2465,7 @@
 
 <histogram
     name="PasswordManager.NewlySavedPasswordHasEmptyUsername.{PasswordType}"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>kazinova@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <owner>chrome-password-manager-metrics-alerts@google.com</owner>
@@ -2477,7 +2477,7 @@
 </histogram>
 
 <histogram name="PasswordManager.NonSyncPasswordHashChange"
-    enum="GaiaPasswordHashChange" expires_after="2025-09-14">
+    enum="GaiaPasswordHashChange" expires_after="2025-11-16">
   <owner>nwokedi@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -2499,7 +2499,7 @@
 </histogram>
 
 <histogram name="PasswordManager.OpenedAsShortcut" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>vasilii@chromium.org</owner>
   <owner>vsemeniuk@google.com</owner>
   <summary>
@@ -2566,7 +2566,7 @@
 </histogram>
 
 <histogram name="PasswordManager.Parsing.UnrelatedFields.AnyFieldIsMasked"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>kazinova@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -2612,7 +2612,7 @@
 
 <histogram
     name="PasswordManager.PasswordAccessLossWarningDialog{AccessLossWarningType}.UserAction"
-    enum="PasswordAccessLossWarningUserActions" expires_after="2025-09-14">
+    enum="PasswordAccessLossWarningUserActions" expires_after="2025-11-16">
   <owner>izuzic@google.com</owner>
   <owner>atsvirchkova@google.com</owner>
   <summary>
@@ -2625,7 +2625,7 @@
 
 <histogram
     name="PasswordManager.PasswordAccessLossWarningExportFlow.{AccessLossWarningType}.FinalStep"
-    enum="PasswordAccessLossWarningExportStep" expires_after="2025-08-10">
+    enum="PasswordAccessLossWarningExportStep" expires_after="2025-11-16">
   <owner>izuzic@google.com</owner>
   <owner>atsvirchkova@google.com</owner>
   <summary>
@@ -2637,7 +2637,7 @@
 
 <histogram
     name="PasswordManager.PasswordAccessLossWarningSheet.{AccessLossWarningType}.UserAction"
-    enum="PasswordAccessLossWarningUserActions" expires_after="2025-09-14">
+    enum="PasswordAccessLossWarningUserActions" expires_after="2025-11-16">
   <owner>izuzic@google.com</owner>
   <owner>atsvirchkova@google.com</owner>
   <summary>
@@ -2650,7 +2650,7 @@
 
 <histogram
     name="PasswordManager.PasswordAccessLossWarningSheet{AccessLossWarningType}Trigger"
-    enum="PasswordAccessLossWarningTriggers" expires_after="2025-09-14">
+    enum="PasswordAccessLossWarningTriggers" expires_after="2025-11-16">
   <owner>izuzic@google.com</owner>
   <owner>atsvirchkova@google.com</owner>
   <summary>
@@ -2774,7 +2774,7 @@
 </histogram>
 
 <histogram name="PasswordManager.PasswordCheckup.Launch.Success"
-    enum="BooleanSuccess" expires_after="2025-09-14">
+    enum="BooleanSuccess" expires_after="2025-11-16">
   <owner>ioanap@chromium.org</owner>
   <owner>vsemeniuk@google.com</owner>
   <summary>
@@ -2842,7 +2842,7 @@
 </histogram>
 
 <histogram name="PasswordManager.PasswordCheckup.{Operation}.Success"
-    enum="BooleanSuccess" expires_after="2025-09-14">
+    enum="BooleanSuccess" expires_after="2025-11-16">
   <owner>ioanap@chromium.org</owner>
   <owner>izuzic@google.com</owner>
   <summary>
@@ -2862,7 +2862,7 @@
 </histogram>
 
 <histogram name="PasswordManager.PasswordDropdownShown"
-    enum="PasswordDropdownState" expires_after="2025-09-14">
+    enum="PasswordDropdownState" expires_after="2025-11-16">
   <owner>kazinova@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>Logs the state of the password dropdown when it's shown.</summary>
@@ -2870,7 +2870,7 @@
 
 <histogram
     name="PasswordManager.PasswordDropdownShown.NonWebAuthnRequest.TotalCount"
-    units="credentials" expires_after="2025-09-14">
+    units="credentials" expires_after="2025-11-16">
   <owner>derinel@google.com</owner>
   <owner>markusheintz@google.com</owner>
   <summary>
@@ -2880,7 +2880,7 @@
 </histogram>
 
 <histogram name="PasswordManager.PasswordDropdownShown.TotalCount"
-    units="credentials" expires_after="2025-09-14">
+    units="credentials" expires_after="2025-11-16">
   <owner>derinel@google.com</owner>
   <owner>markusheintz@google.com</owner>
   <summary>
@@ -2891,7 +2891,7 @@
 
 <histogram
     name="PasswordManager.PasswordDropdownShown.WebAuthnRequest.PasskeyCount"
-    units="credentials" expires_after="2025-09-14">
+    units="credentials" expires_after="2025-11-16">
   <owner>derinel@google.com</owner>
   <owner>markusheintz@google.com</owner>
   <summary>
@@ -2902,7 +2902,7 @@
 
 <histogram
     name="PasswordManager.PasswordDropdownShown.WebAuthnRequest.PasswordCount"
-    units="credentials" expires_after="2025-09-14">
+    units="credentials" expires_after="2025-11-16">
   <owner>derinel@google.com</owner>
   <owner>markusheintz@google.com</owner>
   <summary>
@@ -2913,7 +2913,7 @@
 
 <histogram
     name="PasswordManager.PasswordDropdownShown.WebAuthnRequest.TotalCount"
-    units="credentials" expires_after="2025-09-14">
+    units="credentials" expires_after="2025-11-16">
   <owner>derinel@google.com</owner>
   <owner>markusheintz@google.com</owner>
   <summary>
@@ -2925,7 +2925,7 @@
 
 <histogram
     name="PasswordManager.PasswordDropdownShown.WebAuthnRequest.UseAnotherDeviceShown"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>derinel@google.com</owner>
   <owner>markusheintz@google.com</owner>
   <summary>
@@ -2982,7 +2982,7 @@
 </histogram>
 
 <histogram name="PasswordManager.PasswordReuse.NumberOfMatches"
-    units="credentials" expires_after="2025-09-14">
+    units="credentials" expires_after="2025-11-16">
   <owner>nwokedi@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -3460,7 +3460,7 @@
 
 <histogram
     name="PasswordManager.PasswordStoreAndroidBackend{Function}.APIError"
-    enum="PasswordStoreAndroidBackendAPIError" expires_after="2025-09-14">
+    enum="PasswordStoreAndroidBackendAPIError" expires_after="2025-11-16">
   <owner>maxan@chromium.org</owner>
   <owner>ioanap@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
@@ -3516,7 +3516,7 @@
 
 <histogram
     name="PasswordManager.PasswordStoreAndroidBackend{Function}.ErrorCode"
-    enum="PasswordStoreAndroidBackendError" expires_after="2025-09-14">
+    enum="PasswordStoreAndroidBackendError" expires_after="2025-11-16">
   <owner>maxan@chromium.org</owner>
   <owner>ioanap@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
@@ -3580,7 +3580,7 @@
 </histogram>
 
 <histogram name="PasswordManager.PasswordStore{Backend}.{Function}"
-    enum="PasswordStoreAndroidBackendRequestStatus" expires_after="2025-09-14">
+    enum="PasswordStoreAndroidBackendRequestStatus" expires_after="2025-11-16">
   <owner>maxan@chromium.org</owner>
   <owner>ioanap@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
@@ -3601,7 +3601,7 @@
 </histogram>
 
 <histogram name="PasswordManager.PasswordStore{Backend}.{Function}.Latency"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>maxan@chromium.org</owner>
   <owner>ioanap@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
@@ -3621,7 +3621,7 @@
 </histogram>
 
 <histogram name="PasswordManager.PasswordStore{Backend}.{Function}.Success"
-    enum="BooleanSuccess" expires_after="2025-09-14">
+    enum="BooleanSuccess" expires_after="2025-11-16">
   <owner>maxan@chromium.org</owner>
   <owner>ioanap@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
@@ -3652,7 +3652,7 @@
 </histogram>
 
 <histogram name="PasswordManager.PasswordViewPage.UserActions"
-    enum="PasswordViewPageInteractions" expires_after="2025-09-14">
+    enum="PasswordViewPageInteractions" expires_after="2025-11-16">
   <owner>derinel@google.com</owner>
   <owner>mamir@chromium.org</owner>
   <summary>
@@ -3888,7 +3888,7 @@
 </histogram>
 
 <histogram name="PasswordManager.SaveUIDismissalReason{UserSyncingType}"
-    enum="PasswordManagerUIDismissalReason" expires_after="2025-09-14">
+    enum="PasswordManagerUIDismissalReason" expires_after="2025-11-16">
   <owner>vasilii@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
@@ -3902,7 +3902,7 @@
 </histogram>
 
 <histogram name="PasswordManager.SavingOnUsernameFirstFlow"
-    enum="SavingOnUsernameFirstFlow" expires_after="2025-09-14">
+    enum="SavingOnUsernameFirstFlow" expires_after="2025-11-16">
   <owner>kazinova@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -4081,7 +4081,7 @@
 </histogram>
 
 <histogram name="PasswordManager.SubmittedFormType2" enum="PasswordFormType2"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kazinova@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <owner>chrome-password-manager-metrics-alerts@google.com</owner>
@@ -4336,7 +4336,7 @@
 </histogram>
 
 <histogram name="PasswordManager.UIDismissalReason"
-    enum="PasswordManagerUIDismissalReason" expires_after="2025-09-14">
+    enum="PasswordManagerUIDismissalReason" expires_after="2025-11-16">
   <owner>vasilii@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
   <summary>
@@ -4618,7 +4618,7 @@
 </histogram>
 
 <histogram name="PasswordManager.UsernameDetectionMethod"
-    enum="UsernameDetectionMethod" expires_after="2025-09-14">
+    enum="UsernameDetectionMethod" expires_after="2025-11-16">
   <owner>kazinova@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -4668,7 +4668,7 @@
 </histogram>
 
 <histogram name="PasswordManager.WellKnownChangePasswordResult"
-    enum="WellKnownChangePasswordResult" expires_after="2025-09-14">
+    enum="WellKnownChangePasswordResult" expires_after="2025-11-16">
   <owner>kazinova@google.com</owner>
   <owner>jkeitel@google.com</owner>
   <summary>
@@ -4696,7 +4696,7 @@
 </histogram>
 
 <histogram name="PasswordManager.{Location}.AuthenticationResult"
-    enum="BooleanSuccess" expires_after="2025-09-14">
+    enum="BooleanSuccess" expires_after="2025-11-16">
   <owner>vsemeniuk@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -4744,7 +4744,7 @@
 
 <histogram
     name="PasswordManager.{Store}BlacklistedSitesHiRes3{CustomPassphraseStatus}"
-    units="sites" expires_after="2025-09-14">
+    units="sites" expires_after="2025-11-16">
   <owner>kazinova@google.com</owner>
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
@@ -4759,7 +4759,7 @@
 </histogram>
 
 <histogram name="PasswordManager.{Store}InaccessiblePasswords3"
-    units="saved passwords" expires_after="2025-09-14">
+    units="saved passwords" expires_after="2025-11-16">
   <owner>derinel@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
@@ -4775,7 +4775,7 @@
 </histogram>
 
 <histogram name="PasswordManager.{Store}LoginDatabaseEncryptionStatus"
-    enum="LoginDatabaseEncryptionStatus" expires_after="2025-09-14">
+    enum="LoginDatabaseEncryptionStatus" expires_after="2025-11-16">
   <owner>derinel@google.com</owner>
   <owner>mamir@chromium.org</owner>
   <summary>
@@ -4872,7 +4872,7 @@
 
 <histogram
     name="PasswordManager.{Store}TimesPasswordUsed3.{PasswordType}{CustomPassphraseStatus}"
-    units="PasswordUses" expires_after="2025-09-14">
+    units="PasswordUses" expires_after="2025-11-16">
   <owner>kazinova@google.com</owner>
   <owner>battre@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
@@ -4890,7 +4890,7 @@
 </histogram>
 
 <histogram name="PasswordManager.{Store}TotalAccountsHiRes3.WithScheme{Scheme}"
-    units="accounts" expires_after="2025-09-14">
+    units="accounts" expires_after="2025-11-16">
   <owner>battre@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
@@ -4907,7 +4907,7 @@
 
 <histogram
     name="PasswordManager.{Store}{Metric3}.{PasswordType}{CustomPassphraseStatus}{StoreErrorStatus}"
-    units="units" expires_after="2025-09-14">
+    units="units" expires_after="2025-11-16">
   <owner>kazinova@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/payment/histograms.xml b/tools/metrics/histograms/metadata/payment/histograms.xml
index 44c0ac5..3ab48f43 100644
--- a/tools/metrics/histograms/metadata/payment/histograms.xml
+++ b/tools/metrics/histograms/metadata/payment/histograms.xml
@@ -23,7 +23,7 @@
 <histograms>
 
 <histogram name="PaymentRequest.AddressEditorTrigerred"
-    enum="PaymentRequestAddressEditorMode" expires_after="2025-08-28">
+    enum="PaymentRequestAddressEditorMode" expires_after="2025-11-16">
   <owner>vykochko@chromium.org</owner>
   <owner>smcgruer@google.com</owner>
   <owner>payments-autofill-team@google.com</owner>
@@ -48,7 +48,7 @@
 </histogram>
 
 <histogram name="PaymentRequest.CheckoutFunnel"
-    enum="PaymentRequestCheckoutFunnelSteps" expires_after="2025-09-14">
+    enum="PaymentRequestCheckoutFunnelSteps" expires_after="2025-11-16">
   <owner>rouslan@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/pdf/histograms.xml b/tools/metrics/histograms/metadata/pdf/histograms.xml
index a0c23ab..03c57ee7 100644
--- a/tools/metrics/histograms/metadata/pdf/histograms.xml
+++ b/tools/metrics/histograms/metadata/pdf/histograms.xml
@@ -249,7 +249,7 @@
 </histogram>
 
 <histogram name="PDF.RenderAndPaintVisiblePagesTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>nigi@chromium.org</owner>
   <owner>thestig@chromium.org</owner>
   <summary>
@@ -279,7 +279,7 @@
   </summary>
 </histogram>
 
-<histogram name="PDF.Version" enum="PDFVersion" expires_after="2025-09-14">
+<histogram name="PDF.Version" enum="PDFVersion" expires_after="2025-11-16">
   <owner>dhoss@chromium.org</owner>
   <owner>thestig@chromium.org</owner>
   <summary>Tracks versions of documents opened in the PDF viewer.</summary>
diff --git a/tools/metrics/histograms/metadata/performance_manager/histograms.xml b/tools/metrics/histograms/metadata/performance_manager/histograms.xml
index 665cb9c..122cb6b 100644
--- a/tools/metrics/histograms/metadata/performance_manager/histograms.xml
+++ b/tools/metrics/histograms/metadata/performance_manager/histograms.xml
@@ -90,7 +90,7 @@
 </histogram>
 
 <histogram name="CPU.Experimental.CpuEstimationThreadTimePercent.{CoreType}"
-    units="%" expires_after="2025-09-14">
+    units="%" expires_after="2025-11-16">
   <owner>anthonyvd@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -185,7 +185,7 @@
 </histogram>
 
 <histogram name="PerformanceManager.Experimental.AccessibilityModeFlag"
-    enum="AccessibilityModeFlagEnum" expires_after="2025-09-14">
+    enum="AccessibilityModeFlagEnum" expires_after="2025-11-16">
   <owner>anthonyvd@chromium.org</owner>
   <owner>chrome-catan@google.com</owner>
   <summary>
@@ -195,7 +195,7 @@
 </histogram>
 
 <histogram name="PerformanceManager.Experimental.HasAccessibilityModeFlag"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>anthonyvd@chromium.org</owner>
   <owner>chrome-catan@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/permissions/histograms.xml b/tools/metrics/histograms/metadata/permissions/histograms.xml
index 084631ee..fdde7c4 100644
--- a/tools/metrics/histograms/metadata/permissions/histograms.xml
+++ b/tools/metrics/histograms/metadata/permissions/histograms.xml
@@ -604,7 +604,7 @@
 </histogram>
 
 <histogram name="Permissions.CrowdDeny.PreloadData.DelayedPushNotification"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>elklm@chromium.org</owner>
   <owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
   <summary>
@@ -619,7 +619,7 @@
 </histogram>
 
 <histogram name="Permissions.CrowdDeny.PreloadData.NotificationUxQuality"
-    enum="CrowdDenyNotificationUxQuality" expires_after="2025-09-14">
+    enum="CrowdDenyNotificationUxQuality" expires_after="2025-11-16">
   <owner>andypaicu@chromium.org</owner>
   <owner>engedy@chromium.org</owner>
   <owner>hkamila@chromium.org</owner>
@@ -652,7 +652,7 @@
 </histogram>
 
 <histogram name="Permissions.CrowdDeny.SafeBrowsing.Verdict"
-    enum="CrowdDenySafeBrowsingVerdict" expires_after="2025-09-14">
+    enum="CrowdDenySafeBrowsingVerdict" expires_after="2025-11-16">
   <owner>engedy@chromium.org</owner>
   <owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
   <summary>
@@ -955,7 +955,7 @@
 </histogram>
 
 <histogram name="Permissions.PredictionService.PredictionSource"
-    enum="PermissionPredictionSource" expires_after="2025-09-14">
+    enum="PermissionPredictionSource" expires_after="2025-11-16">
   <owner>ravjit@chromium.org</owner>
   <owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
   <summary>
@@ -966,7 +966,7 @@
 </histogram>
 
 <histogram name="Permissions.PredictionService.Response.{PermissionType}"
-    enum="BooleanIgnored" expires_after="2025-09-14">
+    enum="BooleanIgnored" expires_after="2025-11-16">
   <owner>ravjit@chromium.org</owner>
   <owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
   <summary>
@@ -1273,7 +1273,7 @@
 
 <histogram
     name="Permissions.Prompt.{PermissionType}.BrowserAlwaysActiveWhileShowing"
-    enum="Boolean" expires_after="2025-08-15">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>tungnh@chromium.org</owner>
   <owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
   <summary>
@@ -1371,7 +1371,7 @@
 </histogram>
 
 <histogram name="Permissions.Prompt.{PermissionType}.ShownInActiveBrowser"
-    enum="Boolean" expires_after="2025-08-15">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>tungnh@chromium.org</owner>
   <owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
   <summary>
@@ -1400,7 +1400,7 @@
 </histogram>
 
 <histogram name="Permissions.Prompt.{PermissionType}.{Disposition}.Action"
-    enum="PermissionAction" expires_after="2025-09-14">
+    enum="PermissionAction" expires_after="2025-11-16">
   <owner>elklm@chromium.org</owner>
   <owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
   <summary>
@@ -1838,7 +1838,7 @@
 </histogram>
 
 <histogram name="SiteEngagementService.EngagementScore" units="units"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>calamity@chromium.org</owner>
   <owner>dominickn@chromium.org</owner>
   <summary>
@@ -1859,7 +1859,7 @@
 </histogram>
 
 <histogram name="SiteEngagementService.MeanEngagement" units="units"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jdeblasio@chromium.org</owner>
   <owner>chrome-secure-web-and-net@chromium.org</owner>
   <summary>
@@ -1873,7 +1873,7 @@
 </histogram>
 
 <histogram name="SiteEngagementService.MedianEngagement" units="units"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>calamity@chromium.org</owner>
   <owner>dominickn@chromium.org</owner>
   <summary>
@@ -1884,7 +1884,7 @@
 </histogram>
 
 <histogram name="SiteEngagementService.OriginsEngaged" units="units"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>calamity@chromium.org</owner>
   <owner>dominickn@chromium.org</owner>
   <summary>
@@ -1908,7 +1908,7 @@
 </histogram>
 
 <histogram name="WebsiteSettings.Action" enum="WebsiteSettingsAction"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>estark@chromium.org</owner>
   <owner>dullweber@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/platform/histograms.xml b/tools/metrics/histograms/metadata/platform/histograms.xml
index 3d7a393..084beb3 100644
--- a/tools/metrics/histograms/metadata/platform/histograms.xml
+++ b/tools/metrics/histograms/metadata/platform/histograms.xml
@@ -71,7 +71,7 @@
 </histogram>
 
 <histogram name="Platform.BootMode.FirmwareWriteProtect.{FirmwareType}"
-    enum="Platform.BootMode.FirmwareWriteProtect" expires_after="2025-09-14">
+    enum="Platform.BootMode.FirmwareWriteProtect" expires_after="2025-11-16">
   <owner>enlightened@chromium.org</owner>
   <owner>chromeos-hardening@google.com</owner>
   <summary>
@@ -89,7 +89,7 @@
 </histogram>
 
 <histogram name="Platform.BootMode.WriteProtectSwitch"
-    enum="Platform.BootMode.SwitchStatus" expires_after="2025-09-14">
+    enum="Platform.BootMode.SwitchStatus" expires_after="2025-11-16">
   <owner>enlightened@chromium.org</owner>
   <owner>chromeos-hardening@google.com</owner>
   <summary>
@@ -166,7 +166,7 @@
 </histogram>
 
 <histogram name="Platform.Chaps.TokenManager.UnloadToken"
-    enum="TokenManagerStatus" expires_after="2025-09-14">
+    enum="TokenManagerStatus" expires_after="2025-11-16">
   <owner>chenyian@google.com</owner>
   <owner>cros-hwsec-userland-eng+uma@google.com</owner>
   <summary>
@@ -712,7 +712,7 @@
 </histogram>
 
 <histogram name="Platform.DiskUsage.NumUserHomeDirectories"
-    units="home directories" expires_after="2025-09-14">
+    units="home directories" expires_after="2025-11-16">
   <owner>achuith@chromium.org</owner>
   <owner>tls@chromium.org</owner>
   <summary>
@@ -741,7 +741,7 @@
 </histogram>
 
 <histogram name="Platform.DiskUsageChronos" units="KB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>sarthakkukreti@google.com</owner>
   <owner>chromeos-storage@google.com</owner>
   <summary>
@@ -751,7 +751,7 @@
   </summary>
 </histogram>
 
-<histogram name="Platform.DiskUsageVar" units="KB" expires_after="2025-09-14">
+<histogram name="Platform.DiskUsageVar" units="KB" expires_after="2025-11-16">
   <owner>sarthakkukreti@google.com</owner>
   <owner>chromeos-storage@google.com</owner>
   <summary>
@@ -891,7 +891,7 @@
 </histogram>
 
 <histogram name="Platform.FileSystem.{Partition}.fsckResult" enum="FsckResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>gwendal@google.com</owner>
   <owner>chromeos-storage@google.com</owner>
   <summary>
@@ -901,7 +901,7 @@
 </histogram>
 
 <histogram name="Platform.FileSystem.{Partition}_ErrorCount" units="errors"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>gwendal@google.com</owner>
   <owner>chromeos-storage@google.com</owner>
   <summary>
@@ -912,7 +912,7 @@
 </histogram>
 
 <histogram name="Platform.FileSystem.{Partition}_{MountResult}" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>gwendal@google.com</owner>
   <owner>chromeos-storage@google.com</owner>
   <summary>
@@ -953,7 +953,7 @@
 </histogram>
 
 <histogram name="Platform.FlexCpuIsaLevel" enum="FlexCpuIsaLevel"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>nicholasbishop@google.com</owner>
   <owner>chromeos-flex-eng@google.com</owner>
   <summary>
@@ -1115,7 +1115,7 @@
 </histogram>
 
 <histogram name="Platform.IntelMaxMicroArchitecture"
-    enum="IntelMaxMicroArchitecture" expires_after="2025-09-14">
+    enum="IntelMaxMicroArchitecture" expires_after="2025-11-16">
   <owner>fbarchard@chromium.org</owner>
   <owner>pwnall@chromium.org</owner>
   <summary>
@@ -1271,7 +1271,7 @@
 </histogram>
 
 <histogram name="Platform.Libhwsec.RetryAction{Category}"
-    enum="HwsecRetryActionEnum" expires_after="2025-09-14">
+    enum="HwsecRetryActionEnum" expires_after="2025-11-16">
   <owner>yich@google.com</owner>
   <owner>cros-hwsec-userland-eng+uma@google.com</owner>
   <summary>
@@ -1529,7 +1529,7 @@
 </histogram>
 
 <histogram name="Platform.Memory.ARC{ProcessMemoryType}" units="MiB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bgeffon@chromium.org</owner>
   <owner>khmel@chromium.org</owner>
   <owner>chromeos-memory@google.com</owner>
@@ -1543,7 +1543,7 @@
 </histogram>
 
 <histogram name="Platform.Memory.Browser{ProcessMemoryType}" units="MiB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bgeffon@chromium.org</owner>
   <owner>chromeos-memory@google.com</owner>
   <summary>
@@ -1569,7 +1569,7 @@
 </histogram>
 
 <histogram name="Platform.Memory.Gpu{ProcessMemoryType}" units="MiB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bgeffon@chromium.org</owner>
   <owner>chromeos-memory@google.com</owner>
   <summary>
@@ -1735,7 +1735,7 @@
 </histogram>
 
 <histogram name="Platform.Missive.ClientEnqueueResult"
-    enum="EnterpriseCloudReportingStatusCode" expires_after="2025-09-14">
+    enum="EnterpriseCloudReportingStatusCode" expires_after="2025-11-16">
   <owner>lbaraz@chromium.org</owner>
   <owner>cros-reporting-team@google.com</owner>
   <summary>
@@ -1913,7 +1913,7 @@
 </histogram>
 
 <histogram name="Platform.Modemfwd.DlcInstallResult"
-    enum="ModemfwdDlcInstallResult" expires_after="2025-09-14">
+    enum="ModemfwdDlcInstallResult" expires_after="2025-11-16">
   <owner>andrewlassalle@google.com</owner>
   <owner>ujjwalpande@google.com</owner>
   <summary>
@@ -2263,7 +2263,7 @@
 </histogram>
 
 <histogram name="Platform.StatefulFormat" enum="StatefulFormat"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>sarthakkukreti@chromium.org</owner>
   <owner>gwendal@chromium.org</owner>
   <owner>chromeos-storage@google.com</owner>
@@ -2352,7 +2352,7 @@
 </histogram>
 
 <histogram name="Platform.Storage.Mmc.Internal.{Error}" units="errors"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>korneld@chromium.org</owner>
   <owner>chromeos-devices-team@google.com</owner>
   <summary>
@@ -2399,7 +2399,7 @@
 </histogram>
 
 <histogram name="Platform.StorageCapabilities"
-    enum="InternalStorageCapabilities" expires_after="2025-09-14">
+    enum="InternalStorageCapabilities" expires_after="2025-11-16">
   <owner>dlunev@chromium.org</owner>
   <owner>chromeos-storage@google.com</owner>
   <summary>
@@ -2408,7 +2408,7 @@
   </summary>
 </histogram>
 
-<histogram name="Platform.SwapInDaily" units="pages" expires_after="2025-09-14">
+<histogram name="Platform.SwapInDaily" units="pages" expires_after="2025-11-16">
   <owner>asavery@chromium.org</owner>
   <owner>chromeos-memory@google.com</owner>
   <owner>chromeos-storage@google.com</owner>
@@ -2416,7 +2416,7 @@
 </histogram>
 
 <histogram name="Platform.SwapOutDaily" units="pages"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>asavery@chromium.org</owner>
   <owner>chromeos-memory@google.com</owner>
   <owner>chromeos-storage@google.com</owner>
@@ -2694,7 +2694,7 @@
 </histogram>
 
 <histogram name="Platform.TPM.TimeToTakeOwnership" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>yich@google.com</owner>
   <owner>cros-hwsec+uma@google.com</owner>
   <summary>
@@ -2704,7 +2704,7 @@
 </histogram>
 
 <histogram name="Platform.TPM.TpmManagerSecretStatus"
-    enum="TpmManagerSecretStatus" expires_after="2025-09-14">
+    enum="TpmManagerSecretStatus" expires_after="2025-11-16">
   <owner>yich@google.com</owner>
   <owner>cros-hwsec+uma@google.com</owner>
   <summary>
@@ -2726,7 +2726,7 @@
 </histogram>
 
 <histogram name="Platform.TPM1.CommandAndResponse.{Client}"
-    enum="TPM1CommandAndResponse" expires_after="2025-09-14">
+    enum="TPM1CommandAndResponse" expires_after="2025-11-16">
   <owner>chingkang@chromium.org</owner>
   <owner>cros-hwsec+uma@google.com</owner>
   <summary>
@@ -2748,7 +2748,7 @@
 </histogram>
 
 <histogram name="Platform.TPM2.CommandAndResponse.{Client}"
-    enum="TPM2CommandAndResponse" expires_after="2025-09-14">
+    enum="TPM2CommandAndResponse" expires_after="2025-11-16">
   <owner>chingkang@chromium.org</owner>
   <owner>cros-hwsec+uma@google.com</owner>
   <summary>
@@ -2824,7 +2824,7 @@
 </histogram>
 
 <histogram name="Platform.Trunks.TpmErrorCode" enum="TPMResponseCode"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>yich@google.com</owner>
   <owner>cros-hwsec+uma@google.com</owner>
   <summary>
@@ -2888,7 +2888,7 @@
 </histogram>
 
 <histogram name="Platform.UnaggregatedUsageTime" units="seconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>iby@chromium.org</owner>
   <owner>chromeos-data-eng@google.com</owner>
   <summary>
@@ -3042,7 +3042,7 @@
 </histogram>
 
 <histogram name="Platform.{GSC}.BoardIdFlags" enum="Cr50BoardIdFlags"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>apronin@chromium.org</owner>
   <owner>vbendeb@chromium.org</owner>
   <owner>cros-hwsec+uma@google.com</owner>
@@ -3058,7 +3058,7 @@
 </histogram>
 
 <histogram name="Platform.{GSC}.BoardIdOfRlzMismatch" enum="Cr50CrosRlzCodes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>vbendeb@chromium.org</owner>
   <owner>apronin@chromium.org</owner>
   <owner>cros-hwsec+uma@google.com</owner>
@@ -3107,7 +3107,7 @@
 </histogram>
 
 <histogram name="Platform.{GSC}.RlzOfBoardIdMismatch" enum="Cr50CrosRlzCodes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>vbendeb@chromium.org</owner>
   <owner>apronin@chromium.org</owner>
   <owner>cros-hwsec+uma@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/plus_addresses/histograms.xml b/tools/metrics/histograms/metadata/plus_addresses/histograms.xml
index 0f0212a..69e01ff 100644
--- a/tools/metrics/histograms/metadata/plus_addresses/histograms.xml
+++ b/tools/metrics/histograms/metadata/plus_addresses/histograms.xml
@@ -59,7 +59,7 @@
 </histogram>
 
 <histogram name="PlusAddresses.AffiliationRequest.ResponseTime" units="ms"
-    expires_after="2025-07-27">
+    expires_after="2026-04-30">
   <owner>jkeitel@google.com</owner>
   <owner>vizcay@google.com</owner>
   <summary>
@@ -71,7 +71,7 @@
 </histogram>
 
 <histogram name="PlusAddresses.Blocklist.ParsingResult"
-    enum="PlusAddressBlocklistDataParsingResult" expires_after="2025-10-19">
+    enum="PlusAddressBlocklistDataParsingResult" expires_after="2026-04-30">
   <owner>jkeitel@google.com</owner>
   <owner>vizcay@google.com</owner>
   <owner>mreichhoff@chromium.org</owner>
@@ -82,7 +82,7 @@
 </histogram>
 
 <histogram name="PlusAddresses.NetworkRequest.OauthError"
-    enum="GoogleServiceAuthError" expires_after="2025-08-31">
+    enum="GoogleServiceAuthError" expires_after="2026-04-30">
   <owner>jkeitel@google.com</owner>
   <owner>vizcay@google.com</owner>
   <owner>mreichhoff@chromium.org</owner>
@@ -95,7 +95,7 @@
 </histogram>
 
 <histogram name="PlusAddresses.NetworkRequest.{Type}.Latency" units="ms"
-    expires_after="2025-10-12">
+    expires_after="2026-04-30">
   <owner>jkeitel@google.com</owner>
   <owner>vizcay@google.com</owner>
   <owner>mreichhoff@chromium.org</owner>
@@ -110,7 +110,7 @@
 </histogram>
 
 <histogram name="PlusAddresses.NetworkRequest.{Type}.NetErrorCode"
-    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2025-09-30">
+    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2026-04-30">
   <owner>jkeitel@google.com</owner>
   <owner>vizcay@google.com</owner>
   <owner>fleimgruber@google.com</owner>
@@ -123,7 +123,7 @@
 </histogram>
 
 <histogram name="PlusAddresses.NetworkRequest.{Type}.ResponseByteSize"
-    units="bytes" expires_after="2025-06-30">
+    units="bytes" expires_after="2026-04-30">
   <owner>jkeitel@google.com</owner>
   <owner>vizcay@google.com</owner>
   <owner>mreichhoff@chromium.org</owner>
@@ -136,7 +136,7 @@
 </histogram>
 
 <histogram name="PlusAddresses.NetworkRequest.{Type}.ResponseCode"
-    enum="HttpResponseCode" expires_after="2025-11-02">
+    enum="HttpResponseCode" expires_after="2026-04-30">
   <owner>jkeitel@google.com</owner>
   <owner>vizcay@google.com</owner>
   <owner>mreichhoff@chromium.org</owner>
@@ -149,7 +149,7 @@
 </histogram>
 
 <histogram name="PlusAddresses.Submission{Segment}" enum="PlusAddressOrGaia"
-    expires_after="2025-11-02">
+    expires_after="2026-04-30">
   <owner>jkeitel@google.com</owner>
   <owner>vizcay@google.com</owner>
   <summary>
@@ -182,7 +182,7 @@
 </histogram>
 
 <histogram name="PlusAddresses.Suggestion.Events"
-    enum="PlusAddressSuggestionEvent2" expires_after="2025-10-26">
+    enum="PlusAddressSuggestionEvent2" expires_after="2026-04-30">
   <owner>jkeitel@google.com</owner>
   <owner>vizcay@google.com</owner>
   <owner>mreichhoff@chromium.org</owner>
@@ -196,7 +196,7 @@
 </histogram>
 
 <histogram name="PlusAddresses.{ModalType}.Events"
-    enum="PlusAddressModalEvent2" expires_after="2025-11-02">
+    enum="PlusAddressModalEvent2" expires_after="2026-04-30">
   <owner>jkeitel@google.com</owner>
   <owner>vizcay@google.com</owner>
   <owner>mreichhoff@chromium.org</owner>
@@ -210,7 +210,7 @@
 </histogram>
 
 <histogram name="PlusAddresses.{ModalType}.{Status}.Refreshes"
-    units="refreshes" expires_after="2025-09-14">
+    units="refreshes" expires_after="2026-04-30">
   <owner>jkeitel@google.com</owner>
   <owner>brunobraga@google.com</owner>
   <summary>
@@ -223,7 +223,7 @@
 </histogram>
 
 <histogram name="PlusAddresses.{ModalType}.{Status}.ShownDuration" units="ms"
-    expires_after="2025-09-07">
+    expires_after="2026-04-30">
   <owner>jkeitel@google.com</owner>
   <owner>vizcay@google.com</owner>
   <owner>mreichhoff@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/power/histograms.xml b/tools/metrics/histograms/metadata/power/histograms.xml
index 3b41b8e..ab20341 100644
--- a/tools/metrics/histograms/metadata/power/histograms.xml
+++ b/tools/metrics/histograms/metadata/power/histograms.xml
@@ -381,7 +381,7 @@
 
 <histogram name="PerformanceMonitor.UsageScenario.LongInterval"
     enum="PerformanceMonitor.UsageScenario.LongInterval"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>olivierli@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -744,7 +744,7 @@
 </histogram>
 
 <histogram name="Power.BatteryDischargeRate" units="mW"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>puthik@chromium.org</owner>
   <owner>chromeos-platform-power@google.com</owner>
   <summary>
@@ -1004,7 +1004,7 @@
 </histogram>
 
 <histogram name="Power.CpuTimeSecondsPerProcessType" enum="ProcessType2"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>eseckler@chromium.org</owner>
   <owner>skyostil@chromium.org</owner>
   <owner>woa-performance@google.com</owner>
@@ -1281,7 +1281,7 @@
 </histogram>
 
 <histogram name="Power.ForegroundBatteryDrain.30Seconds{Exclusive}" units="uAh"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>eseckler@chromium.org</owner>
   <owner>skyostil@chromium.org</owner>
   <owner>woa-performance@google.com</owner>
@@ -1327,7 +1327,7 @@
 </histogram>
 
 <histogram name="Power.ForegroundBatteryDrain{Exclusive}" units="0.1 mAh"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>eseckler@chromium.org</owner>
   <owner>skyostil@chromium.org</owner>
   <owner>woa-performance@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/prefetch/histograms.xml b/tools/metrics/histograms/metadata/prefetch/histograms.xml
index 6489bc9..e2ac8a0 100644
--- a/tools/metrics/histograms/metadata/prefetch/histograms.xml
+++ b/tools/metrics/histograms/metadata/prefetch/histograms.xml
@@ -292,7 +292,7 @@
 </histogram>
 
 <histogram name="PrefetchProxy.AfterClick.WasFullRedirectChainServed"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>kouhei@chromium.org</owner>
   <owner>chrome-loading@chromium.org</owner>
   <summary>
@@ -503,7 +503,7 @@
 </histogram>
 
 <histogram name="PrefetchProxy.Prefetch.Mainframe.TotalTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kouhei@chromium.org</owner>
   <owner>chrome-loading@chromium.org</owner>
   <summary>
@@ -579,7 +579,7 @@
 </histogram>
 
 <histogram name="PrefetchProxy.Prefetch.RedirectChainSize" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kouhei@chromium.org</owner>
   <owner>chrome-loading@chromium.org</owner>
   <summary>
@@ -589,7 +589,7 @@
 </histogram>
 
 <histogram name="PrefetchProxy.Prefetch.StreamingURLLoaderFinalStatus"
-    enum="PrefetchStreamingURLLoaderStatus" expires_after="2025-09-14">
+    enum="PrefetchStreamingURLLoaderStatus" expires_after="2025-11-16">
   <owner>kouhei@chromium.org</owner>
   <owner>chrome-loading@chromium.org</owner>
   <summary>
@@ -643,7 +643,7 @@
 </histogram>
 
 <histogram name="PrefetchProxy.Redirect.Result" enum="PrefetchRedirectResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kouhei@chromium.org</owner>
   <owner>chrome-loading@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/printing/histograms.xml b/tools/metrics/histograms/metadata/printing/histograms.xml
index 231965e..9d88ede 100644
--- a/tools/metrics/histograms/metadata/printing/histograms.xml
+++ b/tools/metrics/histograms/metadata/printing/histograms.xml
@@ -53,7 +53,7 @@
 </histogram>
 
 <histogram name="Printing.ConversionSize.PostScript3" units="KB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>thestig@chromium.org</owner>
   <owner>awscreen@chromium.org</owner>
   <summary>
@@ -253,7 +253,7 @@
 </histogram>
 
 <histogram name="Printing.CUPS.PrintDocumentSize" units="KB"
-    expires_after="2025-09-13">
+    expires_after="2025-11-16">
   <owner>bmgordon@chromium.org</owner>
   <owner>project-bolton@google.com</owner>
   <summary>
@@ -273,7 +273,7 @@
 </histogram>
 
 <histogram name="Printing.CUPS.PrinterEditDialogActions"
-    enum="PrinterEditDialogActions" expires_after="2025-09-14">
+    enum="PrinterEditDialogActions" expires_after="2025-11-16">
   <owner>nmuggli@google.com</owner>
   <owner>project-bolton@google.com</owner>
   <summary>
@@ -335,7 +335,7 @@
 </histogram>
 
 <histogram name="Printing.CUPS.PrinterSetupResult.SettingsDiscoveredPrinters"
-    enum="PrinterSetupResult" expires_after="2025-09-14">
+    enum="PrinterSetupResult" expires_after="2025-11-16">
   <owner>gavinwill@chromium.org</owner>
   <owner>bmgordon@chromium.org</owner>
   <owner>src/chromeos/printing/OWNERS</owner>
@@ -743,7 +743,7 @@
 </histogram>
 
 <histogram name="PrintPreview.PrintSettings" enum="PrintSettings"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>thestig@chromium.org</owner>
   <owner>awscreen@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/privacy/histograms.xml b/tools/metrics/histograms/metadata/privacy/histograms.xml
index 617803d..c43800cf 100644
--- a/tools/metrics/histograms/metadata/privacy/histograms.xml
+++ b/tools/metrics/histograms/metadata/privacy/histograms.xml
@@ -162,7 +162,7 @@
 </variants>
 
 <histogram name="Privacy.3PCD.AdsHeuristicAddedToOverrides"
-    enum="AdsHeuristicCookieOverride" expires_after="2025-09-14">
+    enum="AdsHeuristicCookieOverride" expires_after="2025-11-16">
   <owner>linnan@chromium.org</owner>
   <owner>src/chrome/browser/tpcd/OWNERS</owner>
   <summary>
@@ -176,7 +176,7 @@
 </histogram>
 
 <histogram name="Privacy.3PCD.SecCookieDeprecationHeaderStatus"
-    enum="SecCookieDeprecationHeaderStatus" expires_after="2025-09-14">
+    enum="SecCookieDeprecationHeaderStatus" expires_after="2025-11-16">
   <owner>linnan@chromium.org</owner>
   <owner>src/chrome/browser/tpcd/OWNERS</owner>
   <summary>
@@ -324,7 +324,7 @@
 </histogram>
 
 <histogram name="Privacy.DeleteBrowsingData.Dialog"
-    enum="DeleteBrowsingDataDialogAction" expires_after="2025-09-14">
+    enum="DeleteBrowsingDataDialogAction" expires_after="2025-11-16">
   <owner>fsenra@google.com</owner>
   <owner>alimariam@google.com</owner>
   <owner>chrome-browser-privacy-team@google.com</owner>
@@ -413,7 +413,7 @@
 </histogram>
 
 <histogram name="Privacy.DIPS.ClearedSitesCount{DIPSCookieMode}" units="sites"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>liu@chromium.org</owner>
   <owner>src/content/browser/btm/OWNERS</owner>
   <summary>
@@ -438,7 +438,7 @@
 </histogram>
 
 <histogram name="Privacy.DIPS.Database.Operation.{DIPSDatabaseOperation}Time"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>etienneb@chromium.org</owner>
   <owner>jdh@chromium.org</owner>
   <owner>src/content/browser/btm/OWNERS</owner>
@@ -546,7 +546,7 @@
 </histogram>
 
 <histogram name="Privacy.DIPS.Deletion{DIPSCookieMode}"
-    enum="DIPSDeletionAction" expires_after="2025-09-14">
+    enum="DIPSDeletionAction" expires_after="2025-11-16">
   <owner>njeunje@chromium.org</owner>
   <owner>src/content/browser/btm/OWNERS</owner>
   <summary>
@@ -643,7 +643,7 @@
 </histogram>
 
 <histogram name="Privacy.QuickDelete" enum="QuickDeleteAction"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>fsenra@google.com</owner>
   <owner>zalmashni@google.com</owner>
   <owner>chrome-browser-privacy-team@google.com</owner>
@@ -1170,7 +1170,7 @@
 
 <histogram
     name="PrivacySandbox.Attestations.EstimateMemoryUsage.AttestationsMap"
-    units="KB" expires_after="2025-09-14">
+    units="KB" expires_after="2025-11-16">
   <owner>shivanisha@chromium.org</owner>
   <owner>xiaochenzh@chromium.org</owner>
   <summary>
@@ -1228,7 +1228,7 @@
 </histogram>
 
 <histogram name="PrivacySandbox.Attestations.InitializationDuration.Parsing"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>shivanisha@chromium.org</owner>
   <owner>xiaochenzh@chromium.org</owner>
   <summary>
@@ -1253,7 +1253,7 @@
 </histogram>
 
 <histogram name="PrivacySandbox.Attestations.IsSiteAttested.FileSource"
-    enum="PrivacySandboxAttestationsFileSource" expires_after="2025-09-14">
+    enum="PrivacySandboxAttestationsFileSource" expires_after="2025-11-16">
   <owner>shivanisha@chromium.org</owner>
   <owner>xiaochenzh@chromium.org</owner>
   <summary>
@@ -1265,7 +1265,7 @@
 </histogram>
 
 <histogram name="PrivacySandbox.Attestations.IsSiteAttested.FirstCheckTime"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>shivanisha@chromium.org</owner>
   <owner>xiaochenzh@chromium.org</owner>
   <summary>
@@ -1312,7 +1312,7 @@
 </histogram>
 
 <histogram name="PrivacySandbox.Attestations.Parsing.Status"
-    enum="PrivacySandboxAttestationParsingStatus" expires_after="2025-09-14">
+    enum="PrivacySandboxAttestationParsingStatus" expires_after="2025-11-16">
   <owner>shivanisha@chromium.org</owner>
   <owner>xiaochenzh@chromium.org</owner>
   <summary>
@@ -1757,7 +1757,7 @@
 
 <histogram name="PrivacySandbox.PrivateAggregation.Budgeter.RequestResult3"
     enum="PrivacySandboxPrivateAggregationBudgeterRequestResult3"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>alexmt@chromium.org</owner>
   <owner>linnan@chromium.org</owner>
   <summary>
@@ -1891,7 +1891,7 @@
 
 <histogram name="PrivacySandbox.PrivateAggregation.Host.PipeResult"
     enum="PrivacySandboxPrivateAggregationHostPipeResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>alexmt@chromium.org</owner>
   <owner>linnan@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/profile/histograms.xml b/tools/metrics/histograms/metadata/profile/histograms.xml
index d378f89..235764f 100644
--- a/tools/metrics/histograms/metadata/profile/histograms.xml
+++ b/tools/metrics/histograms/metadata/profile/histograms.xml
@@ -47,7 +47,7 @@
 </variants>
 
 <histogram name="Profile.AddNewUser" enum="ProfileAddNewUser"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>rogerta@chromium.org</owner>
   <summary>The frequency of ways that new user profiles are added.</summary>
 </histogram>
@@ -63,7 +63,7 @@
 </histogram>
 
 <histogram name="Profile.AllAccounts.Names" enum="ProfileAllAccountsNames"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>droger@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
@@ -228,7 +228,7 @@
 </histogram>
 
 <histogram name="Profile.Incognito.Lifetime" units="minutes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>rhalavati@chromium.org</owner>
   <owner>chrome-incognito@google.com</owner>
   <summary>
@@ -368,7 +368,7 @@
 </histogram>
 
 <histogram name="Profile.NumberOfActiveProfiles" units="profiles"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>droger@chromium.org</owner>
   <owner>feuunk@chromium.org</owner>
   <summary>
@@ -390,7 +390,7 @@
 </histogram>
 
 <histogram name="Profile.NumberOfManagedProfiles" units="profiles"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>agawronska@chromium.org</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
@@ -404,7 +404,7 @@
 </histogram>
 
 <histogram name="Profile.NumberOfProfiles" units="profiles"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>droger@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
@@ -485,7 +485,7 @@
 </histogram>
 
 <histogram name="Profile.SessionDuration.PerProfile" enum="Profile"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>msarda@chromium.org</owner>
   <owner>alexilin@chromium.org</owner>
   <summary>
@@ -507,7 +507,7 @@
 </histogram>
 
 <histogram name="Profile.State.LastUsed{ProfileStateGroup}" units="days"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>droger@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
@@ -529,7 +529,7 @@
 
 <histogram
     name="Profile.State.UnconsentedPrimaryAccountType{ProfileStateGroup}"
-    enum="ProfileUnconsentedPrimaryAccountType" expires_after="2025-09-14">
+    enum="ProfileUnconsentedPrimaryAccountType" expires_after="2025-11-16">
   <owner>droger@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
@@ -539,7 +539,7 @@
   </summary>
 </histogram>
 
-<histogram name="Profile.TotalSize" units="MB" expires_after="2025-09-14">
+<histogram name="Profile.TotalSize" units="MB" expires_after="2025-11-16">
   <owner>etienneb@chromium.org</owner>
   <owner>gab@chromium.org</owner>
   <summary>Total size of the profile data (excluding sub-folders).</summary>
@@ -706,7 +706,7 @@
 </histogram>
 
 <histogram name="ProfilePicker.FirstRun.ExitStatus" enum="FirstRunExitStatus"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dgn@chromium.org</owner>
   <owner>for-you-fre@google.com</owner>
   <summary>
@@ -787,7 +787,7 @@
 </histogram>
 
 <histogram name="ProfilePicker.StartupMode.{StartupStep}"
-    enum="ProfilePickerStartupProfileMode" expires_after="2025-09-14">
+    enum="ProfilePickerStartupProfileMode" expires_after="2025-11-16">
   <owner>droger@chromium.org</owner>
   <owner>dgn@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -831,7 +831,7 @@
 </histogram>
 
 <histogram name="ProfilePicker.StartupTime.FirstPaint" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>alexilin@chromium.org</owner>
   <owner>dgn@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/quota/histograms.xml b/tools/metrics/histograms/metadata/quota/histograms.xml
index 6826ba7..b13b1f5 100644
--- a/tools/metrics/histograms/metadata/quota/histograms.xml
+++ b/tools/metrics/histograms/metadata/quota/histograms.xml
@@ -53,7 +53,7 @@
 </histogram>
 
 <histogram name="Quota.AvailableDiskSpace2" units="MB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ayui@chromium.org</owner>
   <owner>chrome-owp-storage@google.com</owner>
   <summary>
@@ -353,7 +353,7 @@
   </summary>
 </histogram>
 
-<histogram name="Quota.TotalDiskSpace" units="MB" expires_after="2025-09-14">
+<histogram name="Quota.TotalDiskSpace" units="MB" expires_after="2025-11-16">
   <owner>ayui@chromium.org</owner>
   <owner>chrome-owp-storage@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/renderer/histograms.xml b/tools/metrics/histograms/metadata/renderer/histograms.xml
index 191ef85..ce50240f 100644
--- a/tools/metrics/histograms/metadata/renderer/histograms.xml
+++ b/tools/metrics/histograms/metadata/renderer/histograms.xml
@@ -51,7 +51,7 @@
 </variants>
 
 <histogram name="Renderer.BrowserLaunchToRunLoopStart" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>sky@chromium.org</owner>
   <owner>jam@chromium.org</owner>
   <summary>
@@ -277,7 +277,7 @@
 </histogram>
 
 <histogram name="Renderer.Font.PrimaryFont.DomContentLoaded" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kojii@chromium.org</owner>
   <owner>tkent@chromium.org</owner>
   <owner>layout-dev@chromium.org</owner>
@@ -301,7 +301,7 @@
 </histogram>
 
 <histogram name="Renderer.Font.PrimaryFont.FCP" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kojii@chromium.org</owner>
   <owner>tkent@chromium.org</owner>
   <owner>layout-dev@chromium.org</owner>
@@ -325,7 +325,7 @@
 </histogram>
 
 <histogram name="Renderer.Font.SystemFallback.DomContentLoaded" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kojii@chromium.org</owner>
   <owner>tkent@chromium.org</owner>
   <owner>layout-dev@chromium.org</owner>
@@ -340,7 +340,7 @@
 </histogram>
 
 <histogram name="Renderer.Font.SystemFallback.FCP" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kojii@chromium.org</owner>
   <owner>tkent@chromium.org</owner>
   <owner>layout-dev@chromium.org</owner>
@@ -614,7 +614,7 @@
 </histogram>
 
 <histogram name="RendererScheduler.QueueingDuration.{Priority}Priority"
-    units="microseconds" expires_after="2025-09-14">
+    units="microseconds" expires_after="2025-11-16">
   <owner>szager@chromium.org</owner>
   <owner>paint-dev@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/renderer4/histograms.xml b/tools/metrics/histograms/metadata/renderer4/histograms.xml
index 4169a579..525ed3ba 100644
--- a/tools/metrics/histograms/metadata/renderer4/histograms.xml
+++ b/tools/metrics/histograms/metadata/renderer4/histograms.xml
@@ -193,7 +193,7 @@
 </histogram>
 
 <histogram name="Renderer4.MainThreadGestureScrollReason2"
-    enum="MainThreadScrollingReason2" expires_after="2025-09-14">
+    enum="MainThreadScrollingReason2" expires_after="2025-11-16">
   <owner>flackr@chromium.org</owner>
   <owner>pdr@chromium.org</owner>
   <owner>input-dev@chromium.org</owner>
@@ -212,7 +212,7 @@
 </histogram>
 
 <histogram name="Renderer4.MainThreadWheelScrollReason2"
-    enum="MainThreadScrollingReason2" expires_after="2025-09-14">
+    enum="MainThreadScrollingReason2" expires_after="2025-11-16">
   <owner>flackr@chromium.org</owner>
   <owner>pdr@chromium.org</owner>
   <owner>input-dev@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
index d2c5792..9aebc9f 100644
--- a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
+++ b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
@@ -245,7 +245,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.AndroidTelemetry.ApkDownload.Outcome"
-    enum="ApkDownloadTelemetryOutcome" expires_after="2025-08-31">
+    enum="ApkDownloadTelemetryOutcome" expires_after="2025-11-16">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -340,7 +340,7 @@
 
 <histogram
     name="SafeBrowsing.BrowserThrottle.IntervalBetweenStartAndProcess{ResponseType}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -383,7 +383,7 @@
 
 <histogram
     name="SafeBrowsing.BrowserThrottle.IsCheckCompletedOnProcessResponse"
-    enum="BooleanCompleted" expires_after="2025-09-14">
+    enum="BooleanCompleted" expires_after="2025-11-16">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -699,7 +699,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.CookieAgeHours2" units="hours"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>chlily@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -1617,7 +1617,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.HPRT.BackoffState" enum="BooleanBackoff"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>thefrog@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -1733,7 +1733,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.HPRT.GetCache.Time" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>thefrog@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -1759,7 +1759,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.HPRT.HasOhttpKey" enum="BooleanHasKey"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -1862,7 +1862,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.HPRT.Network.{ResponseSource}Result"
-    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2025-09-14">
+    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2025-11-16">
   <owner>thefrog@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -1920,7 +1920,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.HPRT.OhttpKeyService.HasCachedKey"
-    enum="BooleanHasKey" expires_after="2025-09-14">
+    enum="BooleanHasKey" expires_after="2025-11-16">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -1930,7 +1930,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.HPRT.OhttpKeyService.Network.Result"
-    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2025-09-14">
+    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2025-11-16">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -1940,7 +1940,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.HPRT.OhttpKeyService.Network.Time" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -2341,7 +2341,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.Pref.Enhanced" enum="BooleanEnabled"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>drubery@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -2363,7 +2363,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.Pref.Extended{SafeBrowsingScoutOptInLocations}"
-    enum="BooleanEnabled" expires_after="2025-09-14">
+    enum="BooleanEnabled" expires_after="2025-11-16">
   <owner>vakh@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -2384,7 +2384,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.Pref.General" enum="BooleanEnabled"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>vakh@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -2433,7 +2433,7 @@
 
 <histogram
     name="SafeBrowsing.RendererThrottle.IsCheckCompletedOnProcessResponse"
-    enum="BooleanCompleted" expires_after="2025-09-14">
+    enum="BooleanCompleted" expires_after="2025-11-16">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -2925,7 +2925,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.Settings.UserAction.{AccessPoint}"
-    enum="SafeBrowsingSettingsUserAction" expires_after="2025-09-14">
+    enum="SafeBrowsingSettingsUserAction" expires_after="2025-11-16">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -3128,7 +3128,7 @@
 <histogram
     name="SafeBrowsing.TailoredSecurity.SyncPromptEnabledNotificationResult2"
     enum="SafeBrowsingTailoredSecurityNotificationResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jacastro@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -3141,7 +3141,7 @@
 
 <histogram
     name="SafeBrowsing.TailoredSecurityConsented{Status}{PromptType}Outcome"
-    enum="SafeBrowsingTailoredSecurityOutcome" expires_after="2025-09-14">
+    enum="SafeBrowsingTailoredSecurityOutcome" expires_after="2025-11-16">
   <owner>jacastro@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -3233,7 +3233,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.TokenFetcher.ErrorType"
-    enum="GoogleServiceAuthError" expires_after="2025-09-14">
+    enum="GoogleServiceAuthError" expires_after="2025-11-16">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -3408,7 +3408,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.V4GetHash.Network.Result"
-    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2025-09-14">
+    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2025-11-16">
   <owner>vakh@google.com</owner>
   <owner>kcarattini@google.com</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
@@ -3979,7 +3979,7 @@
 
 <histogram
     name="SafeBrowsing.{CloudOrLocal}DeepScan.{Connector}{Result}.Duration"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>domfc@chromium.org</owner>
   <owner>drubery@chromium.org</owner>
   <owner>nancylanxiao@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/sb_client/histograms.xml b/tools/metrics/histograms/metadata/sb_client/histograms.xml
index 5dbf4bcc..b80f7126 100644
--- a/tools/metrics/histograms/metadata/sb_client/histograms.xml
+++ b/tools/metrics/histograms/metadata/sb_client/histograms.xml
@@ -259,7 +259,7 @@
 </histogram>
 
 <histogram name="SBClientDownload.ServerRequestsDeepScanningPrompt{Encryption}"
-    enum="BooleanRequested" expires_after="2025-09-14">
+    enum="BooleanRequested" expires_after="2025-11-16">
   <owner>drubery@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -296,7 +296,7 @@
 </histogram>
 
 <histogram name="SBClientDownload.TailoredWarningType"
-    enum="TailoredWarningType" expires_after="2025-09-14">
+    enum="TailoredWarningType" expires_after="2025-11-16">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -413,7 +413,7 @@
 </histogram>
 
 <histogram name="SBClientDownload.{Encryption}MalwareDeepScanResult2.{trigger}"
-    enum="SBClientDownloadCheckResult" expires_after="2025-09-14">
+    enum="SBClientDownloadCheckResult" expires_after="2025-11-16">
   <owner>drubery@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -515,7 +515,7 @@
 
 <histogram
     name="SBClientPhishing.ClientSideDetection.AsyncCheckTriggerForceRequestResult"
-    enum="AsyncCheckTriggerForceRequestResult" expires_after="2025-08-24">
+    enum="AsyncCheckTriggerForceRequestResult" expires_after="2025-11-16">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -692,7 +692,7 @@
 </histogram>
 
 <histogram name="SBClientPhishing.LocalModelDetectsPhishing{RequestType}"
-    enum="BooleanIsPhishing" expires_after="2025-09-14">
+    enum="BooleanIsPhishing" expires_after="2025-11-16">
   <owner>andysjlim@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/search/histograms.xml b/tools/metrics/histograms/metadata/search/histograms.xml
index ebc884d..862ce2b 100644
--- a/tools/metrics/histograms/metadata/search/histograms.xml
+++ b/tools/metrics/histograms/metadata/search/histograms.xml
@@ -65,7 +65,7 @@
 </variants>
 
 <histogram name="Search.Ambient.Query" enum="AmbientSearchEntryPoint"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>juanmojica@google.com</owner>
   <owner>schechter@google.com</owner>
   <owner>stanfield@google.com</owner>
@@ -142,7 +142,7 @@
 
 <histogram
     name="Search.AuxiliarySearch.DonationCount.{AuxiliarySearchEntryType}"
-    units="count" expires_after="2025-09-15">
+    units="count" expires_after="2025-11-16">
   <owner>hanxi@chromium.org</owner>
   <owner>gangwu@chromium.org</owner>
   <owner>clank-start@google.com</owner>
@@ -166,7 +166,7 @@
 </histogram>
 
 <histogram name="Search.AuxiliarySearch.DonationRequestStatus"
-    enum="AuxiliarySearchRequestStatus" expires_after="2025-09-15">
+    enum="AuxiliarySearchRequestStatus" expires_after="2025-11-16">
   <owner>gangwu@chromium.org</owner>
   <owner>chrome-mobile-search@google.com</owner>
   <summary>
@@ -177,7 +177,7 @@
 </histogram>
 
 <histogram name="Search.AuxiliarySearch.Favicon.FirstDonateCount" units="Count"
-    expires_after="2025-09-15">
+    expires_after="2025-11-16">
   <owner>hanxi@chromium.org</owner>
   <owner>gangwu@chromium.org</owner>
   <owner>clank-start@google.com</owner>
@@ -204,7 +204,7 @@
 </histogram>
 
 <histogram name="Search.AuxiliarySearch.Module.ClickInfo" enum="ClickInfo"
-    expires_after="2025-09-15">
+    expires_after="2025-11-16">
   <owner>hanxi@chromium.org</owner>
   <owner>gangwu@chromium.org</owner>
   <owner>clank-start@google.com</owner>
@@ -216,7 +216,7 @@
 </histogram>
 
 <histogram name="Search.AuxiliarySearch.QueryTime.{AuxiliarySearchQueryType}"
-    units="ms" expires_after="2025-09-15">
+    units="ms" expires_after="2025-11-16">
   <owner>hanxi@chromium.org</owner>
   <owner>gangwu@chromium.org</owner>
   <owner>clank-start@google.com</owner>
@@ -229,7 +229,7 @@
 </histogram>
 
 <histogram name="Search.AuxiliarySearch.Schedule.DelayTime" units="ms"
-    expires_after="2025-09-15">
+    expires_after="2025-11-16">
   <owner>hanxi@chromium.org</owner>
   <owner>gangwu@chromium.org</owner>
   <owner>clank-start@google.com</owner>
@@ -241,7 +241,7 @@
 </histogram>
 
 <histogram name="Search.AuxiliarySearch.Schedule.DonateTime" units="ms"
-    expires_after="2025-09-15">
+    expires_after="2025-11-16">
   <owner>hanxi@chromium.org</owner>
   <owner>gangwu@chromium.org</owner>
   <owner>clank-start@google.com</owner>
@@ -253,7 +253,7 @@
 </histogram>
 
 <histogram name="Search.AuxiliarySearch.Schedule.Favicon.DonateCount"
-    units="count" expires_after="2025-09-15">
+    units="count" expires_after="2025-11-16">
   <owner>hanxi@chromium.org</owner>
   <owner>gangwu@chromium.org</owner>
   <owner>clank-start@google.com</owner>
@@ -265,7 +265,7 @@
 </histogram>
 
 <histogram name="Search.AuxiliarySearch.Schedule.Favicon.FetchTime" units="ms"
-    expires_after="2025-09-15">
+    expires_after="2025-11-16">
   <owner>hanxi@chromium.org</owner>
   <owner>gangwu@chromium.org</owner>
   <owner>clank-start@google.com</owner>
@@ -277,7 +277,7 @@
 </histogram>
 
 <histogram name="Search.AuxiliarySearch.Schedule.FaviconDonateResult"
-    enum="DonateResult" expires_after="2025-09-15">
+    enum="DonateResult" expires_after="2025-11-16">
   <owner>hanxi@chromium.org</owner>
   <owner>gangwu@chromium.org</owner>
   <owner>clank-start@google.com</owner>
@@ -289,7 +289,7 @@
 </histogram>
 
 <histogram name="Search.AuxiliarySearch.ShareTabsWithOs" enum="Boolean"
-    expires_after="2025-09-15">
+    expires_after="2025-11-16">
   <owner>hanxi@chromium.org</owner>
   <owner>gangwu@chromium.org</owner>
   <owner>clank-start@google.com</owner>
@@ -948,7 +948,7 @@
 </histogram>
 
 <histogram name="Search.Image.Camera.Open" enum="CameraOpenEntryPoint"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>juanmojica@google.com</owner>
   <owner>schechter@google.com</owner>
   <owner>stanfield@google.com</owner>
@@ -983,7 +983,7 @@
 </histogram>
 
 <histogram name="Search.KeywordTable.HashValidationStatus"
-    enum="KeywordTableHashValidationStatus" expires_after="2025-09-15">
+    enum="KeywordTableHashValidationStatus" expires_after="2025-11-16">
   <owner>wfh@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -997,7 +997,7 @@
 </histogram>
 
 <histogram name="Search.KeywordTable.MigrationSuccess.V137"
-    enum="BooleanSuccess" expires_after="2025-09-15">
+    enum="BooleanSuccess" expires_after="2025-11-16">
   <owner>wfh@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <owner>chrome-desktop-search@google.com</owner>
@@ -1024,7 +1024,7 @@
 </histogram>
 
 <histogram name="Search.OsDefaultsChoice.DelayFromDialogShownToFirstStatus"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>dgn@chromium.org</owner>
   <owner>triploblastic@google.com</owner>
   <owner>chrome-waffle-eng@google.com</owner>
@@ -1044,7 +1044,7 @@
 </histogram>
 
 <histogram name="Search.OsDefaultsChoice.DelayFromObservationToFirstStatus"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>dgn@chromium.org</owner>
   <owner>triploblastic@google.com</owner>
   <owner>chrome-waffle-eng@google.com</owner>
@@ -1061,7 +1061,7 @@
 </histogram>
 
 <histogram name="Search.OsDefaultsChoice.DialogShownAttempt" units="attempts"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dgn@chromium.org</owner>
   <owner>triploblastic@google.com</owner>
   <owner>chrome-waffle-eng@google.com</owner>
@@ -1081,7 +1081,7 @@
 </histogram>
 
 <histogram name="Search.OsDefaultsChoice.DialogStatusChange"
-    enum="OsDefaultsChoiceDialogStatus" expires_after="2025-09-14">
+    enum="OsDefaultsChoiceDialogStatus" expires_after="2025-11-16">
   <owner>dgn@chromium.org</owner>
   <owner>triploblastic@google.com</owner>
   <owner>chrome-waffle-eng@google.com</owner>
@@ -1099,7 +1099,7 @@
 </histogram>
 
 <histogram name="Search.OsDefaultsChoice.DialogStatusOnAppOpen"
-    enum="OsDefaultsChoiceDialogStatus" expires_after="2025-09-14">
+    enum="OsDefaultsChoiceDialogStatus" expires_after="2025-11-16">
   <owner>dgn@chromium.org</owner>
   <owner>triploblastic@google.com</owner>
   <owner>chrome-waffle-eng@google.com</owner>
@@ -1110,7 +1110,7 @@
 </histogram>
 
 <histogram name="Search.OsDefaultsChoice.DialogSuppressionStatus"
-    enum="OsDefaultsChoiceDialogSuppressionStatus" expires_after="2025-09-14">
+    enum="OsDefaultsChoiceDialogSuppressionStatus" expires_after="2025-11-16">
   <owner>dgn@chromium.org</owner>
   <owner>triploblastic@google.com</owner>
   <owner>chrome-waffle-eng@google.com</owner>
@@ -1310,7 +1310,7 @@
 </histogram>
 
 <histogram name="Search.RegionSearch.Lens.Result"
-    enum="LensRegionSearchCaptureResult" expires_after="2025-09-14">
+    enum="LensRegionSearchCaptureResult" expires_after="2025-11-16">
   <owner>juanmojica@google.com</owner>
   <owner>benwgold@google.com</owner>
   <owner>stanfield@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/security/histograms.xml b/tools/metrics/histograms/metadata/security/histograms.xml
index 64cf707..4d124f69 100644
--- a/tools/metrics/histograms/metadata/security/histograms.xml
+++ b/tools/metrics/histograms/metadata/security/histograms.xml
@@ -34,7 +34,7 @@
 </variants>
 
 <histogram name="Security.DataDecoder.Image.DecodingTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>lukasza@chromium.org</owner>
   <owner>rsesek@chromium.org</owner>
   <summary>
@@ -398,7 +398,7 @@
 </histogram>
 
 <histogram name="Security.PageInfo.AboutThisSiteLanguageSupported"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>dullweber@chromium.org</owner>
   <owner>olesiamarukhno@chromium.org</owner>
   <summary>
@@ -1000,7 +1000,7 @@
 </histogram>
 
 <histogram name="SiteIsolation.IsPasswordFormSubmittedInDedicatedProcess"
-    enum="SiteIsolationIsDedicatedProcess" expires_after="2025-08-07">
+    enum="SiteIsolationIsDedicatedProcess" expires_after="2025-11-16">
   <owner>alexmos@chromium.org</owner>
   <owner>lukasza@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/sensitive_content/histograms.xml b/tools/metrics/histograms/metadata/sensitive_content/histograms.xml
index 58c8036..582c2e6 100644
--- a/tools/metrics/histograms/metadata/sensitive_content/histograms.xml
+++ b/tools/metrics/histograms/metadata/sensitive_content/histograms.xml
@@ -35,7 +35,7 @@
 </variants>
 
 <histogram name="SensitiveContent.SensitiveTabSwitchingAnimations"
-    enum="TabSwitchingAnimation" expires_after="2025-09-14">
+    enum="TabSwitchingAnimation" expires_after="2025-11-16">
   <owner>jkeitel@google.com</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -49,7 +49,7 @@
 
 <histogram
     name="SensitiveContent.TabSwitching.{TabSwitchingSurface}.Sensitivity"
-    enum="TabSwitchingSurfaceContentSensitivity" expires_after="2025-09-07">
+    enum="TabSwitchingSurfaceContentSensitivity" expires_after="2025-11-16">
   <owner>jkeitel@google.com</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/service/histograms.xml b/tools/metrics/histograms/metadata/service/histograms.xml
index 78519c5..79e9e20 100644
--- a/tools/metrics/histograms/metadata/service/histograms.xml
+++ b/tools/metrics/histograms/metadata/service/histograms.xml
@@ -503,7 +503,7 @@
 
 <histogram
     name="ServiceWorker.FetchEvent.{Resource}.RaceNetworkRequest.IsCloningDataFinishedBeforeResponseComplete"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>sisidovski@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -561,7 +561,7 @@
 
 <histogram
     name="ServiceWorker.FindRegistrationForClientUrl.IsCalledForNavigation"
-    enum="Boolean" expires_after="2025-08-31">
+    enum="Boolean" expires_after="2026-05-20">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -572,7 +572,7 @@
 
 <histogram
     name="ServiceWorker.FindRegistrationForClientUrl.SkippedMojoCall.OnNavigation"
-    enum="BooleanSkipped" expires_after="2025-07-01">
+    enum="BooleanSkipped" expires_after="2026-05-20">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -583,7 +583,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.FindRegistrationForClientUrl.Time" units="ms"
-    expires_after="2025-11-02">
+    expires_after="2026-05-20">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -593,7 +593,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.FoundServiceWorkerRegistrationOnNavigation"
-    enum="BooleanFound" expires_after="2025-08-31">
+    enum="BooleanFound" expires_after="2026-05-20">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -604,7 +604,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.GetClient.SharedWorkerScript.IsBlob"
-    enum="Boolean" expires_after="2025-09-12">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>yyanagisawa@google.com</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -1228,7 +1228,7 @@
 
 <histogram
     name="ServiceWorker.OnBrowserStartup.SkipServiceWorkerOnFirstNavigation"
-    enum="BooleanSkipped" expires_after="2025-06-29">
+    enum="BooleanSkipped" expires_after="2026-05-20">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -1698,7 +1698,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.StaticRouter.{Resource}.CacheLookupDuration"
-    units="microseconds" expires_after="2025-09-14">
+    units="microseconds" expires_after="2025-11-16">
   <owner>suzukikeita@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/session/histograms.xml b/tools/metrics/histograms/metadata/session/histograms.xml
index 1dccf35..f11550c 100644
--- a/tools/metrics/histograms/metadata/session/histograms.xml
+++ b/tools/metrics/histograms/metadata/session/histograms.xml
@@ -49,7 +49,7 @@
 </histogram>
 
 <histogram name="Session.BrowserFullscreen.DurationUpTo24H" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>avi@chromium.org</owner>
   <owner>chrome-mac-dev@google.com</owner>
   <summary>
@@ -1054,7 +1054,7 @@
 </histogram>
 
 <histogram name="Session.WebStates.SavingTimeOnMainThread" units="ms"
-    expires_after="2025-05-25">
+    expires_after="2025-09-28">
   <owner>fedegermi@chromium.org</owner>
   <owner>sdefresne@chromium.org</owner>
   <summary>
@@ -1093,7 +1093,7 @@
 </histogram>
 
 <histogram name="Session.WebStates.StorageMigrationDuration" units="ms"
-    expires_after="2025-05-25">
+    expires_after="2025-09-28">
   <owner>fedegermi@chromium.org</owner>
   <owner>sdefresne@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/settings/histograms.xml b/tools/metrics/histograms/metadata/settings/histograms.xml
index 8e1ede6..3d71ab90 100644
--- a/tools/metrics/histograms/metadata/settings/histograms.xml
+++ b/tools/metrics/histograms/metadata/settings/histograms.xml
@@ -212,7 +212,7 @@
 </histogram>
 
 <histogram name="Settings.ClearBrowsingData.Advanced.TimePeriod"
-    enum="SettingsClearBrowsingDataTimePeriod" expires_after="2025-09-14">
+    enum="SettingsClearBrowsingDataTimePeriod" expires_after="2025-11-16">
   <owner>rainhard@chromium.org</owner>
   <owner>msramek@chromium.org</owner>
   <owner>chrome-privacy-controls@google.com</owner>
@@ -223,7 +223,7 @@
 </histogram>
 
 <histogram name="Settings.ClearBrowsingData.Basic.TimePeriod"
-    enum="SettingsClearBrowsingDataTimePeriod" expires_after="2025-09-14">
+    enum="SettingsClearBrowsingDataTimePeriod" expires_after="2025-11-16">
   <owner>rainhard@chromium.org</owner>
   <owner>msramek@chromium.org</owner>
   <owner>chrome-privacy-controls@google.com</owner>
@@ -390,7 +390,7 @@
 </histogram>
 
 <histogram name="Settings.OverscrollHistoryNavigation.Enabled"
-    enum="BooleanEnabled" expires_after="2025-09-14">
+    enum="BooleanEnabled" expires_after="2025-11-16">
   <owner>charlesmeng@chromium.org</owner>
   <owner>estalin@chromium.org</owner>
   <summary>
@@ -657,7 +657,7 @@
 </histogram>
 
 <histogram name="Settings.SafetyCheck.Interactions"
-    enum="SettingsSafetyCheckInteractions" expires_after="2025-09-14">
+    enum="SettingsSafetyCheckInteractions" expires_after="2025-11-16">
   <owner>rainhard@chromium.org</owner>
   <owner>msramek@chromium.org</owner>
   <owner>anaudrey@chromium.org</owner>
@@ -688,7 +688,7 @@
 </histogram>
 
 <histogram name="Settings.SafetyCheck.UnusedSitePermissionsAllowAgainDays"
-    units="days" expires_after="2025-09-14">
+    units="days" expires_after="2025-11-16">
   <owner>sideyilmaz@chromium.org</owner>
   <owner>msramek@chromium.org</owner>
   <summary>
@@ -773,7 +773,7 @@
 
 <histogram
     name="Settings.SafetyHub.AbusiveNotificationPermissionRevocation.BlocklistCheckCount"
-    units="checks" expires_after="2025-09-13">
+    units="checks" expires_after="2025-11-16">
   <owner>skrakowi@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -834,7 +834,7 @@
 </histogram>
 
 <histogram name="Settings.SafetyHub.DashboardWarning"
-    enum="SafetyHubModuleType" expires_after="2025-07-27">
+    enum="SafetyHubModuleType" expires_after="2025-11-16">
   <owner>sideyilmaz@chromium.org</owner>
   <owner>chrome-privacy-controls@google.com</owner>
   <summary>
@@ -1158,7 +1158,7 @@
 </histogram>
 
 <histogram name="Settings.SearchEngines.Interactions"
-    enum="SettingsSearchEnginesInteractions" expires_after="2025-09-14">
+    enum="SettingsSearchEnginesInteractions" expires_after="2025-11-16">
   <owner>yoangela@chromium.org</owner>
   <owner>chrome-omnibox-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/sharing/histograms.xml b/tools/metrics/histograms/metadata/sharing/histograms.xml
index 75076ed..2597cd4 100644
--- a/tools/metrics/histograms/metadata/sharing/histograms.xml
+++ b/tools/metrics/histograms/metadata/sharing/histograms.xml
@@ -244,7 +244,7 @@
 </histogram>
 
 <histogram name="Sharing.MessageReceivedType" enum="SharingMessageType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mvanouwerkerk@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml
index 83134cf..48bb938 100644
--- a/tools/metrics/histograms/metadata/signin/histograms.xml
+++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -68,7 +68,7 @@
 <!-- LINT.ThenChange(/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/signin_promo/SigninPromoMediator.java:Event) -->
 
 <histogram name="Signin.AccountCapabilities.FetchLatency" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>tju@google.com</owner>
   <owner>chrome-kids-eng@google.com</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -89,7 +89,7 @@
 
 <histogram
     name="Signin.AccountCapabilities.GetFromSystemLibraryDuration{Caller}"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>fernandex@google.com</owner>
   <owner>msarda@chromium.org</owner>
   <owner>triploblastic@chromium.org</owner>
@@ -121,7 +121,7 @@
 </histogram>
 
 <histogram name="Signin.AccountCapabilities.ImmediatelyAvailable"
-    enum="BooleanAvailable" expires_after="2025-09-14">
+    enum="BooleanAvailable" expires_after="2025-11-16">
   <owner>tju@google.com</owner>
   <owner>chrome-kids-eng@google.com</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -140,7 +140,7 @@
 </histogram>
 
 <histogram name="Signin.AccountCapabilities.UserVisibleLatency" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>tju@google.com</owner>
   <owner>chrome-kids-eng@google.com</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -194,7 +194,7 @@
 </histogram>
 
 <histogram name="Signin.AccountCapabilities.{Priority}.FetchResult"
-    enum="AccountCapabilitiesFetchResult" expires_after="2025-09-14">
+    enum="AccountCapabilitiesFetchResult" expires_after="2025-11-16">
   <owner>alexilin@chromium.org</owner>
   <owner>msarda@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -214,7 +214,7 @@
 </histogram>
 
 <histogram name="Signin.AccountConsistencyPromoAction"
-    enum="AccountConsistencyPromoAction" expires_after="2025-09-14">
+    enum="AccountConsistencyPromoAction" expires_after="2025-11-16">
   <owner>bsazonov@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
@@ -224,7 +224,7 @@
 </histogram>
 
 <histogram name="Signin.AccountConsistencyPromoAction.{PromoEvent}"
-    enum="SigninAccessPoint" expires_after="2025-09-14">
+    enum="SigninAccessPoint" expires_after="2025-11-16">
   <owner>bsazonov@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
@@ -443,7 +443,7 @@
 </histogram>
 
 <histogram name="Signin.AccountTracker.GaiaIdMigrationState"
-    enum="OAuth2LoginAccountRevokedMigrationState" expires_after="2025-09-14">
+    enum="OAuth2LoginAccountRevokedMigrationState" expires_after="2025-11-16">
   <owner>msarda@chromium.org</owner>
   <owner>sdefresne@chromium.org</owner>
   <summary>
@@ -490,7 +490,7 @@
 </histogram>
 
 <histogram name="Signin.AccountType.SigninConsent" enum="SigninAccountType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jlebel@chromium.org</owner>
   <owner>chrome-signin-team@chromium.org</owner>
   <summary>
@@ -542,7 +542,7 @@
 </histogram>
 
 <histogram name="Signin.AddAccountToDevice.Result"
-    enum="SigninAddAccountToDeviceResult" expires_after="2025-09-14">
+    enum="SigninAddAccountToDeviceResult" expires_after="2025-11-16">
   <owner>jlebel@google.com</owner>
   <owner>msarda@google.com</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -563,7 +563,7 @@
 </histogram>
 
 <histogram name="Signin.AddAccountToDevice.{Result}.Duration" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jlebel@google.com</owner>
   <owner>msarda@google.com</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -591,7 +591,7 @@
 </histogram>
 
 <histogram name="Signin.Android.FRESigninEvents" enum="FRESigninEvents"
-    expires_after="2025-07-06">
+    expires_after="2025-11-16">
   <owner>mthiesse@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
@@ -998,7 +998,7 @@
 
 <histogram
     name="Signin.BoundSessionCredentials.SessionRegistrationTotalDuration"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>alexilin@chromium.org</owner>
   <owner>msalama@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -1288,7 +1288,7 @@
 </histogram>
 
 <histogram name="Signin.ExplicitSigninMigration.FromSync" enum="BooleanSuccess"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>droger@chromium.org</owner>
   <owner>rsult@google.com</owner>
   <summary>
@@ -1335,7 +1335,7 @@
 </histogram>
 
 <histogram name="Signin.Extensions.GetAuthTokenResult{GetAuthTokenType}"
-    enum="GetAuthTokenResult" expires_after="2025-09-14">
+    enum="GetAuthTokenResult" expires_after="2025-11-16">
   <owner>alexilin@chromium.org</owner>
   <owner>droger@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -1418,7 +1418,7 @@
 </histogram>
 
 <histogram name="Signin.GetAccessTokenFinished" enum="GoogleServiceAuthError"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>droger@chromium.org</owner>
   <owner>msarda@chromium.org</owner>
   <summary>
@@ -1605,7 +1605,7 @@
 </histogram>
 
 <histogram name="Signin.Intercept.ChromeSignin.ResponseTime{Result}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>rsult@google.com</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
@@ -1671,7 +1671,7 @@
 </histogram>
 
 <histogram name="Signin.Intercept.HeuristicOutcome"
-    enum="SigninInterceptHeuristicOutcome" expires_after="2025-09-14">
+    enum="SigninInterceptHeuristicOutcome" expires_after="2025-11-16">
   <owner>droger@chromium.org</owner>
   <owner>alexilin@chromium.org</owner>
   <summary>
@@ -1681,7 +1681,7 @@
 </histogram>
 
 <histogram name="Signin.InterceptResult.ChromeSignin{State}"
-    enum="SigninInterceptResult" expires_after="2025-09-14">
+    enum="SigninInterceptResult" expires_after="2025-11-16">
   <owner>rsult@google.com</owner>
   <owner>droger@chromium.org</owner>
   <summary>
@@ -1701,7 +1701,7 @@
 </histogram>
 
 <histogram name="Signin.InterceptResult.Enterprise{Mode}.{Status}"
-    enum="SigninInterceptResult" expires_after="2025-09-14">
+    enum="SigninInterceptResult" expires_after="2025-11-16">
   <owner>alexilin@chromium.org</owner>
   <owner>droger@chromium.org</owner>
   <summary>
@@ -1724,7 +1724,7 @@
 </histogram>
 
 <histogram name="Signin.InterceptResult.{InterceptType}{SigninState}"
-    enum="SigninInterceptResult" expires_after="2025-09-14">
+    enum="SigninInterceptResult" expires_after="2025-11-16">
   <owner>alexilin@chromium.org</owner>
   <owner>droger@chromium.org</owner>
   <summary>
@@ -2408,7 +2408,7 @@
 </histogram>
 
 <histogram name="Signin.Reconciler.Operation" enum="SigninReconcilerOperation"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>msarda@chromium.org</owner>
   <owner>droger@chromium.org</owner>
   <summary>
@@ -2639,7 +2639,7 @@
 </histogram>
 
 <histogram name="Signin.SignIn.Started" enum="SigninAccessPoint"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bsazonov@chromium.org</owner>
   <owner>dgn@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -2682,7 +2682,7 @@
 </histogram>
 
 <histogram name="Signin.SigninCompletedAccessPoint{SigninAccountStatus}"
-    enum="SigninAccessPoint" expires_after="2025-09-14">
+    enum="SigninAccessPoint" expires_after="2025-11-16">
   <owner>msarda@chromium.org</owner>
   <owner>bsazonov@chromium.org</owner>
   <owner>droger@chromium.org</owner>
@@ -2794,7 +2794,7 @@
 </histogram>
 
 <histogram name="Signin.SigninStartedAccessPoint{SigninAccountStatus}"
-    enum="SigninAccessPoint" expires_after="2025-09-14">
+    enum="SigninAccessPoint" expires_after="2025-11-16">
   <owner>msarda@chromium.org</owner>
   <owner>bsazonov@chromium.org</owner>
   <owner>droger@chromium.org</owner>
@@ -2957,7 +2957,7 @@
 </histogram>
 
 <histogram name="Signin.SyncButtons.Clicked" enum="SyncButtonClicked"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>tju@chromium.org</owner>
   <owner>chrome-kids-team@google.com</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -2980,7 +2980,7 @@
 </histogram>
 
 <histogram name="Signin.SyncButtons.Shown" enum="SyncButtonsType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>tju@chromium.org</owner>
   <owner>chrome-kids-team@google.com</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -3047,7 +3047,7 @@
 </histogram>
 
 <histogram name="Signin.SyncOptIn.Completed" enum="SigninAccessPoint"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bsazonov@chromium.org</owner>
   <owner>dgn@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -3108,7 +3108,7 @@
 </histogram>
 
 <histogram name="Signin.SyncOptIn.Started" enum="SigninAccessPoint"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bsazonov@chromium.org</owner>
   <owner>dgn@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -3150,7 +3150,7 @@
 </histogram>
 
 <histogram name="Signin.SyncTurnOff.Completed" enum="SigninSignoutProfile"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bsazonov@chromium.org</owner>
   <owner>dgn@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -3243,7 +3243,7 @@
 </histogram>
 
 <histogram name="Signin.TokenTable.SetTokenResult"
-    enum="SigninTokenTableWriteTokenToDBResult" expires_after="2025-08-10">
+    enum="SigninTokenTableWriteTokenToDBResult" expires_after="2025-11-16">
   <owner>wfh@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/sql/histograms.xml b/tools/metrics/histograms/metadata/sql/histograms.xml
index f7c967d..99bfdca 100644
--- a/tools/metrics/histograms/metadata/sql/histograms.xml
+++ b/tools/metrics/histograms/metadata/sql/histograms.xml
@@ -165,7 +165,7 @@
 </histogram>
 
 <histogram name="Sql.Recovery.Result.{DatabaseTag}" enum="SqlRecoveryResult"
-    expires_after="2025-09-15">
+    expires_after="2025-11-16">
   <owner>asully@chromium.org</owner>
   <owner>chrome-catan@google.com</owner>
   <summary>
@@ -176,7 +176,7 @@
 </histogram>
 
 <histogram name="Sql.Recovery.ResultCode" enum="SqliteLoggedResultCode"
-    expires_after="2025-09-15">
+    expires_after="2025-11-16">
   <owner>asully@chromium.org</owner>
   <owner>chrome-catan@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/stability/histograms.xml b/tools/metrics/histograms/metadata/stability/histograms.xml
index ba109f10..e3f1181c 100644
--- a/tools/metrics/histograms/metadata/stability/histograms.xml
+++ b/tools/metrics/histograms/metadata/stability/histograms.xml
@@ -189,7 +189,7 @@
 </histogram>
 
 <histogram name="Stability.Android.ProcessedRealMinidumps"
-    enum="AndroidProcessedMinidumps" expires_after="2025-09-14">
+    enum="AndroidProcessedMinidumps" expires_after="2025-11-16">
   <owner>wnwen@chromium.org</owner>
   <owner>src/components/minidump_uploader/OWNERS</owner>
   <summary>
@@ -210,7 +210,7 @@
 </histogram>
 
 <histogram name="Stability.Android.SystemExitReason{AndroidProcessExitReasons}"
-    enum="AndroidProcessExitReason" expires_after="2025-09-14">
+    enum="AndroidProcessExitReason" expires_after="2025-11-16">
   <owner>boliu@chromium.org</owner>
   <owner>ssid@chromium.org</owner>
   <owner>wnwen@chromium.org</owner>
@@ -716,7 +716,7 @@
 </histogram>
 
 <histogram name="Stability.RendererAbnormalTermination2.HostedContentType"
-    enum="RendererHostedContentType" expires_after="2025-09-14">
+    enum="RendererHostedContentType" expires_after="2025-11-16">
   <owner>fdoray@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -726,7 +726,7 @@
 </histogram>
 
 <histogram name="Stability.RendererAbnormalTermination2.{HostedContentType}"
-    enum="TerminationStatus" expires_after="2025-09-14">
+    enum="TerminationStatus" expires_after="2025-11-16">
   <owner>fdoray@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/startup/histograms.xml b/tools/metrics/histograms/metadata/startup/histograms.xml
index ed87e55..7b88550 100644
--- a/tools/metrics/histograms/metadata/startup/histograms.xml
+++ b/tools/metrics/histograms/metadata/startup/histograms.xml
@@ -63,7 +63,7 @@
 </histogram>
 
 <histogram name="Startup.Android.Cold.FirstPaintOccurredPreForeground"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>blundell@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
@@ -180,7 +180,7 @@
 </histogram>
 
 <histogram name="Startup.Android.Cold.TimeToFirstNavigationCommit2.Tabbed"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>pasko@chromium.org</owner>
   <owner>agrieve@chromium.org</owner>
   <summary>
@@ -339,7 +339,7 @@
 </histogram>
 
 <histogram name="Startup.Android.Cold.TimeToForegroundSessionStart" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>pasko@chromium.org</owner>
   <owner>mthiesse@chromium.org</owner>
   <summary>
@@ -349,7 +349,7 @@
 </histogram>
 
 <histogram name="Startup.Android.Cold.TimeToVisibleContent" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ckitagawa@chromium.org</owner>
   <summary>
     Android: The time from the activity creation point to the moment the content
@@ -367,7 +367,7 @@
 </histogram>
 
 <histogram name="Startup.Android.Cold.{FirstDrawSurface}.TimeToFirstDraw"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>nafisabedin@google.com</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
@@ -500,7 +500,7 @@
 </histogram>
 
 <histogram name="Startup.Android.MainIconLaunchTotalWaitTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>nafisabedin@google.com</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
@@ -578,7 +578,7 @@
 </histogram>
 
 <histogram name="Startup.BringToForegroundReason"
-    enum="BooleanBringToForegroundReason" expires_after="2025-09-14">
+    enum="BooleanBringToForegroundReason" expires_after="2025-11-16">
   <owner>peter@chromium.org</owner>
   <summary>
     Records the cause, each time Chrome is brought to the foreground. Currently
@@ -1054,7 +1054,7 @@
 </histogram>
 
 <histogram name="Startup.MobileSessionStartAction"
-    enum="MobileSessionStartAction" expires_after="2025-09-14">
+    enum="MobileSessionStartAction" expires_after="2025-11-16">
   <owner>thegreenfrog@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>
@@ -1064,7 +1064,7 @@
 </histogram>
 
 <histogram name="Startup.MobileSessionStartFromApps"
-    enum="MobileSessionCallerApp" expires_after="2025-09-14">
+    enum="MobileSessionCallerApp" expires_after="2025-11-16">
   <owner>thegreenfrog@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>The calling application (if any).</summary>
@@ -1096,7 +1096,7 @@
 
 <histogram
     name="Startup.Renderer.LoadTime.ApplicationStartToRendererStartRunLoop"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>spvw@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <summary>
@@ -1113,7 +1113,7 @@
 </histogram>
 
 <histogram name="Startup.Renderer.LoadTime.ChromeMainToRendererStartRunLoop"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>spvw@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <summary>
@@ -1128,7 +1128,7 @@
 
 <histogram
     name="Startup.Renderer.LoadTime.ProcessCreationToRendererStartRunLoop"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>spvw@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <summary>
@@ -1214,7 +1214,7 @@
 </histogram>
 
 <histogram name="Startup.{Process}.LoadTime.PreReadFile" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>spvw@chromium.org</owner>
   <owner>fdoray@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/storage/histograms.xml b/tools/metrics/histograms/metadata/storage/histograms.xml
index 8cc574f9b..94f65f5 100644
--- a/tools/metrics/histograms/metadata/storage/histograms.xml
+++ b/tools/metrics/histograms/metadata/storage/histograms.xml
@@ -131,7 +131,7 @@
 </histogram>
 
 <histogram name="API.StorageAccess.RequestOutcome"
-    enum="StorageAccessAPIRequestOutcome" expires_after="2025-09-14">
+    enum="StorageAccessAPIRequestOutcome" expires_after="2025-11-16">
   <owner>cfredric@chromium.org</owner>
   <owner>brandm@microsoft.com</owner>
   <summary>
@@ -142,7 +142,7 @@
 </histogram>
 
 <histogram name="API.StorageAccess.RequestStorageAccess2"
-    enum="RequestStorageResult" expires_after="2025-09-14">
+    enum="RequestStorageResult" expires_after="2025-11-16">
   <owner>mkwst@chromium.org</owner>
   <owner>cfredric@chromium.org</owner>
   <owner>brandm@microsoft.com</owner>
@@ -188,7 +188,7 @@
 </histogram>
 
 <histogram name="API.StorageAccessHeader.SecFetchStorageAccessOutcome"
-    enum="SecFetchStorageAccessOutcome" expires_after="2025-09-15">
+    enum="SecFetchStorageAccessOutcome" expires_after="2025-11-16">
   <owner>sledoux@chromium.org</owner>
   <owner>cfredric@chromium.org</owner>
   <summary>
@@ -201,7 +201,7 @@
 </histogram>
 
 <histogram name="API.StorageAccessHeader.StorageAccessStatusOutcome"
-    enum="StorageAccessStatusOutcome" expires_after="2025-09-15">
+    enum="StorageAccessStatusOutcome" expires_after="2025-11-16">
   <owner>sledoux@chromium.org</owner>
   <owner>cfredric@chromium.org</owner>
   <summary>
@@ -239,7 +239,7 @@
 </histogram>
 
 <histogram name="Clipboard.Read" enum="ClipboardFormatRead"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>huangdarwin@chromium.org</owner>
   <owner>src/ui/base/clipboard/OWNERS</owner>
   <summary>
@@ -266,7 +266,7 @@
 </histogram>
 
 <histogram name="Clipboard.Write" enum="ClipboardFormatWrite"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>huangdarwin@chromium.org</owner>
   <owner>src/ui/base/clipboard/OWNERS</owner>
   <summary>
@@ -399,7 +399,7 @@
 </histogram>
 
 <histogram name="IndexedDB.LargeValueReadResult" enum="FileErrorCode"
-    expires_after="2025-09-07">
+    expires_after="2025-11-16">
   <owner>leimy@chromium.org</owner>
   <owner>evanstade@microsoft.com</owner>
   <owner>chrome-owp-storage@google.com</owner>
@@ -1004,7 +1004,7 @@
 </histogram>
 
 <histogram name="Storage.FileSystemAccess.ObserverUsageQuotaExceeded"
-    enum="Boolean" expires_after="2025-09-14">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>memmott@chromium.org</owner>
   <owner>dslee@chromium.org</owner>
   <owner>christinesm@chromium.org</owner>
@@ -1175,7 +1175,7 @@
 </histogram>
 
 <histogram name="Storage.InterestGroup.AdProtoCompressionRatio" units="%"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>caraitto@chromium.org</owner>
   <owner>pauljensen@chromium.org</owner>
   <summary>
@@ -1241,7 +1241,7 @@
 </histogram>
 
 <histogram name="Storage.InterestGroup.AdProtoSizeCompressed" units="bytes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>caraitto@chromium.org</owner>
   <owner>pauljensen@chromium.org</owner>
   <summary>
@@ -1265,7 +1265,7 @@
 </histogram>
 
 <histogram name="Storage.InterestGroup.AdRenderURLSize" units="bytes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>caraitto@chromium.org</owner>
   <owner>pauljensen@chromium.org</owner>
   <summary>
@@ -1298,7 +1298,7 @@
 </histogram>
 
 <histogram name="Storage.InterestGroup.DBSize" units="KB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>behamilton@google.com</owner>
   <owner>pauljensen@chromium.org</owner>
   <summary>
@@ -1336,7 +1336,7 @@
 
 <histogram name="Storage.InterestGroup.JSONDeserializationResult"
     enum="InterestGroupStorageJSONDeserializationResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>caraitto@chromium.org</owner>
   <owner>pauljensen@chromium.org</owner>
   <summary>
@@ -1373,7 +1373,7 @@
 </histogram>
 
 <histogram name="Storage.InterestGroup.PerInterestGroup.NumAdComponents"
-    units="ad components" expires_after="2025-09-14">
+    units="ad components" expires_after="2025-11-16">
   <owner>caraitto@chromium.org</owner>
   <owner>pauljensen@chromium.org</owner>
   <summary>
@@ -1384,7 +1384,7 @@
 </histogram>
 
 <histogram name="Storage.InterestGroup.PerInterestGroup.NumAds" units="ads"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>caraitto@chromium.org</owner>
   <owner>pauljensen@chromium.org</owner>
   <summary>
@@ -1395,7 +1395,7 @@
 </histogram>
 
 <histogram name="Storage.InterestGroup.PerSiteCount" units="groups"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>behamilton@google.com</owner>
   <owner>pauljensen@chromium.org</owner>
   <summary>
@@ -1419,7 +1419,7 @@
 
 <histogram name="Storage.InterestGroup.ProtoDeserializationResult.{Type}"
     enum="InterestGroupStorageProtoDeserializationResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>caraitto@chromium.org</owner>
   <owner>pauljensen@chromium.org</owner>
   <summary>
@@ -1431,7 +1431,7 @@
 
 <histogram name="Storage.InterestGroup.ProtoSerializationResult.{Type}"
     enum="InterestGroupStorageProtoSerializationResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>caraitto@chromium.org</owner>
   <owner>pauljensen@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/structured_metrics/histograms.xml b/tools/metrics/histograms/metadata/structured_metrics/histograms.xml
index d040e3d0..6dd79ea9 100644
--- a/tools/metrics/histograms/metadata/structured_metrics/histograms.xml
+++ b/tools/metrics/histograms/metadata/structured_metrics/histograms.xml
@@ -120,7 +120,7 @@
 </histogram>
 
 <histogram name="StructuredMetrics.LogStore.CompressionRatio" units="%"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>andrewbregger@google.com</owner>
   <owner>jongahn@google.com</owner>
   <owner>chromeos-data-eng@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/subresource/histograms.xml b/tools/metrics/histograms/metadata/subresource/histograms.xml
index bc2fe7ff..ad250cf 100644
--- a/tools/metrics/histograms/metadata/subresource/histograms.xml
+++ b/tools/metrics/histograms/metadata/subresource/histograms.xml
@@ -23,7 +23,7 @@
 <histograms>
 
 <histogram name="SubresourceFilter.Actions2" enum="SubresourceFilterActions2"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>alexmt@chromium.org</owner>
   <owner>chrome-ads-histograms@google.com</owner>
   <summary>
@@ -47,7 +47,7 @@
 </histogram>
 
 <histogram name="SubresourceFilter.DocumentLoad.SubframeFilteringDelay.Allowed"
-    units="microseconds" expires_after="2025-09-15">
+    units="microseconds" expires_after="2025-11-16">
   <owner>alexmt@chromium.org</owner>
   <owner>chrome-ads-histograms@google.com</owner>
   <summary>
@@ -189,7 +189,7 @@
 </histogram>
 
 <histogram name="SubresourceFilter.PageLoad.ActivationList"
-    enum="ActivationList" expires_after="2025-09-14">
+    enum="ActivationList" expires_after="2025-11-16">
   <owner>alexmt@chromium.org</owner>
   <owner>chrome-ads-histograms@google.com</owner>
   <summary>
@@ -199,7 +199,7 @@
 </histogram>
 
 <histogram name="SubresourceFilter.PageLoad.ActivationState"
-    enum="SubresourceFilterActivationState" expires_after="2025-09-14">
+    enum="SubresourceFilterActivationState" expires_after="2025-11-16">
   <owner>alexmt@chromium.org</owner>
   <owner>chrome-ads-histograms@google.com</owner>
   <summary>
@@ -262,7 +262,7 @@
 </histogram>
 
 <histogram name="SubresourceFilter.PageLoad.NumSubresourceLoads.MatchedRules"
-    units="resource loads" expires_after="2025-09-15">
+    units="resource loads" expires_after="2025-11-16">
   <owner>jkarlin@chromium.org</owner>
   <owner>chrome-ads-histograms@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml
index 2fc3a2c..4a9bf19 100644
--- a/tools/metrics/histograms/metadata/sync/histograms.xml
+++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -496,7 +496,7 @@
 </histogram>
 
 <histogram name="Sync.BookmarkModelMergerTime{UpdatesCount}" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>rushans@google.com</owner>
   <owner>mastiz@chromium.org</owner>
   <summary>
@@ -940,7 +940,7 @@
 </histogram>
 
 <histogram name="Sync.DataTypeErrorSite{SyncDataType}"
-    enum="SyncDataTypeErrorSite" expires_after="2025-09-14">
+    enum="SyncDataTypeErrorSite" expires_after="2025-11-16">
   <owner>treib@chromium.org</owner>
   <owner>rushans@google.com</owner>
   <summary>
@@ -1179,7 +1179,7 @@
 </histogram>
 
 <histogram name="Sync.DeviceCount2.{DeviceType}" units="devices"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ssid@chromium.org</owner>
   <owner>mastiz@chromium.org</owner>
   <owner>chrome-metrics-team@google.com</owner>
@@ -1764,7 +1764,7 @@
 </histogram>
 
 <histogram name="Sync.PostedGetUpdatesOrigin" enum="SyncGetUpdatesOrigin"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mastiz@chromium.org</owner>
   <owner>rushans@google.com</owner>
   <summary>
@@ -2472,7 +2472,7 @@
 </histogram>
 
 <histogram name="Sync.TrustedVaultKeyRetrievalTrigger"
-    enum="TrustedVaultUserActionTrigger" expires_after="2025-09-14">
+    enum="TrustedVaultUserActionTrigger" expires_after="2025-11-16">
   <owner>mmoskvitin@google.com</owner>
   <owner>mastiz@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/tab/histograms.xml b/tools/metrics/histograms/metadata/tab/histograms.xml
index 36e67a8..ad2887d1 100644
--- a/tools/metrics/histograms/metadata/tab/histograms.xml
+++ b/tools/metrics/histograms/metadata/tab/histograms.xml
@@ -76,7 +76,7 @@
 </variants>
 
 <histogram name="Discarding.DailyDiscards{TabDiscardReason}" units="tabs"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>vovoy@chromium.org</owner>
   <owner>fdoray@chromium.org</owner>
   <summary>
@@ -88,7 +88,7 @@
 </histogram>
 
 <histogram name="Discarding.DailyReloads{TabDiscardReason}" units="tabs"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>vovoy@chromium.org</owner>
   <owner>fdoray@chromium.org</owner>
   <summary>
@@ -161,7 +161,7 @@
 </histogram>
 
 <histogram name="Discarding.DiscardPageOnUIThreadOutcome"
-    enum="DiscardPageOnUIThreadOutcome" expires_after="2025-09-14">
+    enum="DiscardPageOnUIThreadOutcome" expires_after="2025-11-16">
   <owner>fdoray@chromium.org</owner>
   <owner>joenotcharles@chromium.org</owner>
   <summary>
@@ -361,7 +361,7 @@
   </summary>
 </histogram>
 
-<histogram name="Tab.NewTab" enum="NewTabType" expires_after="2025-09-14">
+<histogram name="Tab.NewTab" enum="NewTabType" expires_after="2025-11-16">
   <owner>bsep@chromium.org</owner>
   <summary>
     Recorded when a new tab is opened. Tracks the method in which the tab was
@@ -888,7 +888,7 @@
 </histogram>
 
 <histogram name="TabGroups.SavedTabGroupLifespan" units="minutes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dljames@chromium.org</owner>
   <owner>top-chrome-desktop-ui@google.com</owner>
   <summary>
@@ -946,7 +946,7 @@
 </histogram>
 
 <histogram name="TabGroups.SavedTabGroupTabCount" units="tabs"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dljames@chromium.org</owner>
   <owner>top-chrome-desktop-ui@google.com</owner>
   <summary>
@@ -1284,7 +1284,7 @@
 </histogram>
 
 <histogram name="TabGroups.Sync.SavedTabGroupAge" units="minutes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>shaktisahu@chromium.org</owner>
   <owner>clank-tab-dev@google.com</owner>
   <summary>
@@ -1712,7 +1712,7 @@
 </histogram>
 
 <histogram name="TabManager.Discarding.DiscardToReloadTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>chrisha@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -1779,7 +1779,7 @@
 </histogram>
 
 <histogram name="TabRestore.{RestoreType}.TimeBetweenClosedAndRestored"
-    units="ms" expires_after="2025-09-14">
+    units="ms" expires_after="2025-11-16">
   <owner>sreejakshetty@chromium.org</owner>
   <owner>chrome-brapp-loading@google.com</owner>
   <summary>
@@ -2501,7 +2501,7 @@
 </histogram>
 
 <histogram name="Tabs.RestoreTabStateException" enum="RestoreTabStateException"
-    expires_after="2025-08-24">
+    expires_after="2025-11-16">
   <owner>ckitagawa@chromium.org</owner>
   <owner>fredmello@chromium.org</owner>
   <summary>
@@ -2851,7 +2851,7 @@
 </histogram>
 
 <histogram name="Tabs.TabRestoreUrlMatch" enum="Boolean"
-    expires_after="2025-09-07">
+    expires_after="2025-11-16">
   <owner>ckitagawa@chromium.org</owner>
   <owner>dtrainor@chromium.org</owner>
   <summary>
@@ -2993,7 +2993,7 @@
 </histogram>
 
 <histogram name="Tabs.TabSearch.NumTabsOnOpen" units="tabs"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>tluk@chromium.org</owner>
   <owner>robliao@chromium.org</owner>
   <summary>
@@ -3060,7 +3060,7 @@
 </histogram>
 
 <histogram name="Tabs.TabSearch.RecentlyClosedSectionToggleAction"
-    enum="TabSearchRecentlyClosedToggleActions" expires_after="2025-09-14">
+    enum="TabSearchRecentlyClosedToggleActions" expires_after="2025-11-16">
   <owner>romanarora@chromium.org</owner>
   <owner>robliao@chromium.org</owner>
   <owner>tluk@chromium.org</owner>
@@ -3512,7 +3512,7 @@
 </histogram>
 
 <histogram name="Tabs.{TabActiveState}TabWidth" units="px"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dpenning@chromium.org</owner>
   <owner>top-chrome-desktop-ui@google.com</owner>
   <summary>
@@ -3549,7 +3549,7 @@
 </histogram>
 
 <histogram name="TabStrip.Dragging.TimeFromLastDrag" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kerenzhu@chromium.org</owner>
   <owner>yuhengh@chromium.org</owner>
   <owner>temao@chromium.org</owner>
@@ -3594,7 +3594,7 @@
 </histogram>
 
 <histogram name="TabStrip.Tab.{Framework}.ActivationAction"
-    enum="TabActivationTypes" expires_after="2025-09-14">
+    enum="TabActivationTypes" expires_after="2025-11-16">
   <owner>yuhengh@chromium.org</owner>
   <owner>tluk@chromium.org</owner>
   <owner>romanarora@chromium.org</owner>
@@ -3630,7 +3630,7 @@
   </summary>
 </histogram>
 
-<histogram name="TabStrip.TimeToSwitch" units="ms" expires_after="2025-09-14">
+<histogram name="TabStrip.TimeToSwitch" units="ms" expires_after="2025-11-16">
   <owner>dpenning@chromium.org</owner>
   <owner>top-chrome-desktop-ui@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/translate/histograms.xml b/tools/metrics/histograms/metadata/translate/histograms.xml
index 9c245db..fdc62d09 100644
--- a/tools/metrics/histograms/metadata/translate/histograms.xml
+++ b/tools/metrics/histograms/metadata/translate/histograms.xml
@@ -287,7 +287,7 @@
 </histogram>
 
 <histogram name="Translate.OnDeviceTranslation.Download.LanguagePair"
-    units="int" expires_after="2025-08-24">
+    units="int" expires_after="2025-11-16">
   <owner>gjc@google.com</owner>
   <owner>chrome-builtin-ai@google.com</owner>
   <summary>
@@ -343,7 +343,7 @@
 
 <histogram
     name="Translate.OnDeviceTranslation.{OnDeviceTranslationAction}.{LanguageRole}"
-    enum="SupportedLanguage" expires_after="2025-08-24">
+    enum="SupportedLanguage" expires_after="2025-11-16">
   <owner>gjc@google.com</owner>
   <owner>chrome-builtin-ai@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/trusted_vault/histograms.xml b/tools/metrics/histograms/metadata/trusted_vault/histograms.xml
index 944820c..14a5423 100644
--- a/tools/metrics/histograms/metadata/trusted_vault/histograms.xml
+++ b/tools/metrics/histograms/metadata/trusted_vault/histograms.xml
@@ -34,7 +34,7 @@
 </variants>
 
 <histogram name="TrustedVault.AccessTokenFetchSuccess{SecurityDomainId}"
-    enum="Boolean" expires_after="2025-07-01">
+    enum="Boolean" expires_after="2026-07-01">
   <owner>mmoskvitin@google.com</owner>
   <owner>mastiz@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/ui/histograms.xml b/tools/metrics/histograms/metadata/ui/histograms.xml
index 91c029b9..36fd60f 100644
--- a/tools/metrics/histograms/metadata/ui/histograms.xml
+++ b/tools/metrics/histograms/metadata/ui/histograms.xml
@@ -108,7 +108,7 @@
 </variants>
 
 <histogram name="Bubble.{BubbleName}.CloseReason" enum="WidgetClosedReason"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>kerenzhu@chromium.org</owner>
   <owner>dayeung@chromium.org</owner>
   <owner>temao@chromium.org</owner>
@@ -120,7 +120,7 @@
 </histogram>
 
 <histogram name="Bubble.{BubbleName}.CreateToPresentationTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>temao@chromium.org</owner>
   <owner>yuhengh@chromium.org</owner>
   <owner>kerenzhu@chromium.org</owner>
@@ -135,7 +135,7 @@
 </histogram>
 
 <histogram name="Bubble.{BubbleName}.CreateToVisibleTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>temao@chromium.org</owner>
   <owner>yuhengh@chromium.org</owner>
   <owner>kerenzhu@chromium.org</owner>
@@ -150,7 +150,7 @@
 </histogram>
 
 <histogram name="Bubble.{BubbleName}.TimeVisible" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>yuhengh@chromium.org</owner>
   <owner>kerenzhu@chromium.org</owner>
   <owner>dayeung@chromium.org</owner>
@@ -162,7 +162,7 @@
 </histogram>
 
 <histogram name="ContextMenu.LensSupportStatus" enum="LensSupportStatus"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>benwgold@google.com</owner>
   <owner>lens-chrome@google.com</owner>
   <summary>
@@ -191,7 +191,7 @@
 </histogram>
 
 <histogram name="ContextMenu.SelectedOptionDesktop{ContextMenuTypeDesktop}"
-    enum="ContextMenuOptionDesktop" expires_after="2025-09-14">
+    enum="ContextMenuOptionDesktop" expires_after="2025-11-16">
   <owner>avi@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
   <summary>
@@ -292,7 +292,7 @@
 </histogram>
 
 <histogram name="DefaultBrowser.InfoBar.TimesShownBeforeAccept" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>agale@chromium.org</owner>
   <owner>robliao@chromium.org</owner>
   <summary>
@@ -302,7 +302,7 @@
 </histogram>
 
 <histogram name="DefaultBrowser.InfoBar.UserInteraction"
-    enum="DefaultBrowserInfoBarUserInteraction" expires_after="2025-09-14">
+    enum="DefaultBrowserInfoBarUserInteraction" expires_after="2025-11-16">
   <owner>pmonette@chromium.org</owner>
   <owner>robliao@chromium.org</owner>
   <summary>
@@ -346,7 +346,7 @@
 </histogram>
 
 <histogram name="RenderTextHarfBuzz.GetFallbackFontTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dayeung@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <summary>
@@ -364,7 +364,7 @@
 </histogram>
 
 <histogram name="RenderTextHarfBuzz.ShapeRunsFallback" enum="ShapeRunFallback"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dayeung@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <summary>
@@ -397,7 +397,7 @@
 </histogram>
 
 <histogram name="RenderViewContextMenu.Shown" enum="RenderViewContextMenuItem"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>avi@chromium.org</owner>
   <owner>edwardjung@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/uma/histograms.xml b/tools/metrics/histograms/metadata/uma/histograms.xml
index bf0abb1..f9e0ed1 100644
--- a/tools/metrics/histograms/metadata/uma/histograms.xml
+++ b/tools/metrics/histograms/metadata/uma/histograms.xml
@@ -658,7 +658,7 @@
 </histogram>
 
 <histogram name="UMA.PrimaryUserType" enum="UserType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>michaelpg@chromium.org</owner>
   <owner>yilkal@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
@@ -878,7 +878,7 @@
 </histogram>
 
 <histogram name="UMA.StructuredMetrics.InternalError2"
-    enum="StructuredMetricsInternalError2" expires_after="2025-09-14">
+    enum="StructuredMetricsInternalError2" expires_after="2025-11-16">
   <owner>jongahn@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>rkaplow@chromium.org</owner>
@@ -906,7 +906,7 @@
 </histogram>
 
 <histogram name="UMA.StructuredMetrics.NumEventsInUpload" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jongahn@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>rkaplow@chromium.org</owner>
@@ -918,7 +918,7 @@
 </histogram>
 
 <histogram name="UMA.StructuredMetrics.NumFilesPerExternalMetricsScan"
-    units="count" expires_after="2025-09-14">
+    units="count" expires_after="2025-11-16">
   <owner>tby@chromium.org</owner>
   <owner>jongahn@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/v8/histograms.xml b/tools/metrics/histograms/metadata/v8/histograms.xml
index 4fb1799..af34c22 100644
--- a/tools/metrics/histograms/metadata/v8/histograms.xml
+++ b/tools/metrics/histograms/metadata/v8/histograms.xml
@@ -451,7 +451,7 @@
 </histogram>
 
 <histogram name="V8.ExternalPointerTableCompactionOutcome"
-    enum="V8ExternalPointerTableCompactionOutcome" expires_after="2025-06-30">
+    enum="V8ExternalPointerTableCompactionOutcome" expires_after="2026-06-30">
   <owner>saelo@chromium.org</owner>
   <owner>ishell@chromium.org</owner>
   <summary>
@@ -1865,7 +1865,7 @@
 </histogram>
 
 <histogram name="V8.SandboxedCodePointersCount" units="count"
-    expires_after="2025-06-30">
+    expires_after="2026-06-30">
   <owner>saelo@chromium.org</owner>
   <owner>ishell@chromium.org</owner>
   <summary>
@@ -1879,7 +1879,7 @@
 </histogram>
 
 <histogram name="V8.SandboxedCppHeapPointersCount" units="count"
-    expires_after="2025-06-30">
+    expires_after="2026-06-30">
   <owner>saelo@chromium.org</owner>
   <owner>ishell@chromium.org</owner>
   <summary>
@@ -1894,7 +1894,7 @@
 </histogram>
 
 <histogram name="V8.SandboxedExternalPointersCount" units="count"
-    expires_after="2025-06-30">
+    expires_after="2026-06-30">
   <owner>saelo@chromium.org</owner>
   <owner>ishell@chromium.org</owner>
   <summary>
@@ -1909,7 +1909,7 @@
 </histogram>
 
 <histogram name="V8.SandboxedTrustedPointersCount" units="count"
-    expires_after="2025-06-30">
+    expires_after="2026-06-30">
   <owner>saelo@chromium.org</owner>
   <owner>ishell@chromium.org</owner>
   <summary>
@@ -2257,7 +2257,7 @@
 </histogram>
 
 <histogram name="V8.WasmCompileFunctionMicroSeconds{V8WasmSeparateAsmAndWasm}"
-    units="microseconds" expires_after="2025-09-14">
+    units="microseconds" expires_after="2025-11-16">
   <owner>ecmziegler@chromium.org</owner>
   <owner>adamk@chromium.org</owner>
   <owner>clemensb@chromium.org</owner>
@@ -2302,7 +2302,7 @@
 </histogram>
 
 <histogram name="V8.WasmCompileModuleAsyncMicroSeconds" units="microseconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ecmziegler@chromium.org</owner>
   <owner>adamk@chromium.org</owner>
   <owner>clemensb@chromium.org</owner>
@@ -2315,7 +2315,7 @@
 </histogram>
 
 <histogram name="V8.WasmCompileModuleMicroSeconds{V8WasmSeparateAsmAndWasm}"
-    units="microseconds" expires_after="2025-09-14">
+    units="microseconds" expires_after="2025-11-16">
   <owner>ecmziegler@chromium.org</owner>
   <owner>adamk@chromium.org</owner>
   <owner>clemensb@chromium.org</owner>
@@ -2336,7 +2336,7 @@
 </histogram>
 
 <histogram name="V8.WasmCompileModuleStreamingMicroSeconds"
-    units="microseconds" expires_after="2025-09-14">
+    units="microseconds" expires_after="2025-11-16">
   <owner>ecmziegler@chromium.org</owner>
   <owner>adamk@chromium.org</owner>
   <owner>clemensb@chromium.org</owner>
@@ -2407,7 +2407,7 @@
 </histogram>
 
 <histogram name="V8.WasmFinishModuleStreamingMicroSeconds" units="microseconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>bbudge@chromium.org</owner>
   <owner>clemensb@chromium.org</owner>
   <owner>adamk@chromium.org</owner>
@@ -2443,7 +2443,7 @@
 </histogram>
 
 <histogram name="V8.WasmFunctionsPerModule{V8WasmSeparateAsmAndWasm}"
-    units="functions" expires_after="2025-09-14">
+    units="functions" expires_after="2025-11-16">
   <owner>ecmziegler@chromium.org</owner>
   <owner>adamk@chromium.org</owner>
   <owner>clemensb@chromium.org</owner>
@@ -2459,7 +2459,7 @@
 </histogram>
 
 <histogram name="V8.WasmHugeFunctionSizeBytes{V8WasmSeparateAsmAndWasm}"
-    units="bytes" expires_after="2025-09-14">
+    units="bytes" expires_after="2025-11-16">
   <owner>ecmziegler@chromium.org</owner>
   <owner>adamk@chromium.org</owner>
   <owner>clemensb@chromium.org</owner>
@@ -2477,7 +2477,7 @@
 
 <histogram
     name="V8.WasmInstantiateModuleMicroSeconds{V8WasmSeparateAsmAndWasm}"
-    units="microseconds" expires_after="2025-09-14">
+    units="microseconds" expires_after="2025-11-16">
   <owner>ecmziegler@chromium.org</owner>
   <owner>adamk@chromium.org</owner>
   <owner>clemensb@chromium.org</owner>
@@ -2523,7 +2523,7 @@
 </histogram>
 
 <histogram name="V8.WasmMemoryProtectionKeysSupport" enum="BooleanSupported"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>clemensb@chromium.org</owner>
   <owner>jkummerow@chromium.org</owner>
   <owner>ecmziegler@chromium.org</owner>
@@ -2550,7 +2550,7 @@
 </histogram>
 
 <histogram name="V8.WasmModuleCodeSizeMiB" units="MB"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ecmziegler@chromium.org</owner>
   <owner>adamk@chromium.org</owner>
   <owner>clemensb@chromium.org</owner>
@@ -2562,7 +2562,7 @@
 </histogram>
 
 <histogram name="V8.WasmModuleCodeSizePercentFreed" units="%"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ecmziegler@chromium.org</owner>
   <owner>adamk@chromium.org</owner>
   <owner>clemensb@chromium.org</owner>
@@ -2599,7 +2599,7 @@
 </histogram>
 
 <histogram name="V8.WasmModuleNumberOfCodeSpaces" units="spaces"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>ecmziegler@chromium.org</owner>
   <owner>adamk@chromium.org</owner>
   <owner>clemensb@chromium.org</owner>
@@ -2627,7 +2627,7 @@
 </histogram>
 
 <histogram name="V8.WasmModulesPerEngine" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>clemensb@chromium.org</owner>
   <owner>ecmziegler@chromium.org</owner>
   <owner>wasm-v8@google.com</owner>
@@ -2638,7 +2638,7 @@
 </histogram>
 
 <histogram name="V8.WasmModulesPerIsolate" units="count"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>clemensb@chromium.org</owner>
   <owner>ecmziegler@chromium.org</owner>
   <owner>wasm-v8@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/variations/histograms.xml b/tools/metrics/histograms/metadata/variations/histograms.xml
index f7b70c0..03a5040 100644
--- a/tools/metrics/histograms/metadata/variations/histograms.xml
+++ b/tools/metrics/histograms/metadata/variations/histograms.xml
@@ -23,7 +23,7 @@
 <histograms>
 
 <histogram name="Variations.AppliedSeed.Size" units="bytes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>caitlinfischer@google.com</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -36,7 +36,7 @@
 </histogram>
 
 <histogram name="Variations.AppliedSeed.Size.V2" units="bytes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>caitlinfischer@google.com</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -49,7 +49,7 @@
 </histogram>
 
 <histogram name="Variations.AppliedSeed.StudyCount" units="studies"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>caitlinfischer@google.com</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -94,7 +94,7 @@
 </histogram>
 
 <histogram name="Variations.ExtendedSafeMode.BeaconFileStateAtStartup"
-    enum="BeaconFileState" expires_after="2025-09-14">
+    enum="BeaconFileState" expires_after="2025-11-16">
   <owner>caitlinfischer@google.com</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <component>1456342</component>
@@ -189,7 +189,7 @@
 </histogram>
 
 <histogram name="Variations.FirstRunResult" enum="VariationsFirstRunResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>asvitkine@chromium.org</owner>
   <owner>rkaplow@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
@@ -228,7 +228,7 @@
 </histogram>
 
 <histogram name="Variations.Headers.ExperimentCount" units="units"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>asvitkine@chromium.org</owner>
   <owner>rkaplow@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
@@ -391,7 +391,7 @@
 </histogram>
 
 <histogram name="Variations.SafeMode.LoadSafeSeed.Result"
-    enum="VariationsSeedLoadResult" expires_after="2025-09-14">
+    enum="VariationsSeedLoadResult" expires_after="2025-11-16">
   <owner>asvitkine@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -417,7 +417,7 @@
 </histogram>
 
 <histogram name="Variations.SafeMode.StoreSafeSeed.Result"
-    enum="VariationsSeedStoreResult" expires_after="2025-09-14">
+    enum="VariationsSeedStoreResult" expires_after="2025-11-16">
   <owner>asvitkine@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -441,7 +441,7 @@
 </histogram>
 
 <histogram name="Variations.SafeMode.Streak.Crashes" units="crashes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>asvitkine@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -514,7 +514,7 @@
 </histogram>
 
 <histogram name="Variations.SeedDateChange" enum="VariationsSeedDateChange"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>jwd@chromium.org</owner>
   <owner>asvitkine@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
@@ -528,7 +528,7 @@
 </histogram>
 
 <histogram name="Variations.SeedFetchResponseOrErrorCode{ConnectionType}"
-    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2025-09-14">
+    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2025-11-16">
   <owner>asvitkine@chromium.org</owner>
   <owner>rkaplow@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
@@ -574,7 +574,7 @@
 </histogram>
 
 <histogram name="Variations.SeedFileWriteEmptySeed.{SeedFile}"
-    enum="BooleanEmpty" expires_after="2025-09-14">
+    enum="BooleanEmpty" expires_after="2025-11-16">
   <owner>caitlinfischer@google.com</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -590,7 +590,7 @@
 </histogram>
 
 <histogram name="Variations.SeedFreshness" units="minutes"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>asvitkine@chromium.org</owner>
   <owner>rkaplow@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
@@ -653,7 +653,7 @@
 </histogram>
 
 <histogram name="Variations.SeedLoadResult" enum="VariationsSeedLoadResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>asvitkine@chromium.org</owner>
   <owner>rkaplow@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
@@ -665,7 +665,7 @@
 </histogram>
 
 <histogram name="Variations.SeedProcessingTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>asvitkine@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -677,7 +677,7 @@
 </histogram>
 
 <histogram name="Variations.SeedStoreResult" enum="VariationsSeedStoreResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>asvitkine@chromium.org</owner>
   <owner>rkaplow@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
@@ -688,7 +688,7 @@
 </histogram>
 
 <histogram name="Variations.SeedUsage" enum="VariationsSeedUsage"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>caitlinfischer@google.com</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -743,7 +743,7 @@
 </histogram>
 
 <histogram name="Variations.UserChannel" enum="UserChannels"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>asvitkine@chromium.org</owner>
   <owner>rkaplow@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
@@ -784,7 +784,7 @@
 </histogram>
 
 <histogram name="Variations.{Mode}CreateTrials.SeedExpiry"
-    enum="VariationsSeedExpiry" expires_after="2025-09-14">
+    enum="VariationsSeedExpiry" expires_after="2025-11-16">
   <owner>asvitkine@chromium.org</owner>
   <owner>rkaplow@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
diff --git a/tools/metrics/histograms/metadata/web_apk/histograms.xml b/tools/metrics/histograms/metadata/web_apk/histograms.xml
index 89d7e08..1554b3f 100644
--- a/tools/metrics/histograms/metadata/web_apk/histograms.xml
+++ b/tools/metrics/histograms/metadata/web_apk/histograms.xml
@@ -72,7 +72,7 @@
 </histogram>
 
 <histogram name="WebApk.Install.GooglePlayInstallResult"
-    enum="WebApkGooglePlayInstallResult" expires_after="2025-09-14">
+    enum="WebApkGooglePlayInstallResult" expires_after="2025-11-16">
   <owner>hartmanng@chromium.org</owner>
   <owner>src/chrome/android/webapk/OWNERS</owner>
   <summary>
@@ -104,7 +104,7 @@
 </histogram>
 
 <histogram name="WebApk.Install.InstallResult" enum="WebApkInstallResult"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>eirage@chromium.org</owner>
   <owner>hartmanng@chromium.org</owner>
   <owner>src/chrome/android/webapk/OWNERS</owner>
@@ -161,7 +161,7 @@
 </histogram>
 
 <histogram name="WebApk.LaunchFromViewIntent" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>hartmanng@chromium.org</owner>
   <owner>src/chrome/android/webapk/OWNERS</owner>
   <summary>
@@ -207,7 +207,7 @@
 </histogram>
 
 <histogram name="WebApk.ShellApkVersion2{WebApkDistributorType}" units="units"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>hartmanng@chromium.org</owner>
   <owner>src/chrome/android/webapk/OWNERS</owner>
   <summary>
@@ -336,7 +336,7 @@
 </histogram>
 
 <histogram name="WebApk.Uninstall{WebApkDistributorType}" enum="BooleanHit"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>hartmanng@chromium.org</owner>
   <owner>src/chrome/android/webapk/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/web_audio/histograms.xml b/tools/metrics/histograms/metadata/web_audio/histograms.xml
index 3a33e23..05a1a51f 100644
--- a/tools/metrics/histograms/metadata/web_audio/histograms.xml
+++ b/tools/metrics/histograms/metadata/web_audio/histograms.xml
@@ -95,7 +95,7 @@
 </histogram>
 
 <histogram name="WebAudio.AudioContext.CreateTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mjwilson@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <owner>cduvall@chromium.org</owner>
@@ -118,7 +118,7 @@
 </histogram>
 
 <histogram name="WebAudio.AudioContext.latencyHintCategory" units="units"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mjwilson@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <owner>src/third_party/blink/renderer/modules/webaudio/OWNERS</owner>
@@ -170,7 +170,7 @@
 </histogram>
 
 <histogram name="WebAudio.AudioContext.Operation"
-    enum="WebAudioContextOperation" expires_after="2025-09-14">
+    enum="WebAudioContextOperation" expires_after="2025-11-16">
   <owner>mjwilson@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <owner>fdoray@chromium.org</owner>
@@ -444,7 +444,7 @@
 </histogram>
 
 <histogram name="WebAudio.OfflineAudioContext.CreateTime" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>mjwilson@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <owner>cduvall@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/web_rtc/histograms.xml b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
index 528f01f..f31aee3b 100644
--- a/tools/metrics/histograms/metadata/web_rtc/histograms.xml
+++ b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
@@ -757,7 +757,7 @@
 </histogram>
 
 <histogram name="WebRTC.BWE.InitialBandwidthEstimate" units="kbps"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>holmer@chromium.org</owner>
   <summary>The bandwidth estimate 2 seconds into a WebRTC call.</summary>
 </histogram>
@@ -797,7 +797,7 @@
 </histogram>
 
 <histogram name="WebRTC.BWE.RampUpTimeTo2000kbpsInMs" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>holmer@chromium.org</owner>
   <summary>
     The time it takes the estimated bandwidth to reach 2000 kbps from the first
@@ -912,7 +912,7 @@
 </histogram>
 
 <histogram name="WebRTC.Call.BitrateReceivedInKbps" units="kbps"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>holmer@chromium.org</owner>
   <summary>
     Average total bitrate received during a call (audio + video + RTCP), counted
@@ -986,7 +986,7 @@
 </histogram>
 
 <histogram name="WebRTC.Call.VideoBitrateReceivedInKbps" units="kbps"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>holmer@chromium.org</owner>
   <summary>
     Average video bitrate received during a call, counted from first packet
@@ -1159,7 +1159,7 @@
 </histogram>
 
 <histogram name="WebRTC.DesktopCapture.Win.WgcDirtyRegionSupport"
-    enum="BooleanActive" expires_after="2025-09-13">
+    enum="BooleanActive" expires_after="2025-11-16">
   <owner>henrika@chromium.org</owner>
   <owner>webrtc-dev@chromium.org</owner>
   <summary>
@@ -1185,7 +1185,7 @@
 </histogram>
 
 <histogram name="WebRTC.DesktopCaptureCounters" enum="DesktopCaptureCounters"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>toprice@chromium.org</owner>
   <owner>webrtc-dev@chromium.org</owner>
   <summary>
@@ -1325,7 +1325,7 @@
 </histogram>
 
 <histogram name="WebRTC.PeerConnection.Duration.Signaling" units="microseconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>handellm@google.com</owner>
   <owner>webrtc-dev@chromium.org</owner>
   <summary>
@@ -1421,7 +1421,7 @@
 </histogram>
 
 <histogram name="WebRTC.PeerConnection.Latency.Signaling" units="microseconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>handellm@google.com</owner>
   <owner>webrtc-dev@chromium.org</owner>
   <summary>
@@ -1437,7 +1437,7 @@
 </histogram>
 
 <histogram name="WebRTC.PeerConnection.Latency.Worker" units="microseconds"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>handellm@google.com</owner>
   <owner>webrtc-dev@chromium.org</owner>
   <summary>
@@ -1719,7 +1719,7 @@
 </histogram>
 
 <histogram name="WebRTC.Screenshare.DesktopCapturerFullscreenDetector"
-    enum="Boolean" expires_after="2025-09-07">
+    enum="Boolean" expires_after="2025-11-16">
   <owner>kron@chromium.org</owner>
   <owner>webrtc-video@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/webapps/histograms.xml b/tools/metrics/histograms/metadata/webapps/histograms.xml
index d913988..6ad179b0 100644
--- a/tools/metrics/histograms/metadata/webapps/histograms.xml
+++ b/tools/metrics/histograms/metadata/webapps/histograms.xml
@@ -67,7 +67,7 @@
 </variants>
 
 <histogram name="AppBanners.BeforeInstallEvent"
-    enum="AppBannersBeforeInstallEvent" expires_after="2025-09-14">
+    enum="AppBannersBeforeInstallEvent" expires_after="2025-11-16">
   <owner>dominickn@chromium.org</owner>
   <owner>pjmclachlan@google.com</owner>
   <owner>pwa-team@google.com</owner>
@@ -94,7 +94,7 @@
 </histogram>
 
 <histogram name="AppBanners.DisplayEvent" enum="AppBannersDisplayEvent"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>pjmclachlan@google.com</owner>
   <owner>pcovell@google.com</owner>
   <summary>
@@ -106,7 +106,7 @@
 </histogram>
 
 <histogram name="AppBanners.InstallableStatusCode" enum="InstallableStatusCode"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dominickn@chromium.org</owner>
   <owner>pjmclachlan@google.com</owner>
   <summary>
@@ -132,7 +132,7 @@
 </histogram>
 
 <histogram name="AppBanners.UserResponse" enum="AppBannersUserResponse"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dominickn@chromium.org</owner>
   <owner>pjmclachlan@google.com</owner>
   <summary>
@@ -214,7 +214,7 @@
 </histogram>
 
 <histogram name="Launch.WebApp.DiyOrCrafted" enum="LaunchedAppType"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dibyapal@chromium.org</owner>
   <owner>pwa-team@google.com</owner>
   <summary>
@@ -224,7 +224,7 @@
 </histogram>
 
 <histogram name="Launch.WebAppDisplayMode" enum="WebAppDisplayMode"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>peter@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
@@ -270,7 +270,7 @@
 </histogram>
 
 <histogram name="Webapp.AmbientBadge.Terminate"
-    enum="InstallableAmbientBadgeState" expires_after="2025-09-14">
+    enum="InstallableAmbientBadgeState" expires_after="2025-11-16">
   <owner>eirage@chromium.org</owner>
   <owner>src/chrome/android/webapk/OWNERS</owner>
   <summary>
@@ -1022,7 +1022,7 @@
 </histogram>
 
 <histogram name="Webapp.Install.DisplayMode2" enum="WebAppDisplayMode"
-    expires_after="2025-09-15">
+    expires_after="2025-11-16">
   <owner>peter@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
@@ -1180,7 +1180,7 @@
 </histogram>
 
 <histogram name="WebApp.InstalledCount.ByUserNotLocallyInstalled" units="count"
-    expires_after="2025-09-12">
+    expires_after="2025-11-16">
   <owner>dmurph@chromium.org</owner>
   <owner>pwa-team@google.com</owner>
   <summary>
@@ -1192,7 +1192,7 @@
 </histogram>
 
 <histogram name="WebApp.InstalledCount.ByUserNotLocallyInstalled.SyncDisabled"
-    units="count" expires_after="2025-09-12">
+    units="count" expires_after="2025-11-16">
   <owner>mek@chromium.org</owner>
   <owner>pwa-team@google.com</owner>
   <summary>
@@ -1205,7 +1205,7 @@
 </histogram>
 
 <histogram name="WebApp.InstalledCount.NotSyncing.SyncEnabled" units="count"
-    expires_after="2025-09-12">
+    expires_after="2025-11-16">
   <owner>mek@chromium.org</owner>
   <owner>pwa-team@google.com</owner>
   <summary>
@@ -1551,7 +1551,7 @@
 </histogram>
 
 <histogram name="WebApp.Launcher.LaunchResult"
-    enum="WebAppLauncherLaunchResult" expires_after="2025-09-14">
+    enum="WebAppLauncherLaunchResult" expires_after="2025-11-16">
   <owner>davidbienvenu@chromium.org</owner>
   <owner>jessemckenna@google.com</owner>
   <summary>
@@ -2166,14 +2166,14 @@
 </histogram>
 
 <histogram name="WebApp.Shortcuts.Creation.Result"
-    enum="ShortcutsCreationResult" expires_after="2025-09-14">
+    enum="ShortcutsCreationResult" expires_after="2025-11-16">
   <owner>phillis@chromium.org</owner>
   <owner>dmurph@chromium.org</owner>
   <summary>Records the result of shortcut creation for PWA.</summary>
 </histogram>
 
 <histogram name="WebApp.Shortcuts.Delete.Result" enum="BooleanSuccess"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>dmurph@google.com</owner>
   <owner>pwa-team@google.com</owner>
   <summary>
@@ -2187,7 +2187,7 @@
 </histogram>
 
 <histogram name="WebApp.Shortcuts.Update.Result" enum="BooleanSuccess"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>camdenking@google.com</owner>
   <owner>pwa-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/webauthn/histograms.xml b/tools/metrics/histograms/metadata/webauthn/histograms.xml
index d1c91bd..168567b 100644
--- a/tools/metrics/histograms/metadata/webauthn/histograms.xml
+++ b/tools/metrics/histograms/metadata/webauthn/histograms.xml
@@ -23,7 +23,7 @@
 <histograms>
 
 <histogram name="WebAuthentication.Android.CredManAvailability" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>derinel@google.com</owner>
   <owner>kenrb@chromium.org</owner>
   <summary>
@@ -53,7 +53,7 @@
 </histogram>
 
 <histogram name="WebAuthentication.Android.CredManModalRequests"
-    enum="CredManGetRequestEnum" expires_after="2025-09-14">
+    enum="CredManGetRequestEnum" expires_after="2025-11-16">
   <owner>derinel@google.com</owner>
   <owner>kenrb@chromium.org</owner>
   <summary>
@@ -381,7 +381,7 @@
 </histogram>
 
 <histogram name="WebAuthentication.GPM.GetAssertion"
-    enum="GPMGetAssertionEvents" expires_after="2025-09-17">
+    enum="GPMGetAssertionEvents" expires_after="2025-11-16">
   <owner>natiahlyi@google.com</owner>
   <owner>chrome-webauthn@google.com</owner>
   <summary>
@@ -392,7 +392,7 @@
 </histogram>
 
 <histogram name="WebAuthentication.GPM.MakeCredential"
-    enum="GPMMakeCredentialEvents" expires_after="2025-09-17">
+    enum="GPMMakeCredentialEvents" expires_after="2025-11-16">
   <owner>natiahlyi@google.com</owner>
   <owner>chrome-webauthn@google.com</owner>
   <summary>
@@ -467,7 +467,7 @@
 </histogram>
 
 <histogram name="WebAuthentication.OnboardingEvents" enum="OnboardingEvents"
-    expires_after="2025-09-17">
+    expires_after="2025-11-16">
   <owner>natiahlyi@google.com</owner>
   <owner>chrome-webauthn@google.com</owner>
   <summary>
@@ -476,7 +476,7 @@
 </histogram>
 
 <histogram name="WebAuthentication.PinRenewalEvent"
-    enum="WebAuthenticationPinRenewalEvent" expires_after="2025-09-14">
+    enum="WebAuthenticationPinRenewalEvent" expires_after="2025-11-16">
   <owner>agl@google.com</owner>
   <owner>kenrb@chromium.org</owner>
   <summary>Records events related to GPM PIN renewals</summary>
@@ -495,7 +495,7 @@
 
 <histogram
     name="WebAuthentication.SignalAllAcceptedCredentialsRemovedGPMPasskey"
-    enum="SignalAllAcceptedCredentialsResult" expires_after="2025-09-17">
+    enum="SignalAllAcceptedCredentialsResult" expires_after="2025-11-16">
   <owner>nsatragno@chromium.org</owner>
   <owner>chrome-webauthn@google.com</owner>
   <summary>
@@ -506,7 +506,7 @@
 </histogram>
 
 <histogram name="WebAuthentication.SignalCurrentUserDetailsUpdatedGPMPasskey"
-    enum="SignalCurrentUserDetailsResult" expires_after="2025-09-17">
+    enum="SignalCurrentUserDetailsResult" expires_after="2025-11-16">
   <owner>nsatragno@chromium.org</owner>
   <owner>chrome-webauthn@google.com</owner>
   <summary>
@@ -517,7 +517,7 @@
 </histogram>
 
 <histogram name="WebAuthentication.SignalUnknownCredentialRemovedGPMPasskey"
-    enum="SignalUnknownCredentialResult" expires_after="2025-09-17">
+    enum="SignalUnknownCredentialResult" expires_after="2025-11-16">
   <owner>nsatragno@chromium.org</owner>
   <owner>chrome-webauthn@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/windows/histograms.xml b/tools/metrics/histograms/metadata/windows/histograms.xml
index a4c66d47..7787c1a 100644
--- a/tools/metrics/histograms/metadata/windows/histograms.xml
+++ b/tools/metrics/histograms/metadata/windows/histograms.xml
@@ -124,7 +124,7 @@
 </histogram>
 
 <histogram name="Windows.HasHighResolutionTimeTicks" enum="Boolean"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>brucedawson@chromium.org</owner>
   <owner>gab@chromium.org</owner>
   <summary>
@@ -193,7 +193,7 @@
 </histogram>
 
 <histogram name="Windows.LegacyDisplayIdAlgorithm" enum="UsedDisplayIdFallback"
-    expires_after="2025-09-14">
+    expires_after="2025-11-16">
   <owner>btriebw@google.com</owner>
   <owner>msw@google.com</owner>
   <summary>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index a9a9bbe..62cf3dd 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -22,7 +22,7 @@
         },
         "linux": {
             "hash": "da0c3e780366c0dde3891e30805d94d037011cf6",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/5a66f76326a04bf33f05433665cd77b7eb288fcc/trace_processor_shell"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/a9b5b095dac6ee69731e25683949fb181a57fa24/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc
index e8a5cba..138e7f6 100644
--- a/ui/base/ui_base_features.cc
+++ b/ui/base/ui_base_features.cc
@@ -152,6 +152,12 @@
              base::FEATURE_DISABLED_BY_DEFAULT);
 #endif  // BUILDFLAG(IS_LINUX)
 
+// Chrome for Linux should eventually use XInput2 key events.
+// See https://crbug.com/412608405 for context.
+BASE_FEATURE(kXInput2KeyEvents,
+             "XInput2KeyEvents",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Update of the virtual keyboard settings UI as described in
 // https://crbug.com/876901.
 BASE_FEATURE(kInputMethodSettingsUiUpdate,
diff --git a/ui/base/ui_base_features.h b/ui/base/ui_base_features.h
index fc6cf39..04e6c71 100644
--- a/ui/base/ui_base_features.h
+++ b/ui/base/ui_base_features.h
@@ -134,6 +134,9 @@
 BASE_DECLARE_FEATURE(kOverrideDefaultOzonePlatformHintToAuto);
 #endif  // BUILDFLAG(IS_LINUX)
 
+COMPONENT_EXPORT(UI_BASE_FEATURES)
+BASE_DECLARE_FEATURE(kXInput2KeyEvents);
+
 // Indicates whether DrmOverlayManager should used the synchronous API to
 // perform pageflip tests.
 COMPONENT_EXPORT(UI_BASE_FEATURES)
diff --git a/ui/events/devices/x11/BUILD.gn b/ui/events/devices/x11/BUILD.gn
index c12a3c4..d8a5b515 100644
--- a/ui/events/devices/x11/BUILD.gn
+++ b/ui/events/devices/x11/BUILD.gn
@@ -26,6 +26,7 @@
   deps = [
     "//base",
     "//skia",
+    "//ui/base:features",
     "//ui/display",
     "//ui/events:events_base",
     "//ui/events/devices",
diff --git a/ui/events/devices/x11/touch_factory_x11.cc b/ui/events/devices/x11/touch_factory_x11.cc
index eb67313..aa011d3 100644
--- a/ui/events/devices/x11/touch_factory_x11.cc
+++ b/ui/events/devices/x11/touch_factory_x11.cc
@@ -17,6 +17,7 @@
 #include "base/strings/string_split.h"
 #include "base/system/sys_info.h"
 #include "build/build_config.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/events/devices/x11/device_data_manager_x11.h"
 #include "ui/events/devices/x11/device_list_cache_x11.h"
@@ -226,8 +227,10 @@
   SetXinputMask(mask_data, x11::Input::HierarchyEvent::opcode);
   SetXinputMask(mask_data, x11::Input::DeviceChangedEvent::opcode);
 
-  SetXinputMask(mask_data, x11::Input::DeviceEvent::KeyPress);
-  SetXinputMask(mask_data, x11::Input::DeviceEvent::KeyRelease);
+  if (base::FeatureList::IsEnabled(features::kXInput2KeyEvents)) {
+    SetXinputMask(mask_data, x11::Input::DeviceEvent::KeyPress);
+    SetXinputMask(mask_data, x11::Input::DeviceEvent::KeyRelease);
+  }
 
   connection->xinput().XISelectEvents({window, {mask}});
   connection->Flush();
diff --git a/ui/events/x/events_x_utils.cc b/ui/events/x/events_x_utils.cc
index 0fcb43d..f7b051b 100644
--- a/ui/events/x/events_x_utils.cc
+++ b/ui/events/x/events_x_utils.cc
@@ -9,6 +9,7 @@
 
 #include <algorithm>
 #include <cmath>
+#include <numeric>
 
 #include "base/logging.h"
 #include "base/memory/singleton.h"
@@ -466,9 +467,9 @@
   return EventType::kUnknown;
 }
 
-int GetEventFlagsFromXKeyEvent(const x11::KeyEvent& key, bool send_event) {
-  const auto state = static_cast<int>(key.state);
-
+int GetEventFlagsFromXEvent(x11::KeyCode keycode,
+                            uint32_t state,
+                            bool send_event) {
 #if BUILDFLAG(IS_CHROMEOS)
   const int ime_fabricated_flag = 0;
 #else
@@ -481,10 +482,10 @@
   //
   // We have to send these fabricated key events to XIM so it can correctly
   // handle the character compositions.
-  const auto detail = static_cast<uint8_t>(key.detail);
   const auto shift_lock_mask =
-      static_cast<int>(x11::KeyButMask::Shift | x11::KeyButMask::Lock);
-  const bool fabricated_by_xim = detail == 0 && (state & ~shift_lock_mask) == 0;
+      static_cast<uint32_t>(x11::KeyButMask::Shift | x11::KeyButMask::Lock);
+  const bool fabricated_by_xim =
+      keycode == x11::KeyCode{} && (state & ~shift_lock_mask) == 0;
   const int ime_fabricated_flag =
       fabricated_by_xim ? ui::EF_IME_FABRICATED_KEY : 0;
 #endif
@@ -496,7 +497,8 @@
 int EventFlagsFromXEvent(const x11::Event& xev) {
   if (auto* key = xev.As<x11::KeyEvent>()) {
     XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(xev);
-    return GetEventFlagsFromXKeyEvent(*key, xev.send_event());
+    return GetEventFlagsFromXEvent(
+        key->detail, static_cast<uint32_t>(key->state), xev.send_event());
   }
   if (auto* button = xev.As<x11::ButtonEvent>()) {
     int flags = GetEventFlagsFromXState(button->state);
@@ -855,6 +857,18 @@
   return XModifierStateWatcher::GetInstance()->state();
 }
 
+uint32_t XkbStateFromXI2Event(const x11::Input::DeviceEvent& xievent) {
+  uint32_t mods = xievent.mods.effective & 0xff;
+  uint8_t buttons = std::reduce(xievent.button_mask.begin(),
+                                xievent.button_mask.end(), 0, std::bit_or<>());
+  // For some reason, the XInput2 button mask needs to be right-shifted by one
+  // to match the XKB button mask.
+  buttons = (buttons >> 1) & 0x1f;
+  // The group (bits 13-14 of the XKB state) is deliberately omitted because
+  // it's not used by GdkModifierType.
+  return (static_cast<uint32_t>(buttons) << 8) | mods;
+}
+
 void ResetTimestampRolloverCountersForTesting() {
   g_last_seen_timestamp_ms = 0;
   g_rollover_ms = 0;
diff --git a/ui/events/x/events_x_utils.h b/ui/events/x/events_x_utils.h
index a150779..3219d3c 100644
--- a/ui/events/x/events_x_utils.h
+++ b/ui/events/x/events_x_utils.h
@@ -7,7 +7,6 @@
 
 #include <stdint.h>
 
-
 #include "base/time/tick_clock.h"
 #include "base/time/time.h"
 #include "ui/events/event_constants.h"
@@ -23,10 +22,11 @@
 // Gets the EventType from a x11::Event.
 EVENTS_X_EXPORT EventType EventTypeFromXEvent(const x11::Event& xev);
 
-// Gets the EventFlags from a x11::KeyEvent.  `send_event` indicates if the
-// event was sent by an X11 client instead of the server.
-EVENTS_X_EXPORT int GetEventFlagsFromXKeyEvent(const x11::KeyEvent& key,
-                                               bool send_event);
+// Gets the event flags given a `keycode` a modifier `state`, and `send_event`
+// which indicates if the event was sent by an X11 client instead of the server.
+EVENTS_X_EXPORT int GetEventFlagsFromXEvent(x11::KeyCode keycode,
+                                            uint32_t state,
+                                            bool send_event);
 
 // Gets the EventFlags from a x11::Event.
 EVENTS_X_EXPORT int EventFlagsFromXEvent(const x11::Event& xev);
@@ -113,6 +113,12 @@
 
 EVENTS_X_EXPORT void ResetTimestampRolloverCountersForTesting();
 
+// This function is a shim for approximately emulating the state field of
+// legacy XKB key events, using information from XI2 key events, for
+// consumption by GTK.
+EVENTS_X_EXPORT uint32_t
+XkbStateFromXI2Event(const x11::Input::DeviceEvent& xievent);
+
 }  // namespace ui
 
 #endif  // UI_EVENTS_X_EVENTS_X_UTILS_H_
diff --git a/ui/events/x/x11_event_translation.cc b/ui/events/x/x11_event_translation.cc
index ce5eee1..9c90f08 100644
--- a/ui/events/x/x11_event_translation.cc
+++ b/ui/events/x/x11_event_translation.cc
@@ -4,7 +4,6 @@
 
 #include "ui/events/x/x11_event_translation.h"
 
-#include <numeric>
 #include <vector>
 
 #include "base/check.h"
@@ -27,21 +26,6 @@
 
 namespace {
 
-// This function is a shim for approximately emulating the state field of
-// legacy XKB key events, using information from XI2 key events, for
-// consumption by GTK.
-uint32_t XkbStateFromXI2Event(const x11::Input::DeviceEvent& xievent) {
-  uint32_t mods = xievent.mods.effective & 0xff;
-  uint8_t buttons = std::reduce(xievent.button_mask.begin(),
-                                xievent.button_mask.end(), 0, std::bit_or<>());
-  // For some reason, the XInput2 button mask needs to be right-shifted by one
-  // to match the XKB button mask.
-  buttons = (buttons >> 1) & 0x1f;
-  // The group (bits 13-14 of the XKB state) is deliberately omitted because
-  // it's not used by GdkModifierType.
-  return (static_cast<uint32_t>(buttons) << 8) | mods;
-}
-
 int XkbGroupForCoreState(int state) {
   return (state >> 13) & 0x3;
 }
diff --git a/ui/ozone/platform/x11/atk_event_conversion.cc b/ui/ozone/platform/x11/atk_event_conversion.cc
index 549efc6..949c20b 100644
--- a/ui/ozone/platform/x11/atk_event_conversion.cc
+++ b/ui/ozone/platform/x11/atk_event_conversion.cc
@@ -4,9 +4,12 @@
 
 #include "ui/ozone/platform/x11/atk_event_conversion.h"
 
+#include <cstdint>
+
 #include "base/check.h"
 #include "base/notreached.h"
 #include "ui/events/x/events_x_utils.h"
+#include "ui/events/x/x11_event_translation.h"
 #include "ui/gfx/x/connection.h"
 #include "ui/gfx/x/xproto.h"
 #include "ui/gfx/x/xproto_types.h"
@@ -14,45 +17,70 @@
 namespace ui {
 
 std::unique_ptr<AtkKeyEventStruct> AtkKeyEventFromXEvent(
-    const x11::KeyEvent& xkey,
-    bool send_event) {
+    const x11::Event& event) {
+  bool press;
+  x11::KeyCode keycode;
+  uint32_t state;
+  x11::Time time;
+  if (auto* xkey = event.As<x11::KeyEvent>()) {
+    press = xkey->opcode == x11::KeyEvent::Press;
+    keycode = xkey->detail;
+    state = static_cast<uint32_t>(xkey->state);
+    time = xkey->time;
+  } else if (auto* xdevice = event.As<x11::Input::DeviceEvent>()) {
+    if (xdevice->opcode != x11::Input::DeviceEvent::KeyPress &&
+        xdevice->opcode != x11::Input::DeviceEvent::KeyRelease) {
+      return nullptr;
+    }
+    press = xdevice->opcode == x11::Input::DeviceEvent::KeyPress;
+    keycode = static_cast<x11::KeyCode>(xdevice->detail);
+    state = XkbStateFromXI2Event(*xdevice);
+    time = xdevice->time;
+  } else {
+    return nullptr;
+  }
+
   auto atk_key_event = std::make_unique<AtkKeyEventStruct>();
 
-  atk_key_event->type = xkey.opcode == x11::KeyEvent::Press
-                            ? ATK_KEY_EVENT_PRESS
-                            : ATK_KEY_EVENT_RELEASE;
-
-  auto state = static_cast<int>(xkey.state);
-  auto keycode = xkey.detail;
-  auto keysym = x11::Connection::Get()->KeycodeToKeysym(keycode, state);
-
+  atk_key_event->type = press ? ATK_KEY_EVENT_PRESS : ATK_KEY_EVENT_RELEASE;
   atk_key_event->state = state;
-  atk_key_event->keyval = keysym;
-  atk_key_event->keycode = static_cast<uint8_t>(keycode);
-  atk_key_event->timestamp = static_cast<uint32_t>(xkey.time);
+  atk_key_event->keyval =
+      x11::Connection::Get()->KeycodeToKeysym(keycode, state);
+  atk_key_event->keycode = static_cast<guint16>(keycode);
+  atk_key_event->timestamp = static_cast<guint32>(time);
 
-  // This string property matches the one that was removed from GdkEventKey. In
-  // the future, ATK clients should no longer rely on it, so we set it to null.
+  // This string property matches the one that was removed from GdkEventKey.
+  // In the future, ATK clients should no longer rely on it, so we set it to
+  // null.
   atk_key_event->string = nullptr;
   atk_key_event->length = 0;
 
-  int flags = ui::GetEventFlagsFromXKeyEvent(xkey, send_event);
-  if (flags & ui::EF_SHIFT_DOWN)
+  int flags = ui::GetEventFlagsFromXEvent(keycode, state, event.send_event());
+
+  if (flags & ui::EF_SHIFT_DOWN) {
     atk_key_event->state |= AtkKeyModifierMask::kAtkShiftMask;
-  if (flags & ui::EF_CAPS_LOCK_ON)
+  }
+  if (flags & ui::EF_CAPS_LOCK_ON) {
     atk_key_event->state |= AtkKeyModifierMask::kAtkLockMask;
-  if (flags & ui::EF_CONTROL_DOWN)
+  }
+  if (flags & ui::EF_CONTROL_DOWN) {
     atk_key_event->state |= AtkKeyModifierMask::kAtkControlMask;
-  if (flags & ui::EF_ALT_DOWN)
+  }
+  if (flags & ui::EF_ALT_DOWN) {
     atk_key_event->state |= AtkKeyModifierMask::kAtkMod1Mask;
-  if (flags & ui::EF_NUM_LOCK_ON)
+  }
+  if (flags & ui::EF_NUM_LOCK_ON) {
     atk_key_event->state |= AtkKeyModifierMask::kAtkMod2Mask;
-  if (flags & ui::EF_MOD3_DOWN)
+  }
+  if (flags & ui::EF_MOD3_DOWN) {
     atk_key_event->state |= AtkKeyModifierMask::kAtkMod3Mask;
-  if (flags & ui::EF_COMMAND_DOWN)
+  }
+  if (flags & ui::EF_COMMAND_DOWN) {
     atk_key_event->state |= AtkKeyModifierMask::kAtkMod4Mask;
-  if (flags & ui::EF_ALTGR_DOWN)
+  }
+  if (flags & ui::EF_ALTGR_DOWN) {
     atk_key_event->state |= AtkKeyModifierMask::KAtkMod5Mask;
+  }
 
   return atk_key_event;
 }
diff --git a/ui/ozone/platform/x11/atk_event_conversion.h b/ui/ozone/platform/x11/atk_event_conversion.h
index e7936e4..2cb23e74 100644
--- a/ui/ozone/platform/x11/atk_event_conversion.h
+++ b/ui/ozone/platform/x11/atk_event_conversion.h
@@ -27,9 +27,10 @@
   KAtkMod5Mask = 1 << 7,
 } AtkKeyModifierMask;
 
+// Converts `event` to an ATK key event. Handles x11::KeyEvent and
+// x11::Input::DeviceEvent. Returns nullptr on failure.
 std::unique_ptr<AtkKeyEventStruct> AtkKeyEventFromXEvent(
-    const x11::KeyEvent& xkey,
-    bool send_event);
+    const x11::Event& event);
 
 }  // namespace ui
 
diff --git a/ui/ozone/platform/x11/x11_window.cc b/ui/ozone/platform/x11/x11_window.cc
index 8ddea1c9e..a83b9d9 100644
--- a/ui/ozone/platform/x11/x11_window.cc
+++ b/ui/ozone/platform/x11/x11_window.cc
@@ -194,6 +194,55 @@
   return *security_surfaces;
 }
 
+x11::Window GetWindowForEvent(const x11::Event& xev) {
+  if (auto* button = xev.As<x11::ButtonEvent>()) {
+    return button->event;
+  }
+  if (auto* key = xev.As<x11::KeyEvent>()) {
+    return key->event;
+  }
+  if (auto* motion = xev.As<x11::MotionNotifyEvent>()) {
+    return motion->event;
+  }
+  if (auto* xievent = xev.As<x11::Input::DeviceEvent>()) {
+    return xievent->event;
+  }
+  if (auto* crossing = xev.As<x11::CrossingEvent>()) {
+    return crossing->event;
+  }
+  if (auto* expose = xev.As<x11::ExposeEvent>()) {
+    return expose->window;
+  }
+  if (auto* focus = xev.As<x11::FocusEvent>()) {
+    return focus->event;
+  }
+  if (auto* configure = xev.As<x11::ConfigureNotifyEvent>()) {
+    return configure->window;
+  }
+  if (auto* crossing_input = xev.As<x11::Input::CrossingEvent>()) {
+    return crossing_input->event;
+  }
+  if (auto* map = xev.As<x11::MapNotifyEvent>()) {
+    return map->window;
+  }
+  if (auto* unmap = xev.As<x11::UnmapNotifyEvent>()) {
+    return unmap->window;
+  }
+  if (auto* client = xev.As<x11::ClientMessageEvent>()) {
+    return client->window;
+  }
+  if (auto* property = xev.As<x11::PropertyNotifyEvent>()) {
+    return property->window;
+  }
+  if (auto* selection = xev.As<x11::SelectionNotifyEvent>()) {
+    return selection->requestor;
+  }
+  if (auto* visibility = xev.As<x11::VisibilityNotifyEvent>()) {
+    return visibility->window;
+  }
+  return x11::Window::None;
+}
+
 }  // namespace
 
 X11Window::X11Window(PlatformWindowDelegate* platform_window_delegate)
@@ -1259,9 +1308,7 @@
   return bounds_wm_sync_.get();
 }
 
-bool X11Window::HandleAsAtkEvent(const x11::KeyEvent& key_event,
-                                 bool send_event,
-                                 bool transient) {
+bool X11Window::HandleAsAtkEvent(const x11::Event& event) {
 #if !BUILDFLAG(USE_ATK)
   // TODO(crbug.com/40653448): Support ATK in Ozone/X11.
   NOTREACHED();
@@ -1269,8 +1316,12 @@
   if (!x11_extension_delegate_) {
     return false;
   }
-  auto atk_key_event = AtkKeyEventFromXEvent(key_event, send_event);
-  return x11_extension_delegate_->OnAtkKeyEvent(atk_key_event.get(), transient);
+  auto atk_key_event = AtkKeyEventFromXEvent(event);
+  if (!atk_key_event) {
+    return false;
+  }
+  return x11_extension_delegate_->OnAtkKeyEvent(
+      atk_key_event.get(), GetWindowForEvent(event) == transient_window_);
 #endif
 }
 
@@ -1315,11 +1366,8 @@
     X11WindowManager::GetInstance()->MouseOnWindow(this);
   }
 #if BUILDFLAG(USE_ATK)
-  if (auto* key = current_xevent.As<x11::KeyEvent>()) {
-    if (HandleAsAtkEvent(*key, current_xevent.send_event(),
-                         key->event == transient_window_)) {
-      return POST_DISPATCH_STOP_PROPAGATION;
-    }
+  if (HandleAsAtkEvent(current_xevent)) {
+    return POST_DISPATCH_STOP_PROPAGATION;
   }
 #endif
 
@@ -2204,55 +2252,7 @@
 }
 
 bool X11Window::IsTargetedBy(const x11::Event& xev) const {
-  if (auto* button = xev.As<x11::ButtonEvent>()) {
-    return button->event == xwindow_;
-  }
-  if (auto* key = xev.As<x11::KeyEvent>()) {
-    return key->event == xwindow_;
-  }
-  if (auto* motion = xev.As<x11::MotionNotifyEvent>()) {
-    return motion->event == xwindow_;
-  }
-  if (auto* xievent = xev.As<x11::Input::DeviceEvent>()) {
-    return xievent->event == xwindow_;
-  }
-  if (auto* motion = xev.As<x11::MotionNotifyEvent>()) {
-    return motion->event == xwindow_;
-  }
-  if (auto* crossing = xev.As<x11::CrossingEvent>()) {
-    return crossing->event == xwindow_;
-  }
-  if (auto* expose = xev.As<x11::ExposeEvent>()) {
-    return expose->window == xwindow_;
-  }
-  if (auto* focus = xev.As<x11::FocusEvent>()) {
-    return focus->event == xwindow_;
-  }
-  if (auto* configure = xev.As<x11::ConfigureNotifyEvent>()) {
-    return configure->window == xwindow_;
-  }
-  if (auto* crossing_input = xev.As<x11::Input::CrossingEvent>()) {
-    return crossing_input->event == xwindow_;
-  }
-  if (auto* map = xev.As<x11::MapNotifyEvent>()) {
-    return map->window == xwindow_;
-  }
-  if (auto* unmap = xev.As<x11::UnmapNotifyEvent>()) {
-    return unmap->window == xwindow_;
-  }
-  if (auto* client = xev.As<x11::ClientMessageEvent>()) {
-    return client->window == xwindow_;
-  }
-  if (auto* property = xev.As<x11::PropertyNotifyEvent>()) {
-    return property->window == xwindow_;
-  }
-  if (auto* selection = xev.As<x11::SelectionNotifyEvent>()) {
-    return selection->requestor == xwindow_;
-  }
-  if (auto* visibility = xev.As<x11::VisibilityNotifyEvent>()) {
-    return visibility->window == xwindow_;
-  }
-  return false;
+  return xwindow_ != x11::Window::None && GetWindowForEvent(xev) == xwindow_;
 }
 
 void X11Window::SetTransientWindow(x11::Window window) {
diff --git a/ui/ozone/platform/x11/x11_window.h b/ui/ozone/platform/x11/x11_window.h
index 972eb4d..c19a0d7d 100644
--- a/ui/ozone/platform/x11/x11_window.h
+++ b/ui/ozone/platform/x11/x11_window.h
@@ -227,10 +227,8 @@
 
   void QuitDragLoop();
 
-  // Handles `key_event` as an Atk Key Event
-  bool HandleAsAtkEvent(const x11::KeyEvent& key_event,
-                        bool send_event,
-                        bool transient);
+  // Handles `event` as an Atk Key Event
+  bool HandleAsAtkEvent(const x11::Event& event);
 
   // Adjusts |requested_size_in_pixels| to avoid the WM "feature" where setting
   // the window size to the monitor size causes the WM to set the EWMH for
diff --git a/v8 b/v8
index 6dc75f0..2037825 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit 6dc75f0da012c4a9f638b78eefa86876a8349e77
+Subproject commit 203782512c9e2925ca7759c22abd07f59f16366d