diff --git a/DEPS b/DEPS
index 243c2e37..5870648 100644
--- a/DEPS
+++ b/DEPS
@@ -308,7 +308,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'src_internal_revision': 'cac0eda4f931b94c714acd417202a318f49cc1cd',
+  'src_internal_revision': '96d567763cde6fce93437285efeffbe518734435',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
@@ -316,11 +316,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '54df9a2e6ec0f28a218491cf15a4d6841779b4cc',
+  'v8_revision': '6e0661d6b0f95270c198d690bb2c4f54ba2acf4d',
   # 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': '0c0d10c4914aa427d1fe969508ca327fbeece913',
+  'angle_revision': '1724ab3641c825d2ed6fc76e20c3d20301e73696',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -400,7 +400,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': '60b8977eb329282198e284c76f6ac002f5320b45',
+  'devtools_frontend_revision': '9d9a7262df8a7db685524e449c0c08fc3f5f0e8c',
   # 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.
@@ -424,7 +424,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '23f08c798e68e28242fe3cd6990ec049695a930b',
+  'dawn_revision': 'd07825efa003125c46a2819c37081dbde0528277',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1115,10 +1115,10 @@
     'condition': 'non_git_source',
     'objects': [
       {
-        'object_name': 'meet-gpu-tests/840346920.tar.gz',
-        'sha256sum': '6b8fd087ccff4a3a71f025eab8dbaacf0c2aafa333094ab88d6d9c34f7df5acd',
-        'size_bytes': 279899236,
-        'generation': 1764923229945265,
+        'object_name': 'meet-gpu-tests/841497707.tar.gz',
+        'sha256sum': 'c69f9f23e86b431b890fa3260c91a48aeb404a3c118078ce9c940093b724dbbe',
+        'size_bytes': 279899387,
+        'generation': 1765182513274195,
       },
     ],
   },
@@ -1195,7 +1195,7 @@
       'packages': [
           {
               'package': 'chromium/chrome/android/orderfiles/arm',
-              'version': 'dZYQu3DP9aaWlHq0Fa9e5E08WuCGbTsZ8uoJSlg_nkoC',
+              'version': 'dmVPO_W27wruNBXShqIBgtUGdKz8XMw2BvT9NIlorw0C',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -1206,7 +1206,7 @@
       'packages': [
           {
               'package': 'chromium/chrome/android/orderfiles/arm64',
-              'version': 'qWD78zCgbRcktfbDN-NVmhHl4Nezm3StTjRgRpyCKaoC',
+              'version': 'IhWwwYw-VCiROoqjoUgb7gl8tB4cR7gBZz_HHd7OxxsC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -1217,7 +1217,7 @@
       'packages': [
           {
               'package': 'chromium/android_webview/tools/orderfiles/arm',
-              'version': 'Z7dxpqy_1i64GDrZgQmTk42oIsd0RC-thZ2veKuGIfQC',
+              'version': 'UeP3VMzc6YVY-2zU4l1AzC23_zu9TwS7wFHLMV3YxZkC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -1613,7 +1613,7 @@
     'packages': [
       {
         'package': 'chromium/chrome/test/data/variations/cipd',
-        'version': 'SXedGGUJh-QzWbgR9gl1wLbi-NDG8kgAPBkm4rBk3icC',
+        'version': 'mDYe4CwlW_ojJ4hA2-gTz4U6t5J8Hfx9r9EXNxHoFdEC',
       },
     ],
     'dep_type': 'cipd',
@@ -1624,12 +1624,12 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '78c4f1290f499ca246f0c7763f32c0c44a41a00d',
+    'fe18f1532fab7fddfaac4b6fb1b53dd222e0a532',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + '105a46915f47f94998e4a3084520835f24ea5a6c',
+    'url': Var('chromium_git') + '/website.git' + '@' + '1e6b9080b485c33e823208661cebb5e1f470960c',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -2109,7 +2109,7 @@
     Var('chromium_git') + '/external/github.com/google/flatbuffers.git' + '@' + '187240970746d00bbd26b0f5873ed54d2477f9f3',
 
   'src/third_party/fontconfig/src': {
-      'url': Var('chromium_git') + '/external/fontconfig.git' + '@' + '23b3fc6e58a13d126b9c30fafc9a16f8bd7143e9',
+      'url': Var('chromium_git') + '/external/fontconfig.git' + '@' + 'd62c2ab268d1679335daa8fb0ea6970f35224a76',
       'condition': 'checkout_linux',
   },
 
@@ -2610,7 +2610,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '8ab293da46a370dc17283a4d413242385e2033b1',
+    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + 'ec42dd387c2ab14c7369136e86898be936248315',
 
   'src/base/tracing/test/data': {
     'bucket': 'perfetto',
@@ -2794,7 +2794,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/r8',
-              'version': 'Fq2es0-0bCkqirMbdSj2rJpzrvuypdDva8j20lrg3wUC',
+              'version': 'aQiRizhSSPFGfHGuoC-0t2O4lFR5OY2qySLXtBS_vtIC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -2929,7 +2929,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/turbine',
-              'version': 'DV_E8eKAtXx3kTD4avzQC_CWVnH_yOQrf80YkYt77PAC',
+              'version': 'Fr97aXogWofWM2OLPzzlPsz6pDtCWNeOCpshlUq7nHMC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -2988,7 +2988,7 @@
     Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'),
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'd80cfa2a3d24618558f150bcca616a56cdca234a',
+    Var('webrtc_git') + '/src.git' + '@' + 'bfe531707560d16644de452e51e2c4fe40c46b91',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -3176,7 +3176,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'gs2z8aUF2clQ-2deJ8WTj--ByyAnJP2o_JRY5l0ROf0C',
+        'version': 'nLAi6FBQrimREDydiJC9KBDAKrrbCLNBjusC-RUmudcC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3759,7 +3759,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        'b751aaeca79d1952ef7631a2e83fbb5b00c133b8',
+        'fd52a146a6011abcc1c9c18a07f113fa192a9161',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc
index feaa750..55d30b537 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc
@@ -1759,8 +1759,12 @@
 void PartitionRoot::ResetBookkeepingForTesting() {
   ::partition_alloc::internal::ScopedGuard guard{
       internal::PartitionRootLock(this)};
-  max_size_of_allocated_bytes = total_size_of_allocated_bytes;
-  max_size_of_committed_pages.store(total_size_of_committed_pages);
+  max_size_of_allocated_bytes.store(
+      total_size_of_allocated_bytes.load(std::memory_order_relaxed),
+      std::memory_order_relaxed);
+  max_size_of_committed_pages.store(
+      total_size_of_committed_pages.load(std::memory_order_relaxed),
+      std::memory_order_relaxed);
 }
 
 void PartitionRoot::SetGlobalEmptySlotSpanRingIndexForTesting(int16_t index) {
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_root.h b/base/allocator/partition_allocator/src/partition_alloc/partition_root.h
index c2b2c62..befbb5b4 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_root.h
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_root.h
@@ -334,10 +334,8 @@
   std::atomic<size_t> max_size_of_committed_pages{0};
   std::atomic<size_t> total_size_of_super_pages{0};
   std::atomic<size_t> total_size_of_direct_mapped_pages{0};
-  size_t total_size_of_allocated_bytes
-      PA_GUARDED_BY(internal::PartitionRootLock(this)) = 0;
-  size_t max_size_of_allocated_bytes
-      PA_GUARDED_BY(internal::PartitionRootLock(this)) = 0;
+  std::atomic<size_t> total_size_of_allocated_bytes{0};
+  std::atomic<size_t> max_size_of_allocated_bytes{0};
   // Atomic, because system calls can be made without the lock held.
   std::atomic<uint64_t> syscall_count{};
   std::atomic<uint64_t> syscall_total_time_ns{};
@@ -450,12 +448,10 @@
       uintptr_t address);
 
   PA_ALWAYS_INLINE void DecreaseTotalSizeOfAllocatedBytes(uintptr_t slot_start,
-                                                          size_t len)
-      PA_EXCLUSIVE_LOCKS_REQUIRED(internal::PartitionRootLock(this));
+                                                          size_t len);
   PA_ALWAYS_INLINE void IncreaseTotalSizeOfAllocatedBytes(uintptr_t addr,
                                                           size_t len,
-                                                          size_t raw_size)
-      PA_EXCLUSIVE_LOCKS_REQUIRED(internal::PartitionRootLock(this));
+                                                          size_t raw_size);
   PA_ALWAYS_INLINE void IncreaseCommittedPages(size_t len);
   PA_ALWAYS_INLINE void DecreaseCommittedPages(size_t len);
   PA_ALWAYS_INLINE void DecommitSystemPagesForData(
@@ -744,13 +740,13 @@
   size_t get_total_size_of_allocated_bytes() const {
     // Since this is only used for bookkeeping, we don't care if the value is
     // stale, so no need to get a lock here.
-    return PA_TS_UNCHECKED_READ(total_size_of_allocated_bytes);
+    return total_size_of_allocated_bytes.load(std::memory_order_relaxed);
   }
 
   size_t get_max_size_of_allocated_bytes() const {
     // Since this is only used for bookkeeping, we don't care if the value is
     // stale, so no need to get a lock here.
-    return PA_TS_UNCHECKED_READ(max_size_of_allocated_bytes);
+    return max_size_of_allocated_bytes.load(std::memory_order_relaxed);
   }
 
   internal::pool_handle ChoosePool() const { return settings.pool_handle; }
@@ -1304,9 +1300,6 @@
 
   slot_start.Check(this);
 
-  IncreaseTotalSizeOfAllocatedBytes(
-      slot_start.value(), slot_span->GetSlotSizeForBookkeeping(), raw_size);
-
   *slot_size = slot_span->bucket->slot_size;
   return slot_start;
 }
@@ -1707,9 +1700,6 @@
 PA_ALWAYS_INLINE void PartitionRoot::FreeInSlotSpan(
     internal::UntaggedSlotStart slot_start,
     SlotSpanMetadata* slot_span) {
-  DecreaseTotalSizeOfAllocatedBytes(slot_start.value(),
-                                    slot_span->GetSlotSizeForBookkeeping());
-
   return slot_span->Free(slot_start.value(), this);
 }
 
@@ -1773,6 +1763,9 @@
     internal::SecureMemset(ptr, 0, GetSlotUsableSize(slot_span));
   }
 
+  DecreaseTotalSizeOfAllocatedBytes(slot_start.value(),
+                                    slot_span->GetSlotSizeForBookkeeping());
+
   ::partition_alloc::internal::ScopedGuard guard{
       internal::PartitionRootLock(this)};
   FreeInSlotSpan(slot_start.Untag(), slot_span);
@@ -1862,6 +1855,8 @@
   // may not expect that, but we never call this function on direct-mapped
   // allocations.
   PA_DCHECK(!IsDirectMappedBucket(slot_span->bucket));
+  DecreaseTotalSizeOfAllocatedBytes(slot_start.value(),
+                                    slot_span->GetSlotSizeForBookkeeping());
   FreeInSlotSpan(slot_start, slot_span);
 }
 
@@ -1901,9 +1896,20 @@
     uintptr_t addr,
     size_t len,
     size_t raw_size) {
-  total_size_of_allocated_bytes += len;
-  max_size_of_allocated_bytes =
-      std::max(max_size_of_allocated_bytes, total_size_of_allocated_bytes);
+  // |total_size_of_allocated_bytes| is only for debugging/stats, so relaxed
+  // memory order is sufficient.
+  size_t previous_total_size_of_allocated_bytes =
+      total_size_of_allocated_bytes.fetch_add(len, std::memory_order_relaxed);
+  size_t new_total_size_of_allocated_bytes =
+      previous_total_size_of_allocated_bytes + len;
+
+  size_t expected, desired;
+  do {
+    expected = max_size_of_allocated_bytes.load(std::memory_order_relaxed);
+    desired = std::max(expected, new_total_size_of_allocated_bytes);
+  } while (!max_size_of_allocated_bytes.compare_exchange_weak(
+      expected, desired, std::memory_order_relaxed, std::memory_order_relaxed));
+
 #if PA_BUILDFLAG(RECORD_ALLOC_INFO)
   partition_alloc::internal::RecordAllocOrFree(addr | 0x01, raw_size);
 #endif  // PA_BUILDFLAG(RECORD_ALLOC_INFO)
@@ -1914,8 +1920,11 @@
     size_t len) {
   // An underflow here means we've miscounted |total_size_of_allocated_bytes|
   // somewhere.
-  PA_DCHECK(total_size_of_allocated_bytes >= len);
-  total_size_of_allocated_bytes -= len;
+  // |total_size_of_allocated_bytes| is only for debugging/stats, so relaxed
+  // memory order is sufficient.
+  size_t previous_total_size_of_allocated_bytes =
+      total_size_of_allocated_bytes.fetch_sub(len, std::memory_order_relaxed);
+  PA_DCHECK(previous_total_size_of_allocated_bytes >= len);
 #if PA_BUILDFLAG(RECORD_ALLOC_INFO)
   partition_alloc::internal::RecordAllocOrFree(addr | 0x00, len);
 #endif  // PA_BUILDFLAG(RECORD_ALLOC_INFO)
@@ -2402,10 +2411,20 @@
     size_t* usable_size,
     size_t* slot_size,
     bool* is_already_zeroed) {
-  ::partition_alloc::internal::ScopedGuard guard{
-      internal::PartitionRootLock(this)};
-  return AllocFromBucket<flags>(bucket, raw_size, slot_span_alignment,
-                                usable_size, slot_size, is_already_zeroed);
+  internal::UntaggedSlotStart slot_start;
+  {
+    ::partition_alloc::internal::ScopedGuard guard{
+        internal::PartitionRootLock(this)};
+    slot_start =
+        AllocFromBucket<flags>(bucket, raw_size, slot_span_alignment,
+                               usable_size, slot_size, is_already_zeroed);
+  }
+
+  if (slot_start.value()) [[likely]] {
+    IncreaseTotalSizeOfAllocatedBytes(slot_start.value(), *slot_size, raw_size);
+  }
+
+  return slot_start;
 }
 
 template <AllocFlags flags>
diff --git a/base/allocator/partition_allocator/src/partition_alloc/thread_cache.cc b/base/allocator/partition_allocator/src/partition_alloc/thread_cache.cc
index d8393eb..eb4dee2f 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/thread_cache.cc
+++ b/base/allocator/partition_allocator/src/partition_alloc/thread_cache.cc
@@ -621,38 +621,54 @@
   PA_UNSAFE_TODO(PA_DCHECK(!root_->buckets[bucket_index].is_direct_mapped()));
 
   size_t allocated_slots = 0;
-  // Same as calling RawAlloc() |count| times, but acquires the lock only once.
-  internal::ScopedGuard guard(internal::PartitionRootLock(root_));
-  for (int i = 0; i < count; i++) {
-    // Thread cache fill should not trigger expensive operations, to not grab
-    // the lock for a long time needlessly, but also to not inflate memory
-    // usage. Indeed, without AllocFlags::kFastPathOrReturnNull, cache
-    // fill may activate a new PartitionPage, or even a new SuperPage, which is
-    // clearly not desirable.
-    //
-    // |raw_size| is set to the slot size, as we don't know it. However, it is
-    // only used for direct-mapped allocations and single-slot ones anyway,
-    // which are not handled here.
-    size_t ret_slot_size;
-    internal::UntaggedSlotStart slot_start = root_->AllocFromBucket<
-        AllocFlags::kFastPathOrReturnNull | AllocFlags::kReturnNull>(
-        &PA_UNSAFE_TODO(root_->buckets[bucket_index]),
-        PA_UNSAFE_TODO(root_->buckets[bucket_index]).slot_size /* raw_size */,
-        internal::PartitionPageSize(), &usable_size, &ret_slot_size,
-        &is_already_zeroed);
-    // Either the previous allocation would require a slow path allocation, or
-    // the central allocator is out of memory. If the bucket was filled with
-    // some objects, then the allocation will be handled normally. Otherwise,
-    // this goes to the central allocator, which will service the allocation,
-    // return nullptr or crash.
-    if (!slot_start) {
-      break;
-    }
-    PA_UNSAFE_TODO(
-        PA_DCHECK(ret_slot_size == root_->buckets[bucket_index].slot_size));
 
-    allocated_slots++;
-    PutInBucket(bucket, slot_start);
+  // limit is uint8_t, so max 255. count <= 255/8 = 31.
+  // Use a slightly larger buffer to be safe.
+  constexpr size_t kMaxBatchSize = 64;
+  count = std::min(count, static_cast<int>(kMaxBatchSize));
+  internal::UntaggedSlotStart slot_starts[kMaxBatchSize];
+
+  {
+    // Same as calling RawAlloc() |count| times, but acquires the lock only
+    // once.
+    internal::ScopedGuard guard(internal::PartitionRootLock(root_));
+    for (int i = 0; i < count; i++) {
+      // Thread cache fill should not trigger expensive operations, to not grab
+      // the lock for a long time needlessly, but also to not inflate memory
+      // usage. Indeed, without AllocFlags::kFastPathOrReturnNull, cache
+      // fill may activate a new PartitionPage, or even a new SuperPage, which
+      // is clearly not desirable.
+      //
+      // |raw_size| is set to the slot size, as we don't know it. However, it is
+      // only used for direct-mapped allocations and single-slot ones anyway,
+      // which are not handled here.
+      size_t ret_slot_size;
+      internal::UntaggedSlotStart slot_start = root_->AllocFromBucket<
+          AllocFlags::kFastPathOrReturnNull | AllocFlags::kReturnNull>(
+          &PA_UNSAFE_TODO(root_->buckets[bucket_index]),
+          PA_UNSAFE_TODO(root_->buckets[bucket_index]).slot_size /* raw_size */,
+          internal::PartitionPageSize(), &usable_size, &ret_slot_size,
+          &is_already_zeroed);
+      // Either the previous allocation would require a slow path allocation, or
+      // the central allocator is out of memory. If the bucket was filled with
+      // some objects, then the allocation will be handled normally. Otherwise,
+      // this goes to the central allocator, which will service the allocation,
+      // return nullptr or crash.
+      if (!slot_start) {
+        break;
+      }
+      PA_UNSAFE_TODO(
+          PA_DCHECK(ret_slot_size == root_->buckets[bucket_index].slot_size));
+
+      PA_UNSAFE_TODO(slot_starts[allocated_slots++]) = slot_start;
+    }
+  }
+
+  for (size_t i = 0; i < allocated_slots; ++i) {
+    root_->IncreaseTotalSizeOfAllocatedBytes(
+        PA_UNSAFE_TODO(slot_starts[i]).value(), bucket.slot_size,
+        bucket.slot_size);
+    PutInBucket(bucket, PA_UNSAFE_TODO(slot_starts[i]));
   }
 
   cached_memory_ += allocated_slots * bucket.slot_size;
diff --git a/base/trace_event/builtin_categories.h b/base/trace_event/builtin_categories.h
index af3c4d2..8649b24 100644
--- a/base/trace_event/builtin_categories.h
+++ b/base/trace_event/builtin_categories.h
@@ -303,11 +303,6 @@
         .SetTags("slow"),
     perfetto::Category(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"))
         .SetTags("slow"),
-    perfetto::Category(TRACE_DISABLED_BY_DEFAULT("identifiability"))
-        .SetTags("slow"),
-    perfetto::Category(
-        TRACE_DISABLED_BY_DEFAULT("identifiability.high_entropy_api"))
-        .SetTags("slow"),
     perfetto::Category(TRACE_DISABLED_BY_DEFAULT("cc"))
         .SetTags("slow"),
     perfetto::Category(TRACE_DISABLED_BY_DEFAULT("cc.debug")).SetTags("debug"),
diff --git a/base/tracing/protos/chrome_track_event.proto b/base/tracing/protos/chrome_track_event.proto
index 84cb96e..4c5ce3ad 100644
--- a/base/tracing/protos/chrome_track_event.proto
+++ b/base/tracing/protos/chrome_track_event.proto
@@ -1340,122 +1340,6 @@
   optional double first_contentful_paint_ms = 5;
 }
 
-// A serialisation of v8StackFrame class.
-message V8StackFrame {
-  // Code location (path to the script and line/column number)
-  message ScriptLocation {
-    optional string source_url = 1;
-    optional int64 line_number = 2;
-    optional int64 column_number = 3;
-  }
-
-  // The name of the function that was called
-  optional string function_name = 1;
-
-  // If the function was defined in a script, contains the location within the
-  // script.
-  optional ScriptLocation script_location = 2;
-}
-
-// Serializes the blink::ExecutionContext object.
-message BlinkExecutionContext {
-  // Definition of different context types.
-  enum ContextType {
-    UNKNOWN_CONTEXT = 0;
-    WINDOW = 1;
-    WORKLET = 2;
-    DEDICATED_WORKER = 3;
-    SHARED_WORKER = 4;
-    SERVICE_WORKER = 5;
-  }
-
-  // Definition of world type.
-  enum WorldType {
-    WORLD_UNKNOWN = 0;
-    WORLD_MAIN = 1;
-    WORLD_ISOLATED = 2;
-    WORLD_INSPECTOR_ISOLATED = 3;
-    WORLD_REG_EXP = 4;
-    WORLD_FOR_V8_CONTEXT_SNAPSHOT_NON_MAIN = 5;
-    WORLD_WORKER = 6;
-    WORLD_SHADOW_REALM = 7;
-  }
-
-  optional ContextType type = 1;
-  // Contains url of frame or worker.
-  optional string url = 2;
-  // The origin of the execution context.
-  optional string origin = 3;
-  // The world type of the execution context.
-  optional WorldType world_type = 4;
-}
-
-// Serializes the blink::SourceLocation object.
-message BlinkSourceLocation {
-  optional string function_name = 1;
-  optional int32 script_id = 2;
-  optional string url = 3;
-  optional int32 line_number = 4;
-  optional int32 column_number = 5;
-  optional string stack_trace = 6;
-  repeated V8StackFrame stack_frames = 7;
-}
-
-// Contains the meta information for high entropy events (like api calls)
-// that are to be traced for debugging in the context of identifiability study.
-message BlinkHighEntropyAPI {
-  // Serialization of a parameter passed to a javascript function.
-  // Contains the stringified type of the object and some string representation
-  // of its value.
-  message JSFunctionArgument {
-    // Definition of different types of function parameters.
-    enum ArgumentType {
-      UNKNOWN_TYPE = 0;
-      NULL_TYPE = 1;
-      UNDEFINED = 2;
-      BIGINT = 3;
-      BOOLEAN = 4;
-      FUNCTION = 5;
-      NUMBER = 6;
-      STRING = 7;
-      SYMBOL = 8;
-      OBJECT = 9;
-    }
-    optional ArgumentType type = 1;
-    optional string value = 2;
-  }
-
-  // Describes a Javascript API call.
-  message CalledJsApi {
-    // Contains class and function name of api called
-    // similar to "Navigator.languages.get".
-    optional string identifier = 1;
-    repeated JSFunctionArgument func_arguments = 2;
-
-    // Deprecated in favour of outer source_location. Not filled anymore in
-    // newer versions of chrome.
-    optional BlinkSourceLocation source_location = 3 [deprecated = true];
-  }
-  optional BlinkExecutionContext execution_context = 1;
-  optional CalledJsApi called_api = 2;
-  optional BlinkSourceLocation source_location = 3;
-
-  // Describes lookup of a font.
-  message FontLookup {
-    enum FontLookupType {
-      FONT_LOOKUP_UNKNOWN_TYPE = 0;
-      FONT_LOOKUP_UNIQUE_OR_FAMILY_NAME = 1;
-      FONT_LOOKUP_UNIQUE_NAME_ONLY = 2;
-    }
-    optional FontLookupType type = 1;
-    optional string name = 2;
-    optional uint64 weight = 3;
-    optional uint64 width = 4;
-    optional uint64 slope = 5;
-  }
-  optional FontLookup font_lookup = 4;
-}
-
 // Contains information about a tab switch measurement.
 message TabSwitchMeasurement {
   // Possible outcomes of a tab switch. Maps to
@@ -2875,6 +2759,8 @@
 };
 
 message ChromeTrackEvent {
+  reserved 1045;
+
   // Extension range for Chrome: 1000-1999
   // Next ID: 1079
   extend TrackEvent {
@@ -2973,8 +2859,6 @@
 
     optional UkmPageLoadTimingUpdate ukm_page_load_timing_update = 1044;
 
-    optional BlinkHighEntropyAPI high_entropy_api = 1045;
-
     optional TabSwitchMeasurement tab_switch_measurement = 1046;
 
     optional ScrollDeltas scroll_deltas = 1047;
diff --git a/build/config/freetype/BUILD.gn b/build/config/freetype/BUILD.gn
index 4b80753..a5d5ec6 100644
--- a/build/config/freetype/BUILD.gn
+++ b/build/config/freetype/BUILD.gn
@@ -20,8 +20,6 @@
   visibility = [
     "//chrome/test:*",
     "//content/test:*",
-    "//skia",
-    "//third_party/fontconfig",
 
     # The path/label of the PDFium target that depends on `freetype` is
     # different when building PDFium during Chromium build and during
@@ -29,7 +27,8 @@
     "//:freetype_common",  # Building standalone PDFium
     "//third_party/pdfium:freetype_common",  # Building Chromium
 
-    # Other dependencies that we think are PDFium-related:
+    # Other dependencies that are PDFium-related:
     "//components/services/font:font_service_unittests",
+    "//skia",
   ]
 }
diff --git a/build/config/freetype/freetype.gni b/build/config/freetype/freetype.gni
index 7ad6862d..dd89ad0 100644
--- a/build/config/freetype/freetype.gni
+++ b/build/config/freetype/freetype.gni
@@ -21,13 +21,8 @@
   # FreeType is completely replaced with the Rust-based Fontations set of
   # libraries plus Skia path rendering.
   #
-  # Ideally, this should be set with the same value as `enable_pdf` in
-  # //pdf/features.gni, but:
-  #
-  # - Cast on Linux depends on Fontconfig, and Fontconfig depends on FreeType:
-  #   https://crbug.com/370816215
-  #
-  # Note: //build should not import directly from //pdf for layering reasons.
-  enable_freetype =
-      !is_android && !is_ios && (is_linux || !is_castos) && !is_fuchsia
+  # This should be kept in sync with the value of `enable_pdf` in
+  # //pdf/features.gni, but for layering reasons,
+  # we can't import pdf's features.gni here.
+  enable_freetype = !is_android && !is_ios && !is_castos && !is_fuchsia
 }
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index b278bb8..59dd7da1 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -149,14 +149,9 @@
 void LayerTreePixelTest::DrawLayersOnThread(LayerTreeHostImpl* host_impl) {
   // Verify that we're using Gpu rasterization or not as requested.
   if (!use_software_renderer()) {
-    viz::RasterContextProvider* worker_context_provider =
-        host_impl->layer_tree_frame_sink()->worker_context_provider();
-    viz::RasterContextProvider::ScopedRasterContextLock lock(
-        worker_context_provider);
-    EXPECT_EQ(use_accelerated_raster(),
-              worker_context_provider->ContextCapabilities().gpu_rasterization);
+    EXPECT_EQ(use_accelerated_raster(), host_impl->use_gpu_rasterization());
     EXPECT_EQ(raster_type() == TestRasterType::kGpu,
-              worker_context_provider->ContextCapabilities().gpu_rasterization);
+              host_impl->use_gpu_rasterization());
   } else {
     EXPECT_EQ(TestRasterType::kBitmap, raster_type());
   }
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java
index e75a4664..4ca93cf 100644
--- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java
+++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java
@@ -11,7 +11,9 @@
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasItem;
 import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.not;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
@@ -50,6 +52,7 @@
 import org.chromium.base.task.test.CustomShadowAsyncTask;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Features;
+import org.chromium.base.test.util.Features.DisableFeatures;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManagerFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -97,6 +100,7 @@
         shadows = {CustomShadowAsyncTask.class})
 @Features.EnableFeatures({
     ChromeFeatureList.AUTOFILL_ANDROID_DESKTOP_KEYBOARD_ACCESSORY_REVAMP,
+    ChromeFeatureList.AUTOFILL_ANDROID_KEYBOARD_ACCESSORY_DYNAMIC_POSITIONING,
     ChromeFeatureList.AUTOFILL_ENABLE_KEYBOARD_ACCESSORY_CHIP_REDESIGN,
     ChromeFeatureList.AUTOFILL_ENABLE_KEYBOARD_ACCESSORY_CHIP_WIDTH_ADJUSTMENT,
 })
@@ -658,6 +662,7 @@
     }
 
     @Test
+    @DisableFeatures(ChromeFeatureList.AUTOFILL_ANDROID_KEYBOARD_ACCESSORY_DYNAMIC_POSITIONING)
     public void testLargeFormFactorHasDismissButton() {
         when(mMockIsLargeFormFactorSupplier.get()).thenReturn(true);
 
@@ -670,6 +675,19 @@
     }
 
     @Test
+    public void testLargeFormFactorDynamicPositioningHasNoDismissButton() {
+        when(mMockIsLargeFormFactorSupplier.get()).thenReturn(true);
+
+        mCoordinator.setSuggestions(List.of(mock(AutofillSuggestion.class)), mMockAutofillDelegate);
+
+        assertThat(mModel.get(BAR_ITEMS), contains(instanceOf(AutofillBarItem.class)));
+
+        assertThat(mModel.get(BAR_ITEMS_FIXED), not(hasItem(instanceOf(DismissBarItem.class))));
+        assertThat(mModel.get(BAR_ITEMS_FIXED), contains(instanceOf(SheetOpenerBarItem.class)));
+    }
+
+    @Test
+    @DisableFeatures(ChromeFeatureList.AUTOFILL_ANDROID_KEYBOARD_ACCESSORY_DYNAMIC_POSITIONING)
     public void testLargeFormFactorHasFixedItems() {
         when(mMockIsLargeFormFactorSupplier.get()).thenReturn(true);
         Provider<Action[]> generationProvider = new Provider<>(GENERATE_PASSWORD_AUTOMATIC);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/BatchUploadCardPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/BatchUploadCardPreference.java
index 1fcc0398..eb1e8f7a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/BatchUploadCardPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/BatchUploadCardPreference.java
@@ -55,9 +55,7 @@
         mBatchUploadCardCoordinator.immediatelyHideBatchUploadCardAndUpdateItsVisibility();
     }
 
-    @Override
-    public void onDetached() {
-        super.onDetached();
+    void destroy() {
         mBatchUploadCardCoordinator.destroy();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java
index be26093d..61302fb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java
@@ -305,6 +305,10 @@
         if (!mShouldReplaceSyncSettingsWithAccountSettings) {
             mSyncSetupInProgressHandle.close();
         }
+        if (mBatchUploadCardPreference != null) {
+            mBatchUploadCardPreference.destroy();
+            mBatchUploadCardPreference = null;
+        }
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/chrome_item_picker/ChromeItemPickerActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/chrome_item_picker/ChromeItemPickerActivityTest.java
index ae4d01f6..0ac5c74 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/chrome_item_picker/ChromeItemPickerActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/chrome_item_picker/ChromeItemPickerActivityTest.java
@@ -22,6 +22,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseActivityTestRule;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.DoNotBatch;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.omnibox.fusebox.FuseboxMediator;
@@ -79,6 +80,7 @@
 
     @Test
     @MediumTest
+    @DisabledTest(message = "https://crbug.com/463427787")
     public void testActivityThemeColorIsDefault() {
         doTestActivityThemeColor(false);
     }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index c1056f4..76651ae 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -485,8 +485,6 @@
     "enterprise/reporting/profile_report_generator_delegate_base.h",
     "enterprise/signals/profile_signals_collector.cc",
     "enterprise/signals/profile_signals_collector.h",
-    "enterprise/signin/enterprise_identity_service_factory.cc",
-    "enterprise/signin/enterprise_identity_service_factory.h",
     "enterprise/signin/interstitials/managed_profile_required_controller_client.cc",
     "enterprise/signin/interstitials/managed_profile_required_controller_client.h",
     "enterprise/signin/interstitials/managed_profile_required_page.cc",
@@ -2183,7 +2181,6 @@
     "//components/enterprise/device_trust",
     "//components/enterprise/encryption/cache",
     "//components/enterprise/obfuscation/core:enterprise_obfuscation",
-    "//components/enterprise/signin",
     "//components/error_page/common",
     "//components/error_page/content/browser",
     "//components/facilitated_payments/core/features",
diff --git a/chrome/browser/devtools/aida_service_handler.cc b/chrome/browser/devtools/aida_service_handler.cc
index 3bc00a2f..6ab2b3af 100644
--- a/chrome/browser/devtools/aida_service_handler.cc
+++ b/chrome/browser/devtools/aida_service_handler.cc
@@ -75,8 +75,8 @@
   return GURL("https://aida.googleapis.com");
 }
 
-signin::ScopeSet AidaServiceHandler::OAuthScopes() const {
-  return {GaiaConstants::kAidaOAuth2Scope};
+signin::OAuthConsumerId AidaServiceHandler::OAuthConsumerId() const {
+  return signin::OAuthConsumerId::kDevtoolsAida;
 }
 
 net::NetworkTrafficAnnotationTag
diff --git a/chrome/browser/devtools/aida_service_handler.h b/chrome/browser/devtools/aida_service_handler.h
index 31b9ac2..e9d178d 100644
--- a/chrome/browser/devtools/aida_service_handler.h
+++ b/chrome/browser/devtools/aida_service_handler.h
@@ -19,7 +19,7 @@
   void CanMakeRequest(Profile* profile,
                       base::OnceCallback<void(bool success)> callback) override;
   GURL BaseURL() const override;
-  signin::ScopeSet OAuthScopes() const override;
+  signin::OAuthConsumerId OAuthConsumerId() const override;
   net::NetworkTrafficAnnotationTag NetworkTrafficAnnotationTag() const override;
 };
 
diff --git a/chrome/browser/devtools/devtools_http_service_handler.cc b/chrome/browser/devtools/devtools_http_service_handler.cc
index 79251dc1..c647f69 100644
--- a/chrome/browser/devtools/devtools_http_service_handler.cc
+++ b/chrome/browser/devtools/devtools_http_service_handler.cc
@@ -59,7 +59,7 @@
   auto access_token_fetcher =
       identity_manager->CreateAccessTokenFetcherForAccount(
           identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSignin),
-          "DevTools_dispatchHttpRequest", OAuthScopes(),
+          OAuthConsumerId(),
           base::BindOnce(&DevToolsHttpServiceHandler::OnTokenFetched,
                          weak_factory_.GetWeakPtr(), std::move(callback),
                          profile, params, fetcher_id),
diff --git a/chrome/browser/devtools/devtools_http_service_handler.h b/chrome/browser/devtools/devtools_http_service_handler.h
index e357951..7661088 100644
--- a/chrome/browser/devtools/devtools_http_service_handler.h
+++ b/chrome/browser/devtools/devtools_http_service_handler.h
@@ -13,7 +13,6 @@
 #include "base/unguessable_token.h"
 #include "chrome/browser/devtools/devtools_dispatch_http_request_params.h"
 #include "components/signin/public/identity_manager/access_token_fetcher.h"
-#include "components/signin/public/identity_manager/scope_set.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/public/cpp/simple_url_loader.h"
@@ -69,8 +68,8 @@
   // Returns the base URL for the service's API.
   virtual GURL BaseURL() const = 0;
 
-  // Returns the OAuth scopes required for authenticating with the service.
-  virtual signin::ScopeSet OAuthScopes() const = 0;
+  // Returns the OAuth consumer id required for authenticating with the service.
+  virtual signin::OAuthConsumerId OAuthConsumerId() const = 0;
 
   // Returns the traffic annotation for the request.
   virtual net::NetworkTrafficAnnotationTag NetworkTrafficAnnotationTag()
diff --git a/chrome/browser/devtools/devtools_ui_bindings_unittest.cc b/chrome/browser/devtools/devtools_ui_bindings_unittest.cc
index fd59a68..c1bffff 100644
--- a/chrome/browser/devtools/devtools_ui_bindings_unittest.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings_unittest.cc
@@ -207,7 +207,9 @@
   ~TestServiceHandler() override = default;
 
   GURL BaseURL() const override { return GURL("http://localhost:8000"); }
-  signin::ScopeSet OAuthScopes() const override { return {}; }
+  signin::OAuthConsumerId OAuthConsumerId() const override {
+    return signin::OAuthConsumerId::kDevtoolsAida;
+  }
   net::NetworkTrafficAnnotationTag NetworkTrafficAnnotationTag()
       const override {
     return TRAFFIC_ANNOTATION_FOR_TESTS;
@@ -268,7 +270,9 @@
   ~MockServiceHandler() override = default;
 
   GURL BaseURL() const override { return GURL("http://localhost:8000"); }
-  signin::ScopeSet OAuthScopes() const override { return {}; }
+  signin::OAuthConsumerId OAuthConsumerId() const override {
+    return signin::OAuthConsumerId::kDevtoolsAida;
+  }
   net::NetworkTrafficAnnotationTag NetworkTrafficAnnotationTag()
       const override {
     return TRAFFIC_ANNOTATION_FOR_TESTS;
diff --git a/chrome/browser/devtools/features.cc b/chrome/browser/devtools/features.cc
index 468e82b9..48a79dd 100644
--- a/chrome/browser/devtools/features.cc
+++ b/chrome/browser/devtools/features.cc
@@ -210,7 +210,7 @@
 
 // If enabled, allows starting remote debugging in a running Chrome instance.
 BASE_FEATURE(kDevToolsAcceptDebuggingConnections,
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Whether the policy dialog should be shown instead of greying out the
 // Developer Tools toggle.
diff --git a/chrome/browser/devtools/gdp_service_handler.cc b/chrome/browser/devtools/gdp_service_handler.cc
index ed93f4e..0790711 100644
--- a/chrome/browser/devtools/gdp_service_handler.cc
+++ b/chrome/browser/devtools/gdp_service_handler.cc
@@ -51,8 +51,8 @@
   return GURL("https://developers.googleapis.com");
 }
 
-signin::ScopeSet GdpServiceHandler::OAuthScopes() const {
-  return {GaiaConstants::kGdpOAuth2Scope};
+signin::OAuthConsumerId GdpServiceHandler::OAuthConsumerId() const {
+  return signin::OAuthConsumerId::kDevtoolsGdp;
 }
 
 net::NetworkTrafficAnnotationTag
diff --git a/chrome/browser/devtools/gdp_service_handler.h b/chrome/browser/devtools/gdp_service_handler.h
index 266cd11..248c1d1 100644
--- a/chrome/browser/devtools/gdp_service_handler.h
+++ b/chrome/browser/devtools/gdp_service_handler.h
@@ -15,7 +15,7 @@
  private:
   // DevToolsHttpServiceHandler overrides:
   GURL BaseURL() const override;
-  signin::ScopeSet OAuthScopes() const override;
+  signin::OAuthConsumerId OAuthConsumerId() const override;
   net::NetworkTrafficAnnotationTag NetworkTrafficAnnotationTag() const override;
 };
 
diff --git a/chrome/browser/devtools/protocol/devtools_pwa_browsertest.cc b/chrome/browser/devtools/protocol/devtools_pwa_browsertest.cc
index ad61604..341583d7d34 100644
--- a/chrome/browser/devtools/protocol/devtools_pwa_browsertest.cc
+++ b/chrome/browser/devtools/protocol/devtools_pwa_browsertest.cc
@@ -607,7 +607,7 @@
   ASSERT_FALSE(AppExists(NotInstallableWebAppManifestId()));
 }
 
-// TODO(crbug.com/331214986): May want a test to trigger the installation
+// TODO(crbug.com/466316822): May want a test to trigger the installation
 // failure when installing from the url.
 
 IN_PROC_BROWSER_TEST_F(PWAProtocolTest,
@@ -904,7 +904,7 @@
   ASSERT_TRUE(result()->FindList("targetIds")->size() == 3);
 }
 
-// TODO(crbug.com/331214986): May want a test to trigger the LaunchFilesInApp
+// TODO(crbug.com/466313171): May want a test to trigger the LaunchFilesInApp
 // failure in LaunchApp callback.
 
 IN_PROC_BROWSER_TEST_F(PWAProtocolTest, LaunchFilesInApp_PartiallyFailed) {
diff --git a/chrome/browser/enterprise/signin/enterprise_identity_service_factory.cc b/chrome/browser/enterprise/signin/enterprise_identity_service_factory.cc
deleted file mode 100644
index 9c172a2..0000000
--- a/chrome/browser/enterprise/signin/enterprise_identity_service_factory.cc
+++ /dev/null
@@ -1,50 +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 "chrome/browser/enterprise/signin/enterprise_identity_service_factory.h"
-
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/identity_manager_factory.h"
-#include "components/enterprise/signin/enterprise_identity_service.h"
-
-namespace enterprise {
-
-// static
-EnterpriseIdentityServiceFactory*
-EnterpriseIdentityServiceFactory::GetInstance() {
-  static base::NoDestructor<EnterpriseIdentityServiceFactory> instance;
-  return instance.get();
-}
-
-// static
-EnterpriseIdentityService*
-EnterpriseIdentityServiceFactory::GetForBrowserContext(
-    content::BrowserContext* browser_context) {
-  return static_cast<EnterpriseIdentityService*>(
-      GetInstance()->GetServiceForBrowserContext(browser_context, true));
-}
-
-EnterpriseIdentityServiceFactory::EnterpriseIdentityServiceFactory()
-    : ProfileKeyedServiceFactory("EnterpriseIdentityService",
-                                 // Only create EnterpriseIdentityService for
-                                 // regular, non-Incognito profiles.
-                                 ProfileSelections::BuildForRegularProfile()) {
-  DependsOn(IdentityManagerFactory::GetInstance());
-}
-
-EnterpriseIdentityServiceFactory::~EnterpriseIdentityServiceFactory() = default;
-
-std::unique_ptr<KeyedService>
-EnterpriseIdentityServiceFactory::BuildServiceInstanceForBrowserContext(
-    content::BrowserContext* context) const {
-  auto* profile = Profile::FromBrowserContext(context);
-  if (!profile) {
-    return nullptr;
-  }
-
-  return EnterpriseIdentityService::Create(
-      IdentityManagerFactory::GetForProfile(profile));
-}
-
-}  // namespace enterprise
diff --git a/chrome/browser/enterprise/signin/enterprise_identity_service_factory.h b/chrome/browser/enterprise/signin/enterprise_identity_service_factory.h
deleted file mode 100644
index 2934c01..0000000
--- a/chrome/browser/enterprise/signin/enterprise_identity_service_factory.h
+++ /dev/null
@@ -1,41 +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 CHROME_BROWSER_ENTERPRISE_SIGNIN_ENTERPRISE_IDENTITY_SERVICE_FACTORY_H_
-#define CHROME_BROWSER_ENTERPRISE_SIGNIN_ENTERPRISE_IDENTITY_SERVICE_FACTORY_H_
-
-#include <memory>
-
-#include "base/no_destructor.h"
-#include "chrome/browser/profiles/profile_keyed_service_factory.h"
-
-namespace enterprise {
-
-class EnterpriseIdentityService;
-
-class EnterpriseIdentityServiceFactory : public ProfileKeyedServiceFactory {
- public:
-  static EnterpriseIdentityServiceFactory* GetInstance();
-  static EnterpriseIdentityService* GetForBrowserContext(
-      content::BrowserContext* browser_context);
-
-  EnterpriseIdentityServiceFactory(const EnterpriseIdentityServiceFactory&) =
-      delete;
-  EnterpriseIdentityServiceFactory& operator=(
-      const EnterpriseIdentityServiceFactory&) = delete;
-
- private:
-  friend base::NoDestructor<EnterpriseIdentityServiceFactory>;
-
-  EnterpriseIdentityServiceFactory();
-  ~EnterpriseIdentityServiceFactory() override;
-
-  // BrowserContextKeyedServiceFactory:
-  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
-      content::BrowserContext* context) const override;
-};
-
-}  // namespace enterprise
-
-#endif  // CHROME_BROWSER_ENTERPRISE_SIGNIN_ENTERPRISE_IDENTITY_SERVICE_FACTORY_H_
diff --git a/chrome/browser/extensions/api/tabs/windows_event_router.cc b/chrome/browser/extensions/api/tabs/windows_event_router.cc
index 37dc701..4e127c2 100644
--- a/chrome/browser/extensions/api/tabs/windows_event_router.cc
+++ b/chrome/browser/extensions/api/tabs/windows_event_router.cc
@@ -54,7 +54,6 @@
     filter_value = listener_filter->FindList(kWindowTypesKey);
   }
 
-  // TODO(crbug.com/41367902): Remove this.
   bool allow_dev_tools_windows = !!filter_value;
   if (!window_controller->IsVisibleToTabsAPIForExtension(
           extension, allow_dev_tools_windows)) {
@@ -77,7 +76,6 @@
     bool* dispatch_separate_event_out) {
   bool has_filter =
       listener_filter && listener_filter->contains(kWindowTypesKey);
-  // TODO(crbug.com/41367902): Remove this.
   bool allow_dev_tools_windows = has_filter;
   if (!window_controller->IsVisibleToTabsAPIForExtension(
           extension, allow_dev_tools_windows)) {
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 4d7f7e7..26cad25 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -9899,16 +9899,6 @@
     "expiry_milestone": 150
   },
   {
-    "name": "tab-resumption",
-    "owners": [ "olivierrobin@chromium.org", "gambard@chromium.org", "bling-flags@google.com" ],
-    "expiry_milestone": 142
-  },
-  {
-    "name": "tab-resumption-images",
-    "owners": [ "gambard@chromium.org", "olivierrobin@chromium.org", "bling-flags@google.com" ],
-    "expiry_milestone": 140
-  },
-  {
     "name": "tab-search-position-setting",
     "owners": [ "top-chrome-desktop-ui@google.com", "dpenning@chromium.org" ],
     "expiry_milestone": 137
diff --git a/chrome/browser/glic/glic_user_status_fetcher.cc b/chrome/browser/glic/glic_user_status_fetcher.cc
index 318566c..fd1cc37b 100644
--- a/chrome/browser/glic/glic_user_status_fetcher.cc
+++ b/chrome/browser/glic/glic_user_status_fetcher.cc
@@ -85,7 +85,6 @@
                                              base::RepeatingClosure callback)
     : profile_(profile), callback_(std::move(callback)) {
   endpoint_ = GURL(features::kGlicUserStatusUrl.Get());
-  oauth2_scope_ = features::kGeminiOAuth2Scope.Get();
 
   signin::IdentityManager* identity_manager =
       IdentityManagerFactory::GetForProfile(profile_);
@@ -290,7 +289,7 @@
           identity_manager,
           identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSignin),
           profile_->GetURLLoaderFactory(),
-          std::vector<std::string>{oauth2_scope_}),
+          signin::OAuthConsumerId::kGlicUserStatus),
       profile_->GetURLLoaderFactory(),
       base::ThreadPool::CreateSequencedTaskRunner(
           {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
diff --git a/chrome/browser/glic/glic_user_status_fetcher.h b/chrome/browser/glic/glic_user_status_fetcher.h
index 036212d..ee78094 100644
--- a/chrome/browser/glic/glic_user_status_fetcher.h
+++ b/chrome/browser/glic/glic_user_status_fetcher.h
@@ -142,7 +142,6 @@
   raw_ptr<Profile> profile_;
   const base::RepeatingClosure callback_;
   GURL endpoint_;
-  std::string oauth2_scope_;
 
   // Ensures we run a request at least as often as
   // `features::kGlicUserStatusRequestDelay`. Reset on browser start, when a
diff --git a/chrome/browser/keyboard_accessory/android/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java b/chrome/browser/keyboard_accessory/android/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java
index d1ab2ef0..c814146 100644
--- a/chrome/browser/keyboard_accessory/android/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java
+++ b/chrome/browser/keyboard_accessory/android/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java
@@ -178,7 +178,13 @@
         List<BarItem> fixedBarItems = new ArrayList<BarItem>();
         if (showFloatingKeyboardAccessory()) {
             fixedBarItems.add(mModel.get(SHEET_OPENER_ITEM));
-            fixedBarItems.add(mModel.get(DISMISS_ITEM));
+            // Dismiss button shouldn't be added when dynamic positioning is used.
+            // TODO(crbug.com/458610269): Delete the the dismiss button after dynamic positioning is
+            // launched.
+            if (!ChromeFeatureList.isEnabled(
+                    ChromeFeatureList.AUTOFILL_ANDROID_KEYBOARD_ACCESSORY_DYNAMIC_POSITIONING)) {
+                fixedBarItems.add(mModel.get(DISMISS_ITEM));
+            }
         } else {
             scrollableItems.add(mModel.get(SHEET_OPENER_ITEM));
         }
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index b37b77d7..5473ecbc 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -553,39 +553,6 @@
 // Please keep the list of deprecated prefs in chronological order. i.e. Add to
 // the bottom of the list, not here at the top.
 
-// Deprecated 12/2024.
-inline constexpr char kDeleteTimePeriodV2[] =
-    "browser.clear_data.time_period_v2";
-inline constexpr char kDeleteTimePeriodV2Basic[] =
-    "browser.clear_data.time_period_v2_basic";
-
-#if BUILDFLAG(IS_CHROMEOS)
-// Deprecated 12/2024
-inline const char kCryptAuthDeviceSyncIsRecoveringFromFailure[] =
-    "cryptauth.device_sync.is_recovering_from_failure";
-inline const char kCryptAuthDeviceSyncLastSyncTimeSeconds[] =
-    "cryptauth.device_sync.last_device_sync_time_seconds";
-inline const char kCryptAuthDeviceSyncReason[] = "cryptauth.device_sync.reason";
-inline const char kCryptAuthDeviceSyncUnlockKeys[] =
-    "cryptauth.device_sync.unlock_keys";
-inline const char kCryptAuthEnrollmentIsRecoveringFromFailure[] =
-    "cryptauth.enrollment.is_recovering_from_failure";
-inline const char kCryptAuthEnrollmentLastEnrollmentTimeSeconds[] =
-    "cryptauth.enrollment.last_enrollment_time_seconds";
-inline const char kCryptAuthEnrollmentReason[] = "cryptauth.enrollment.reason";
-inline const char kCryptAuthEnrollmentUserPublicKey[] =
-    "cryptauth.enrollment.user_public_key";
-inline const char kCryptAuthEnrollmentUserPrivateKey[] =
-    "cryptauth.enrollment.user_private_key";
-inline const char kLacrosLaunchOnLogin[] = "lacros.launch_on_login";
-inline const char kLacrosLaunchSwitch[] = "lacros_launch_switch";
-inline const char kLacrosSelection[] = "lacros_selection";
-#endif
-
-// Deprecated 12/2024.
-inline constexpr char kPageContentCollectionEnabled[] =
-    "page_content_collection.enabled";
-
 // Deprecated 01/2025.
 inline constexpr char kCompactModeEnabled[] = "compact_mode";
 
@@ -941,11 +908,6 @@
 // Register local state used only for migration (clearing or moving to a new
 // key).
 void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) {
-#if BUILDFLAG(IS_CHROMEOS)
-  // Deprecated 12/2024.
-  registry->RegisterIntegerPref(kLacrosLaunchSwitch, 0);
-  registry->RegisterIntegerPref(kLacrosSelection, 0);
-#endif
 
   // Deprecated 02/2025.
   registry->RegisterBooleanPref(kUserAgentClientHintsGREASEUpdateEnabled, true);
@@ -1043,34 +1005,6 @@
     user_prefs::PrefRegistrySyncable* registry) {
   chrome_browser_net::secure_dns::RegisterProbesSettingBackupPref(registry);
 
-  // Deprecated 12/2024.
-  registry->RegisterIntegerPref(kDeleteTimePeriodV2, -1);
-  registry->RegisterIntegerPref(kDeleteTimePeriodV2Basic, -1);
-
-#if BUILDFLAG(IS_CHROMEOS)
-  // Deprecated 12/2024
-  registry->RegisterDoublePref(kCryptAuthDeviceSyncLastSyncTimeSeconds, 0.0);
-  registry->RegisterBooleanPref(kCryptAuthDeviceSyncIsRecoveringFromFailure,
-                                false);
-  registry->RegisterIntegerPref(kCryptAuthDeviceSyncReason,
-                                cryptauth::INVOCATION_REASON_UNKNOWN);
-  registry->RegisterListPref(kCryptAuthDeviceSyncUnlockKeys);
-  registry->RegisterBooleanPref(kCryptAuthEnrollmentIsRecoveringFromFailure,
-                                false);
-  registry->RegisterDoublePref(kCryptAuthEnrollmentLastEnrollmentTimeSeconds,
-                               0.0);
-  registry->RegisterIntegerPref(kCryptAuthEnrollmentReason,
-                                cryptauth::INVOCATION_REASON_UNKNOWN);
-  registry->RegisterStringPref(kCryptAuthEnrollmentUserPublicKey,
-                               std::string());
-  registry->RegisterStringPref(kCryptAuthEnrollmentUserPrivateKey,
-                               std::string());
-  registry->RegisterBooleanPref(kLacrosLaunchOnLogin, false);
-#endif
-
-  // Deprecated 12/2024.
-  registry->RegisterBooleanPref(kPageContentCollectionEnabled, false);
-
   // Deprecated 01/2025.
   registry->RegisterBooleanPref(kCompactModeEnabled, false);
 
@@ -2139,12 +2073,6 @@
   // BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS
   // Please don't delete the preceding line. It is used by PRESUBMIT.py.
 
-  // Added 12/2024
-#if BUILDFLAG(IS_CHROMEOS)
-  local_state->ClearPref(kLacrosLaunchSwitch);
-  local_state->ClearPref(kLacrosSelection);
-#endif
-
   // Added 02/2025.
   local_state->ClearPref(kUserAgentClientHintsGREASEUpdateEnabled);
 
@@ -2298,27 +2226,6 @@
   MigrateDefaultBrowserLastDeclinedPref(profile_prefs);
 #endif
 
-  // Added 12/2024.
-  profile_prefs->ClearPref(kDeleteTimePeriodV2);
-  profile_prefs->ClearPref(kDeleteTimePeriodV2Basic);
-
-#if BUILDFLAG(IS_CHROMEOS)
-  // Deprecated 12/2024
-  profile_prefs->ClearPref(kCryptAuthDeviceSyncLastSyncTimeSeconds);
-  profile_prefs->ClearPref(kCryptAuthDeviceSyncIsRecoveringFromFailure);
-  profile_prefs->ClearPref(kCryptAuthDeviceSyncReason);
-  profile_prefs->ClearPref(kCryptAuthDeviceSyncUnlockKeys);
-  profile_prefs->ClearPref(kCryptAuthEnrollmentIsRecoveringFromFailure);
-  profile_prefs->ClearPref(kCryptAuthEnrollmentLastEnrollmentTimeSeconds);
-  profile_prefs->ClearPref(kCryptAuthEnrollmentReason);
-  profile_prefs->ClearPref(kCryptAuthEnrollmentUserPublicKey);
-  profile_prefs->ClearPref(kCryptAuthEnrollmentUserPrivateKey);
-  profile_prefs->ClearPref(kLacrosLaunchOnLogin);
-#endif
-
-  // Added 12/2024.
-  profile_prefs->ClearPref(kPageContentCollectionEnabled);
-
 #if !BUILDFLAG(IS_ANDROID)
   // Added 01/2025.
   password_manager::features_util::MigrateDefaultProfileStorePref(
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 122081c..1617afa57 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -80,7 +80,6 @@
 #include "chrome/browser/enterprise/reporting/cloud_profile_reporting_service_factory.h"
 #include "chrome/browser/enterprise/reporting/legacy_tech/legacy_tech_service.h"
 #include "chrome/browser/enterprise/signals/user_permission_service_factory.h"
-#include "chrome/browser/enterprise/signin/enterprise_identity_service_factory.h"
 #include "chrome/browser/enterprise/signin/profile_management_disclaimer_service_factory.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/favicon/history_ui_favicon_request_handler_factory.h"
@@ -880,7 +879,6 @@
   DriveServiceFactory::GetInstance();
   EnclaveManagerFactory::GetInstance();
 #endif
-  enterprise::EnterpriseIdentityServiceFactory::GetInstance();
   enterprise::ProfileIdServiceFactory::GetInstance();
 #if !BUILDFLAG(IS_CHROMEOS)
   enterprise_commands::UserRemoteCommandsServiceFactory::GetInstance();
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv2/background/phonetic_data_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/mv2/background/phonetic_data_test.js
index 16155b5ef..2e26cda 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv2/background/phonetic_data_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv2/background/phonetic_data_test.js
@@ -47,8 +47,6 @@
   ['働', 'ロウドウノドウ'],
 ]);
 
-// TODO(crbug.com/40758998): Polish phonetic readings so that users can disambiguate
-// more precisely.
 AX_TEST_F('ChromeVoxMV2PhoneticDataTest', 'forCharacterJa', function() {
   assertEquals('ヒラガナ アサヒ ノ ア', PhoneticData.forCharacter('あ', 'ja'));
   assertEquals('カタカナ アサヒ ノ ア', PhoneticData.forCharacter('ア', 'ja'));
diff --git a/chrome/browser/resources/side_panel/read_anything/app/app.ts b/chrome/browser/resources/side_panel/read_anything/app/app.ts
index a8539ed..2aaee9a 100644
--- a/chrome/browser/resources/side_panel/read_anything/app/app.ts
+++ b/chrome/browser/resources/side_panel/read_anything/app/app.ts
@@ -263,6 +263,10 @@
       this.speechController_.onLockScreen();
     };
 
+    chrome.readingMode.readingModeWillClose = () => {
+      this.speechController_.onReadingModeWillClose();
+    };
+
     chrome.readingMode.onTtsEngineInstalled = () => {
       this.voiceLanguageController_.onTtsEngineInstalled();
     };
diff --git a/chrome/browser/resources/side_panel/read_anything/app/read_anything.d.ts b/chrome/browser/resources/side_panel/read_anything/app/read_anything.d.ts
index d1ba137..6837d41 100644
--- a/chrome/browser/resources/side_panel/read_anything/app/read_anything.d.ts
+++ b/chrome/browser/resources/side_panel/read_anything/app/read_anything.d.ts
@@ -215,6 +215,9 @@
     // Called when the font is changed via the webui toolbar.
     function onFontChange(font: string): void;
 
+    // Called when reading mode is closed.
+    function readingModeWillClose(): void;
+
     // Called when the speech rate is changed via the webui toolbar.
     function onSpeechRateChange(rate: number): void;
 
diff --git a/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_controller.ts b/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_controller.ts
index b7d164f8..38c5cb1 100644
--- a/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_controller.ts
+++ b/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_controller.ts
@@ -176,6 +176,16 @@
     }
   }
 
+  // When the view is hidden with Immersive Reading Mode enabled, we should
+  // stop speaking.
+  onReadingModeWillClose() {
+    // TODO: crbug.com/466967616 - Ensure Read Aloud resume honors word
+    // boundaries after ReadingModeWillClose is called
+    if (this.isSpeechActive()) {
+      this.stopSpeech_(PauseActionSource.DEFAULT);
+    }
+  }
+
   onTabMuteStateChange(muted: boolean) {
     this.model_.setVolume(muted ? 0.0 : 1.0);
     this.onSpeechSettingsChange();
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request.cc b/chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request.cc
index d586018f..d93e167d 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h"
 #include "components/enterprise/connectors/core/features.h"
 #include "components/enterprise/obfuscation/core/download_obfuscator.h"
+#include "components/enterprise/obfuscation/core/utils.h"
 #include "components/file_access/scoped_file_access.h"
 #include "components/file_access/scoped_file_access_delegate.h"
 #include "content/public/browser/browser_thread.h"
@@ -261,13 +262,22 @@
   base::FilePath::StringType ext(file_name_.FinalExtension());
   std::ranges::transform(ext, ext.begin(), tolower);
   if (IsZipFile(ext, mime_type)) {
-    zip_analyzer_ = SandboxedZipAnalyzer::CreateAnalyzer(
-        path_,
-        /*password=*/password(),
-        base::BindOnce(&FileAnalysisRequest::OnCheckedForEncryption,
-                       weakptr_factory_.GetWeakPtr(),
-                       std::move(result_and_data.second)),
-        LaunchFileUtilService());
+    auto callback = base::BindOnce(&FileAnalysisRequest::OnCheckedForEncryption,
+                                   weakptr_factory_.GetWeakPtr(),
+                                   std::move(result_and_data.second));
+    if (is_obfuscated_ && base::FeatureList::IsEnabled(
+                              enterprise_obfuscation::
+                                  kEnterpriseFileObfuscationArchiveAnalyzer)) {
+      zip_analyzer_ = SandboxedZipAnalyzer::CreateObfuscatedAnalyzer(
+          path_,
+          /*password=*/password(), std::move(callback),
+          LaunchFileUtilService());
+    } else {
+      zip_analyzer_ = SandboxedZipAnalyzer::CreateAnalyzer(
+          path_,
+          /*password=*/password(), std::move(callback),
+          LaunchFileUtilService());
+    }
     zip_analyzer_->Start();
   } else if (IsRarFile(ext, mime_type)) {
     rar_analyzer_ = SandboxedRarAnalyzer::CreateAnalyzer(
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request_unittest.cc b/chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request_unittest.cc
index fc93a6e..590655c3 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request_unittest.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request_unittest.cc
@@ -594,4 +594,56 @@
   EXPECT_EQ(data.size, original_contents.size());
 }
 
+TEST_F(FileAnalysisRequestTest, ObfuscatedEncryptedZipFile) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures(
+      {enterprise_obfuscation::kEnterpriseFileObfuscation,
+       enterprise_obfuscation::kEnterpriseFileObfuscationArchiveAnalyzer},
+      {});
+
+  content::BrowserTaskEnvironment browser_task_environment;
+  content::InProcessUtilityThreadHelper in_process_utility_thread_helper;
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  base::FilePath test_zip;
+  EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_zip));
+  test_zip = test_zip.AppendASCII("safe_browsing")
+                 .AppendASCII("download_protection")
+                 .AppendASCII("encrypted.zip");
+
+  std::string original_contents;
+  ASSERT_TRUE(base::ReadFileToString(test_zip, &original_contents));
+
+  // Obfuscate the file contents and write to file.
+  enterprise_obfuscation::DownloadObfuscator obfuscator;
+  auto obfuscation_result =
+      obfuscator.ObfuscateChunk(base::as_byte_span(original_contents), true);
+
+  ASSERT_TRUE(obfuscation_result.has_value());
+  base::FilePath obfuscated_path =
+      temp_dir.GetPath().AppendASCII("obfuscated.zip");
+  ASSERT_TRUE(base::WriteFile(obfuscated_path, obfuscation_result.value()));
+
+  auto obfuscated_request =
+      MakeRequest(obfuscated_path, obfuscated_path.BaseName(),
+                  /*delay_opening_file=*/false,
+                  /*mime_type=*/"application/zip",
+                  /*is_obfuscated=*/true);
+  obfuscated_request->set_password("67890");  // Incorrect password
+
+  base::test::TestFuture<enterprise_connectors::ScanRequestUploadResult,
+                         BinaryUploadService::Request::Data>
+      future;
+  obfuscated_request->GetRequestData(future.GetCallback());
+  auto [result, data] = future.Take();
+
+  // Should detect encryption and fail because of incorrect password.
+  EXPECT_EQ(result,
+            enterprise_connectors::ScanRequestUploadResult::kFileEncrypted);
+  // Check if size has been updated to use the calculated unobfuscated content
+  // size.
+  EXPECT_EQ(data.size, original_contents.size());
+}
+
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/download_protection/download_item_metadata.cc b/chrome/browser/safe_browsing/download_protection/download_item_metadata.cc
index 6c592f8f..3a669216 100644
--- a/chrome/browser/safe_browsing/download_protection/download_item_metadata.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_item_metadata.cc
@@ -141,8 +141,8 @@
 std::unique_ptr<DownloadRequestMaker>
 DownloadItemMetadata::CreateDownloadRequestFromMetadata(
     scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor) const {
-  return DownloadRequestMaker::CreateFromDownloadItem(binary_feature_extractor,
-                                                      item_);
+  return DownloadRequestMaker::CreateFromDownloadItem(
+      binary_feature_extractor, item_, std::nullopt, IsObfuscated());
 }
 
 std::unique_ptr<DeepScanningMetadata::DownloadScopedObservation>
diff --git a/chrome/browser/safe_browsing/download_protection/download_request_maker.cc b/chrome/browser/safe_browsing/download_protection/download_request_maker.cc
index deef8da..062b951 100644
--- a/chrome/browser/safe_browsing/download_protection/download_request_maker.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_request_maker.cc
@@ -82,7 +82,8 @@
 DownloadRequestMaker::CreateFromDownloadItem(
     scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor,
     download::DownloadItem* item,
-    base::optional_ref<const std::string> password) {
+    base::optional_ref<const std::string> password,
+    bool is_obfuscated) {
   std::vector<ClientDownloadRequest::Resource> resources;
   for (size_t i = 0; i < item->GetUrlChain().size(); ++i) {
     ClientDownloadRequest::Resource resource;
@@ -123,14 +124,16 @@
       // owned by the CheckClientDownloadRequest, which observes for `item`
       // being destroyed, and deletes this if it is.
       base::BindOnce(&SetDownloadItemWarningData, item,
-                     password.CopyAsOptional()));
+                     password.CopyAsOptional()),
+      is_obfuscated);
 }
 
 // static
 std::unique_ptr<DownloadRequestMaker>
 DownloadRequestMaker::CreateFromFileSystemAccess(
     scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor,
-    const content::FileSystemAccessWriteItem& item) {
+    const content::FileSystemAccessWriteItem& item,
+    bool is_obfuscated) {
   ClientDownloadRequest::Resource resource;
   resource.set_url(
       ShortURLForReporting(GetFileSystemAccessDownloadUrl(item.frame_url)));
@@ -150,7 +153,7 @@
       item.sha256_hash, item.size,
       std::vector<ClientDownloadRequest::Resource>{resource},
       item.has_user_gesture, referrer_chain_data.get(), std::nullopt,
-      /*previous_token=*/"", base::DoNothing());
+      /*previous_token=*/"", base::DoNothing(), is_obfuscated);
 }
 
 DownloadRequestMaker::DownloadRequestMaker(
@@ -167,10 +170,13 @@
     ReferrerChainData* referrer_chain_data,
     base::optional_ref<const std::string> password,
     const std::string& previous_token,
-    base::OnceCallback<void(const FileAnalyzer::Results&)> on_results_callback)
+    base::OnceCallback<void(const FileAnalyzer::Results&)> on_results_callback,
+    bool is_obfuscated)
     : browser_context_(browser_context),
       request_(std::make_unique<ClientDownloadRequest>()),
       binary_feature_extractor_(binary_feature_extractor),
+      file_analyzer_(std::make_unique<FileAnalyzer>(binary_feature_extractor_,
+                                                    is_obfuscated)),
       tab_urls_(tab_urls),
       target_file_name_(target_file_name),
       full_path_(full_path),
diff --git a/chrome/browser/safe_browsing/download_protection/download_request_maker.h b/chrome/browser/safe_browsing/download_protection/download_request_maker.h
index 2f323d9..4078ef829 100644
--- a/chrome/browser/safe_browsing/download_protection/download_request_maker.h
+++ b/chrome/browser/safe_browsing/download_protection/download_request_maker.h
@@ -44,11 +44,13 @@
   static std::unique_ptr<DownloadRequestMaker> CreateFromDownloadItem(
       scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor,
       download::DownloadItem* item,
-      base::optional_ref<const std::string> password = std::nullopt);
+      base::optional_ref<const std::string> password = std::nullopt,
+      bool is_obfuscated = false);
 
   static std::unique_ptr<DownloadRequestMaker> CreateFromFileSystemAccess(
       scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor,
-      const content::FileSystemAccessWriteItem& item);
+      const content::FileSystemAccessWriteItem& item,
+      bool is_obfuscated = false);
 
   DownloadRequestMaker(
       scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor,
@@ -65,7 +67,8 @@
       base::optional_ref<const std::string> password,
       const std::string& previous_token,
       base::OnceCallback<void(const FileAnalyzer::Results&)>
-          on_results_callback);
+          on_results_callback,
+      bool is_obfuscated = false);
 
   DownloadRequestMaker(const DownloadRequestMaker&) = delete;
   DownloadRequestMaker& operator=(const DownloadRequestMaker&) = delete;
@@ -95,8 +98,7 @@
   raw_ptr<content::BrowserContext> browser_context_;
   std::unique_ptr<ClientDownloadRequest> request_;
   const scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor_;
-  const std::unique_ptr<FileAnalyzer> file_analyzer_ =
-      std::make_unique<FileAnalyzer>(binary_feature_extractor_);
+  const std::unique_ptr<FileAnalyzer> file_analyzer_;
   base::CancelableTaskTracker request_tracker_;  // For HistoryService lookup.
 
   // The current URL for the WebContents that initiated the download, and its
diff --git a/chrome/browser/safe_browsing/download_protection/file_analyzer.cc b/chrome/browser/safe_browsing/download_protection/file_analyzer.cc
index d277ead..4442bea 100644
--- a/chrome/browser/safe_browsing/download_protection/file_analyzer.cc
+++ b/chrome/browser/safe_browsing/download_protection/file_analyzer.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
 #include "chrome/common/safe_browsing/archive_analyzer_results.h"
 #include "chrome/common/safe_browsing/download_type_util.h"
+#include "components/enterprise/obfuscation/core/utils.h"
 #include "components/safe_browsing/content/common/file_type_policies.h"
 #include "components/safe_browsing/content/common/proto/download_file_types.pb.h"
 #include "components/safe_browsing/core/common/features.h"
@@ -49,8 +50,12 @@
 FileAnalyzer::Results::Results(const FileAnalyzer::Results& other) = default;
 
 FileAnalyzer::FileAnalyzer(
-    scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor)
+    scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor,
+    bool is_obfuscated)
     : binary_feature_extractor_(binary_feature_extractor) {
+#if !BUILDFLAG(IS_ANDROID)
+  is_obfuscated_ = is_obfuscated;
+#endif
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
@@ -136,11 +141,21 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // We give the zip analyzer a weak pointer to this object.
-  zip_analyzer_ = SandboxedZipAnalyzer::CreateAnalyzer(
-      tmp_path_, password_,
-      base::BindOnce(&FileAnalyzer::OnZipAnalysisFinished,
-                     weakptr_factory_.GetWeakPtr()),
-      LaunchFileUtilService());
+  if (is_obfuscated_ &&
+      base::FeatureList::IsEnabled(
+          enterprise_obfuscation::kEnterpriseFileObfuscationArchiveAnalyzer)) {
+    zip_analyzer_ = SandboxedZipAnalyzer::CreateObfuscatedAnalyzer(
+        tmp_path_, password_,
+        base::BindOnce(&FileAnalyzer::OnZipAnalysisFinished,
+                       weakptr_factory_.GetWeakPtr()),
+        LaunchFileUtilService());
+  } else {
+    zip_analyzer_ = SandboxedZipAnalyzer::CreateAnalyzer(
+        tmp_path_, password_,
+        base::BindOnce(&FileAnalyzer::OnZipAnalysisFinished,
+                       weakptr_factory_.GetWeakPtr()),
+        LaunchFileUtilService());
+  }
   zip_analyzer_->Start();
 }
 
diff --git a/chrome/browser/safe_browsing/download_protection/file_analyzer.h b/chrome/browser/safe_browsing/download_protection/file_analyzer.h
index 678a98d..03b8293 100644
--- a/chrome/browser/safe_browsing/download_protection/file_analyzer.h
+++ b/chrome/browser/safe_browsing/download_protection/file_analyzer.h
@@ -88,7 +88,8 @@
   };
 
   explicit FileAnalyzer(
-      scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor);
+      scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor,
+      bool is_obfuscated = false);
   ~FileAnalyzer();
   void Start(const base::FilePath& target_file_name,
              const base::FilePath& tmp_path,
@@ -142,6 +143,8 @@
 
   std::unique_ptr<SandboxedRarAnalyzer, base::OnTaskRunnerDeleter>
       rar_analyzer_{nullptr, base::OnTaskRunnerDeleter(nullptr)};
+
+  bool is_obfuscated_ = false;
 #endif
 
 #if BUILDFLAG(IS_MAC)
diff --git a/chrome/browser/safe_browsing/download_protection/file_analyzer_unittest.cc b/chrome/browser/safe_browsing/download_protection/file_analyzer_unittest.cc
index 2da2ec60..59d7cbda 100644
--- a/chrome/browser/safe_browsing/download_protection/file_analyzer_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection/file_analyzer_unittest.cc
@@ -16,6 +16,8 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/safe_browsing/archive_analyzer_results.h"
 #include "chrome/common/safe_browsing/mock_binary_feature_extractor.h"
+#include "components/enterprise/obfuscation/core/download_obfuscator.h"
+#include "components/enterprise/obfuscation/core/utils.h"
 #include "components/safe_browsing/content/common/file_type_policies_test_util.h"
 #include "components/safe_browsing/content/common/proto/download_file_types.pb.h"
 #include "components/safe_browsing/core/common/features.h"
@@ -1092,6 +1094,55 @@
   EXPECT_EQ(result_.archived_binaries[1].length(), 0);
   EXPECT_EQ(result_.inspection_performed, DownloadFileType::SEVEN_ZIP);
 }
+
+TEST_F(FileAnalyzerTest, ObfuscatedZipAnalysis) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures(
+      {enterprise_obfuscation::kEnterpriseFileObfuscation,
+       enterprise_obfuscation::kEnterpriseFileObfuscationArchiveAnalyzer},
+      {});
+
+  scoped_refptr<MockBinaryFeatureExtractor> extractor =
+      new testing::StrictMock<MockBinaryFeatureExtractor>();
+  FileAnalyzer analyzer(extractor, /*is_obfuscated=*/true);
+  base::RunLoop run_loop;
+
+  base::FilePath target_file_name(FILE_PATH_LITERAL("target.zip"));
+  base::FilePath tmp_path =
+      temp_dir_.GetPath().Append(FILE_PATH_LITERAL("tmp.crdownload"));
+
+  base::ScopedTempDir zip_source_dir;
+  ASSERT_TRUE(zip_source_dir.CreateUniqueTempDir());
+  std::string file_contents = "dummy file";
+  ASSERT_TRUE(base::WriteFile(
+      zip_source_dir.GetPath().Append(FILE_PATH_LITERAL("file.exe")),
+      file_contents));
+  base::FilePath zip_path = temp_dir_.GetPath().AppendASCII("original.zip");
+  ASSERT_TRUE(zip::Zip(zip_source_dir.GetPath(), zip_path,
+                       /* include_hidden_files= */ false));
+
+  // Obfuscate
+  std::string original_zip_content;
+  ASSERT_TRUE(base::ReadFileToString(zip_path, &original_zip_content));
+  enterprise_obfuscation::DownloadObfuscator obfuscator;
+  auto obfuscation_result =
+      obfuscator.ObfuscateChunk(base::as_byte_span(original_zip_content), true);
+  ASSERT_TRUE(obfuscation_result.has_value());
+  ASSERT_TRUE(base::WriteFile(tmp_path, obfuscation_result.value()));
+
+  analyzer.Start(
+      target_file_name, tmp_path, /*password=*/std::nullopt,
+      base::BindOnce(&FileAnalyzerTest::DoneCallback, base::Unretained(this),
+                     run_loop.QuitClosure()));
+  run_loop.Run();
+
+  ASSERT_TRUE(has_result_);
+  // It should be successfully analyzed as a zip
+  EXPECT_EQ(result_.inspection_performed, DownloadFileType::ZIP);
+  EXPECT_TRUE(result_.archived_executable);
+  EXPECT_EQ(result_.archive_summary.parser_status(),
+            ClientDownloadRequest::ArchiveSummary::VALID);
+}
 #endif  // !BUILDFLAG(IS_ANDROID)
 
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/download_protection/file_system_access_metadata.cc b/chrome/browser/safe_browsing/download_protection/file_system_access_metadata.cc
index 26a09503b..dcf6045 100644
--- a/chrome/browser/safe_browsing/download_protection/file_system_access_metadata.cc
+++ b/chrome/browser/safe_browsing/download_protection/file_system_access_metadata.cc
@@ -95,6 +95,7 @@
 
 bool FileSystemAccessMetadata::IsObfuscated() const {
   // No support for enterprise obfuscation for filesystem access API.
+  // TODO(crbug.com/378490429): Add support for obfuscated files.
   return false;
 }
 
@@ -130,7 +131,7 @@
 FileSystemAccessMetadata::CreateDownloadRequestFromMetadata(
     scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor) const {
   return DownloadRequestMaker::CreateFromFileSystemAccess(
-      binary_feature_extractor, *item_);
+      binary_feature_extractor, *item_, IsObfuscated());
 }
 
 std::unique_ptr<DeepScanningMetadata::DownloadScopedObservation>
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc
index 9fdb57e3..22e337b 100644
--- a/chrome/browser/signin/chrome_signin_client.cc
+++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -38,6 +38,7 @@
 #include "chrome/browser/ui/hats/survey_config.h"
 #include "chrome/common/buildflags.h"
 #include "chrome/common/channel_info.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/metrics/metrics_service.h"
@@ -197,6 +198,17 @@
         signin::oauth_consumer_name::kEnterprisePlusAddressName,
         {plus_addresses::features::kEnterprisePlusAddressOAuthScope.Get()});
   }
+
+  signin::OAuthConsumer GetOAuthConsumerForGlicUserStatus() const override {
+#if BUILDFLAG(ENABLE_GLIC)
+    CHECK(base::FeatureList::IsEnabled(features::kGlicUserStatusCheck));
+    return signin::OAuthConsumer(
+        signin::oauth_consumer_name::kGlicUserStatusName,
+        {features::kGeminiOAuth2Scope.Get()});
+#else
+    NOTREACHED();
+#endif
+  }
 };
 
 }  // namespace
diff --git a/chrome/browser/ui/autofill/BUILD.gn b/chrome/browser/ui/autofill/BUILD.gn
index abee0df..656b6ef 100644
--- a/chrome/browser/ui/autofill/BUILD.gn
+++ b/chrome/browser/ui/autofill/BUILD.gn
@@ -60,6 +60,7 @@
       "autofill_keyboard_accessory_controller_impl.h",
       "autofill_keyboard_accessory_view.h",
       "autofill_message_controller.h",
+      "autofill_message_controller_impl.h",
       "autofill_message_model.h",
       "autofill_snackbar_controller.h",
       "autofill_snackbar_controller_impl.h",
@@ -184,7 +185,7 @@
     sources += [
       "autofill_keyboard_accessory_controller.cc",
       "autofill_keyboard_accessory_controller_impl.cc",
-      "autofill_message_controller.cc",
+      "autofill_message_controller_impl.cc",
       "autofill_message_model.cc",
       "autofill_snackbar_controller_impl.cc",
     ]
@@ -316,7 +317,7 @@
   if (is_android) {
     sources += [
       "autofill_keyboard_accessory_controller_impl_unittest.cc",
-      "autofill_message_controller_unittest.cc",
+      "autofill_message_controller_impl_unittest.cc",
       "autofill_message_model_unittest.cc",
       "autofill_snackbar_controller_impl_unittest.cc",
     ]
@@ -355,12 +356,17 @@
     "test/test_autofill_bubble_handler.h",
   ]
 
-  public_deps = [ ":autofill" ]
+  public_deps = [
+    ":autofill",
+    "//testing/gmock",
+  ]
 
   if (is_android) {
     sources += [
       "autofill_keyboard_accessory_controller_impl_test_api.h",
       "autofill_message_controller_test_api.h",
+      "mock_autofill_message_controller.cc",
+      "mock_autofill_message_controller.h",
     ]
   } else {
     sources += [
@@ -370,10 +376,7 @@
       "mock_autofill_popup_controller.cc",
       "mock_autofill_popup_controller.h",
     ]
-    public_deps += [
-      "//testing/gmock",
-      "//ui/gfx:test_support",
-    ]
+    public_deps += [ "//ui/gfx:test_support" ]
   }
 }
 
diff --git a/chrome/browser/ui/autofill/autofill_message_controller.h b/chrome/browser/ui/autofill/autofill_message_controller.h
index df2a2ff..bede856d 100644
--- a/chrome/browser/ui/autofill/autofill_message_controller.h
+++ b/chrome/browser/ui/autofill/autofill_message_controller.h
@@ -1,4 +1,4 @@
-// Copyright 2024 The Chromium Authors
+// 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.
 
@@ -13,37 +13,13 @@
 
 namespace autofill {
 
-// AutofillMessageController is used to control the lifecycle of autofill
-// Messages on Android. This includes handling the show, dismiss and callbacks
-// of the messages.
 class AutofillMessageController {
  public:
-  explicit AutofillMessageController(content::WebContents* web_contents);
-  AutofillMessageController(const AutofillMessageController&) = delete;
-  AutofillMessageController& operator=(const AutofillMessageController&) =
-      delete;
-  virtual ~AutofillMessageController();
+  virtual ~AutofillMessageController() = default;
 
   // Show a new message. If an existing message is already showing, dismiss that
   // message and show the new one.
-  virtual void Show(std::unique_ptr<AutofillMessageModel> message_model);
-
- private:
-  friend class AutofillMessageControllerTestApi;
-
-  // Callback for when the action button on the message is clicked.
-  void OnActionClicked(AutofillMessageModel* message_model_ptr);
-
-  // Callback for when the message is dismissed.
-  void OnDismissed(AutofillMessageModel* message_model_ptr,
-                   messages::DismissReason reason);
-
-  void Dismiss();
-
-  const raw_ref<content::WebContents> web_contents_;
-  std::set<std::unique_ptr<AutofillMessageModel>, base::UniquePtrComparator>
-      message_models_;
-  base::WeakPtrFactory<AutofillMessageController> weak_ptr_factory_{this};
+  virtual void Show(std::unique_ptr<AutofillMessageModel> message_model) = 0;
 };
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/autofill/autofill_message_controller.cc b/chrome/browser/ui/autofill/autofill_message_controller_impl.cc
similarity index 83%
rename from chrome/browser/ui/autofill/autofill_message_controller.cc
rename to chrome/browser/ui/autofill/autofill_message_controller_impl.cc
index a8bd196..c62b289 100644
--- a/chrome/browser/ui/autofill/autofill_message_controller.cc
+++ b/chrome/browser/ui/autofill/autofill_message_controller_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/autofill/autofill_message_controller.h"
+#include "chrome/browser/ui/autofill/autofill_message_controller_impl.h"
 
 #include <memory>
 
@@ -14,26 +14,26 @@
 
 namespace autofill {
 
-AutofillMessageController::AutofillMessageController(
+AutofillMessageControllerImpl::AutofillMessageControllerImpl(
     content::WebContents* web_contents)
     : web_contents_(*web_contents) {}
 
-AutofillMessageController::~AutofillMessageController() {
+AutofillMessageControllerImpl::~AutofillMessageControllerImpl() {
   Dismiss();
 }
 
-void AutofillMessageController::Show(
+void AutofillMessageControllerImpl::Show(
     std::unique_ptr<AutofillMessageModel> message_model) {
   AutofillMessageModel* message_model_ptr = message_model.get();
   message_models_.insert(std::move(message_model));
 
   message_model_ptr->GetMessage(/*pass_key=*/{})
       .SetActionClick(
-          base::BindOnce(&AutofillMessageController::OnActionClicked,
+          base::BindOnce(&AutofillMessageControllerImpl::OnActionClicked,
                          weak_ptr_factory_.GetWeakPtr(), message_model_ptr));
   message_model_ptr->GetMessage(/*pass_key=*/{})
       .SetDismissCallback(
-          base::BindOnce(&AutofillMessageController::OnDismissed,
+          base::BindOnce(&AutofillMessageControllerImpl::OnDismissed,
                          weak_ptr_factory_.GetWeakPtr(), message_model_ptr));
 
   messages::MessageDispatcherBridge::Get()->EnqueueMessage(
@@ -47,7 +47,7 @@
       true);
 }
 
-void AutofillMessageController::OnActionClicked(
+void AutofillMessageControllerImpl::OnActionClicked(
     AutofillMessageModel* message_model_ptr) {
   auto message_model_it = message_models_.find(message_model_ptr);
   CHECK(message_model_it != message_models_.end());
@@ -58,7 +58,7 @@
       true);
 }
 
-void AutofillMessageController::OnDismissed(
+void AutofillMessageControllerImpl::OnDismissed(
     AutofillMessageModel* message_model_ptr,
     messages::DismissReason reason) {
   auto message_model_it = message_models_.find(message_model_ptr);
@@ -72,7 +72,7 @@
   message_models_.erase(message_model_it);
 }
 
-void AutofillMessageController::Dismiss() {
+void AutofillMessageControllerImpl::Dismiss() {
   for (auto it = message_models_.begin(); it != message_models_.end();) {
     messages::MessageDispatcherBridge::Get()->DismissMessage(
         &(*it++)->GetMessage(/*pass_key=*/{}),
diff --git a/chrome/browser/ui/autofill/autofill_message_controller_impl.h b/chrome/browser/ui/autofill/autofill_message_controller_impl.h
new file mode 100644
index 0000000..5a8039cb9
--- /dev/null
+++ b/chrome/browser/ui/autofill/autofill_message_controller_impl.h
@@ -0,0 +1,51 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_MESSAGE_CONTROLLER_IMPL_H_
+#define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_MESSAGE_CONTROLLER_IMPL_H_
+
+#include <memory>
+
+#include "base/containers/unique_ptr_adapters.h"
+#include "chrome/browser/ui/autofill/autofill_message_controller.h"
+#include "chrome/browser/ui/autofill/autofill_message_model.h"
+#include "content/public/browser/web_contents.h"
+
+namespace autofill {
+
+// AutofillMessageControllerImpl is used to control the lifecycle of autofill
+// Messages on Android. This includes handling the show, dismiss and callbacks
+// of the messages.
+class AutofillMessageControllerImpl : public AutofillMessageController {
+ public:
+  explicit AutofillMessageControllerImpl(content::WebContents* web_contents);
+  AutofillMessageControllerImpl(const AutofillMessageControllerImpl&) = delete;
+  AutofillMessageControllerImpl& operator=(
+      const AutofillMessageControllerImpl&) = delete;
+  ~AutofillMessageControllerImpl() override;
+
+  // AutofillMessageController:
+  void Show(std::unique_ptr<AutofillMessageModel> message_model) override;
+
+ private:
+  friend class AutofillMessageControllerTestApi;
+
+  // Callback for when the action button on the message is clicked.
+  void OnActionClicked(AutofillMessageModel* message_model_ptr);
+
+  // Callback for when the message is dismissed.
+  void OnDismissed(AutofillMessageModel* message_model_ptr,
+                   messages::DismissReason reason);
+
+  void Dismiss();
+
+  const raw_ref<content::WebContents> web_contents_;
+  std::set<std::unique_ptr<AutofillMessageModel>, base::UniquePtrComparator>
+      message_models_;
+  base::WeakPtrFactory<AutofillMessageControllerImpl> weak_ptr_factory_{this};
+};
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_MESSAGE_CONTROLLER_IMPL_H_
diff --git a/chrome/browser/ui/autofill/autofill_message_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_message_controller_impl_unittest.cc
similarity index 84%
rename from chrome/browser/ui/autofill/autofill_message_controller_unittest.cc
rename to chrome/browser/ui/autofill/autofill_message_controller_impl_unittest.cc
index c60fb2b..860bf7e 100644
--- a/chrome/browser/ui/autofill/autofill_message_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_message_controller_impl_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/autofill/autofill_message_controller.h"
+#include "chrome/browser/ui/autofill/autofill_message_controller_impl.h"
 
 #include <memory>
 
@@ -14,9 +14,10 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace autofill {
-class AutofillMessageControllerTest : public ChromeRenderViewHostTestHarness {
+class AutofillMessageControllerImplTest
+    : public ChromeRenderViewHostTestHarness {
  public:
-  AutofillMessageControllerTest() = default;
+  AutofillMessageControllerImplTest() = default;
 
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
@@ -59,9 +60,9 @@
     return (*it).get();
   }
 
-  AutofillMessageController& controller() {
+  AutofillMessageControllerImpl& controller() {
     if (!controller_) {
-      controller_ = new AutofillMessageController(web_contents());
+      controller_ = new AutofillMessageControllerImpl(web_contents());
     }
     return *controller_;
   }
@@ -71,11 +72,11 @@
   }
 
  private:
-  raw_ptr<AutofillMessageController> controller_;
+  raw_ptr<AutofillMessageControllerImpl> controller_;
   messages::MockMessageDispatcherBridge message_dispatcher_bridge_;
 };
 
-TEST_F(AutofillMessageControllerTest, Show) {
+TEST_F(AutofillMessageControllerImplTest, Show) {
   ExpectEnqueueMessageCall();
 
   raw_ptr<AutofillMessageModel> message = CreateAndShowNewMessage();
@@ -83,7 +84,7 @@
   EXPECT_EQ(FindMessageModel(message), message);
 }
 
-TEST_F(AutofillMessageControllerTest, ShowTwiceWithoutDismiss) {
+TEST_F(AutofillMessageControllerImplTest, ShowTwiceWithoutDismiss) {
   ExpectEnqueueMessageCall(/*times=*/2);
 
   CreateAndShowNewMessage();
@@ -92,7 +93,7 @@
   EXPECT_THAT(message_models(), testing::SizeIs(2));
 }
 
-TEST_F(AutofillMessageControllerTest, OnDismissed) {
+TEST_F(AutofillMessageControllerImplTest, OnDismissed) {
   raw_ptr<AutofillMessageModel> first_message = CreateAndShowNewMessage();
   raw_ptr<AutofillMessageModel> second_message = CreateAndShowNewMessage();
 
@@ -103,7 +104,7 @@
   EXPECT_EQ(FindMessageModel(second_message), second_message);
 }
 
-TEST_F(AutofillMessageControllerTest, Dismiss) {
+TEST_F(AutofillMessageControllerImplTest, Dismiss) {
   CreateAndShowNewMessage();
   CreateAndShowNewMessage();
 
@@ -113,14 +114,14 @@
   test_api(controller()).Dismiss();
 }
 
-TEST_F(AutofillMessageControllerTest, DismissWithoutMessages) {
+TEST_F(AutofillMessageControllerImplTest, DismissWithoutMessages) {
   ExpectDismissMessageCallWithReason(messages::DismissReason::UNKNOWN,
                                      /*times=*/0);
 
   test_api(controller()).Dismiss();
 }
 
-TEST_F(AutofillMessageControllerTest, Metrics_Show) {
+TEST_F(AutofillMessageControllerImplTest, Metrics_Show) {
   base::HistogramTester histogram_tester;
   raw_ptr<AutofillMessageModel> message = CreateAndShowNewMessage();
 
@@ -129,7 +130,7 @@
       true, 1);
 }
 
-TEST_F(AutofillMessageControllerTest, Metrics_OnActionClicked) {
+TEST_F(AutofillMessageControllerImplTest, Metrics_OnActionClicked) {
   base::HistogramTester histogram_tester;
   raw_ptr<AutofillMessageModel> message = CreateAndShowNewMessage();
 
@@ -141,7 +142,7 @@
       true, 1);
 }
 
-TEST_F(AutofillMessageControllerTest, Metrics_OnDismissed) {
+TEST_F(AutofillMessageControllerImplTest, Metrics_OnDismissed) {
   base::HistogramTester histogram_tester;
   messages::DismissReason dismiss_reason =
       messages::DismissReason::PRIMARY_ACTION;
diff --git a/chrome/browser/ui/autofill/autofill_message_controller_test_api.h b/chrome/browser/ui/autofill/autofill_message_controller_test_api.h
index d1e1d53..8cd57a2c 100644
--- a/chrome/browser/ui/autofill/autofill_message_controller_test_api.h
+++ b/chrome/browser/ui/autofill/autofill_message_controller_test_api.h
@@ -5,14 +5,14 @@
 #ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_MESSAGE_CONTROLLER_TEST_API_H_
 #define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_MESSAGE_CONTROLLER_TEST_API_H_
 
-#include "chrome/browser/ui/autofill/autofill_message_controller.h"
+#include "chrome/browser/ui/autofill/autofill_message_controller_impl.h"
 
 namespace autofill {
 
 class AutofillMessageControllerTestApi {
  public:
   explicit AutofillMessageControllerTestApi(
-      AutofillMessageController& controller)
+      AutofillMessageControllerImpl& controller)
       : controller_(controller) {}
 
   ~AutofillMessageControllerTestApi() = default;
@@ -40,11 +40,11 @@
   void Dismiss() { controller_->Dismiss(); }
 
  private:
-  const raw_ref<AutofillMessageController> controller_;
+  const raw_ref<AutofillMessageControllerImpl> controller_;
 };
 
 inline AutofillMessageControllerTestApi test_api(
-    AutofillMessageController& controller) {
+    AutofillMessageControllerImpl& controller) {
   return AutofillMessageControllerTestApi(controller);
 }
 
diff --git a/chrome/browser/ui/autofill/autofill_message_model.cc b/chrome/browser/ui/autofill/autofill_message_model.cc
index 6db43de..4a2a579 100644
--- a/chrome/browser/ui/autofill/autofill_message_model.cc
+++ b/chrome/browser/ui/autofill/autofill_message_model.cc
@@ -65,7 +65,7 @@
 }
 
 messages::MessageWrapper& AutofillMessageModel::GetMessage(
-    base::PassKey<AutofillMessageController> pass_key) {
+    base::PassKey<AutofillMessageControllerImpl> pass_key) {
   return *message_;
 }
 
diff --git a/chrome/browser/ui/autofill/autofill_message_model.h b/chrome/browser/ui/autofill/autofill_message_model.h
index f3650ab..e6c6f54 100644
--- a/chrome/browser/ui/autofill/autofill_message_model.h
+++ b/chrome/browser/ui/autofill/autofill_message_model.h
@@ -13,7 +13,7 @@
 
 namespace autofill {
 
-class AutofillMessageController;
+class AutofillMessageControllerImpl;
 
 // AutofillMessageModel is used to create autofill Android Messages to be used
 // with the AutofillMessageController.
@@ -43,7 +43,7 @@
   CreateForVirtualCardEnrollFailure(std::u16string card_label);
 
   messages::MessageWrapper& GetMessage(
-      base::PassKey<AutofillMessageController> pass_key);
+      base::PassKey<AutofillMessageControllerImpl> pass_key);
   const Type& GetType() const;
   std::string_view GetTypeAsString() const;
 
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index da348ef..74748ee 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -166,7 +166,7 @@
 #include "chrome/browser/signin/android/signin_bridge.h"
 #include "chrome/browser/ui/android/autofill/autofill_accessibility_utils.h"
 #include "chrome/browser/ui/android/autofill/save_update_address_profile_flow_manager.h"
-#include "chrome/browser/ui/autofill/autofill_message_controller.h"
+#include "chrome/browser/ui/autofill/autofill_message_controller_impl.h"
 #include "chrome/browser/ui/autofill/autofill_snackbar_type.h"
 #include "chrome/browser/ui/autofill/payments/offer_notification_controller_android.h"
 #include "components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h"
@@ -1161,7 +1161,7 @@
 ChromeAutofillClient::GetAutofillMessageController() {
   if (!autofill_message_controller_) {
     autofill_message_controller_ =
-        std::make_unique<AutofillMessageController>(web_contents());
+        std::make_unique<AutofillMessageControllerImpl>(web_contents());
   }
 
   return autofill_message_controller_.get();
diff --git a/chrome/browser/ui/autofill/mock_autofill_message_controller.cc b/chrome/browser/ui/autofill/mock_autofill_message_controller.cc
new file mode 100644
index 0000000..2fcf1457
--- /dev/null
+++ b/chrome/browser/ui/autofill/mock_autofill_message_controller.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 "chrome/browser/ui/autofill/mock_autofill_message_controller.h"
+
+namespace autofill {
+
+MockAutofillMessageController::MockAutofillMessageController() = default;
+
+MockAutofillMessageController::~MockAutofillMessageController() = default;
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/autofill/mock_autofill_message_controller.h b/chrome/browser/ui/autofill/mock_autofill_message_controller.h
new file mode 100644
index 0000000..faaeeec
--- /dev/null
+++ b/chrome/browser/ui/autofill/mock_autofill_message_controller.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 CHROME_BROWSER_UI_AUTOFILL_MOCK_AUTOFILL_MESSAGE_CONTROLLER_H_
+#define CHROME_BROWSER_UI_AUTOFILL_MOCK_AUTOFILL_MESSAGE_CONTROLLER_H_
+
+#include <memory>
+
+#include "chrome/browser/ui/autofill/autofill_message_controller.h"
+#include "chrome/browser/ui/autofill/autofill_message_model.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill {
+
+class MockAutofillMessageController : public AutofillMessageController {
+ public:
+  MockAutofillMessageController();
+  ~MockAutofillMessageController() override;
+
+  MOCK_METHOD(void, Show, (std::unique_ptr<AutofillMessageModel>), (override));
+};
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_AUTOFILL_MOCK_AUTOFILL_MESSAGE_CONTROLLER_H_
diff --git a/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.cc b/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.cc
index 6f7faa9d..c3946b03 100644
--- a/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.cc
+++ b/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.cc
@@ -92,7 +92,7 @@
 #include "chrome/browser/ui/android/autofill/card_expiration_date_fix_flow_view_android.h"
 #include "chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.h"
 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
-#include "chrome/browser/ui/autofill/autofill_message_controller.h"
+#include "chrome/browser/ui/autofill/autofill_message_controller_impl.h"
 #include "chrome/browser/ui/autofill/autofill_message_model.h"
 #include "chrome/browser/ui/autofill/autofill_snackbar_controller_impl.h"
 #include "chrome/browser/ui/autofill/payments/android_bnpl_ui_delegate.h"
@@ -1225,7 +1225,7 @@
 ChromePaymentsAutofillClient::GetAutofillMessageController() {
   if (!autofill_message_controller_) {
     autofill_message_controller_ =
-        std::make_unique<AutofillMessageController>(web_contents());
+        std::make_unique<AutofillMessageControllerImpl>(web_contents());
   }
 
   return *autofill_message_controller_;
diff --git a/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client_unittest.cc b/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client_unittest.cc
index 2284f86..0c06957b 100644
--- a/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client_unittest.cc
+++ b/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client_unittest.cc
@@ -39,6 +39,7 @@
 #include "chrome/browser/ui/android/tab_model/tab_model_test_helper.h"
 #include "chrome/browser/ui/autofill/autofill_message_controller.h"
 #include "chrome/browser/ui/autofill/autofill_snackbar_controller_impl.h"
+#include "chrome/browser/ui/autofill/mock_autofill_message_controller.h"
 #include "components/autofill/core/browser/data_model/payments/bnpl_issuer.h"
 #include "components/autofill/core/browser/payments/android_bnpl_strategy.h"
 #include "components/autofill/core/browser/payments/autofill_save_card_ui_info.h"
@@ -128,14 +129,6 @@
                base::OnceClosure),
               (override));
 };
-
-class MockAutofillMessageController : public AutofillMessageController {
- public:
-  explicit MockAutofillMessageController(content::WebContents* web_contents)
-      : AutofillMessageController(web_contents) {}
-
-  MOCK_METHOD(void, Show, (std::unique_ptr<AutofillMessageModel>), (override));
-};
 #else  //! BUILDFLAG(IS_ANDROID)
 class MockSaveCardBubbleController : public SaveCardBubbleControllerImpl {
  public:
@@ -255,7 +248,7 @@
 
   MockAutofillMessageController* InjectMockAutofillMessageController() {
     std::unique_ptr<MockAutofillMessageController> mock =
-        std::make_unique<MockAutofillMessageController>(web_contents());
+        std::make_unique<MockAutofillMessageController>();
     MockAutofillMessageController* pointer = mock.get();
     chrome_payments_client()->SetAutofillMessageControllerForTesting(
         std::move(mock));
diff --git a/chrome/browser/ui/views/dark_mode_manager_linux.cc b/chrome/browser/ui/views/dark_mode_manager_linux.cc
index a856c6a..01e5f00 100644
--- a/chrome/browser/ui/views/dark_mode_manager_linux.cc
+++ b/chrome/browser/ui/views/dark_mode_manager_linux.cc
@@ -74,8 +74,8 @@
   SetColorScheme(observed_theme->preferred_color_scheme(), true);
 }
 
-void DarkModeManagerLinux::OnPortalRequestResult(bool success) {
-  if (!success) {
+void DarkModeManagerLinux::OnPortalRequestResult(uint32_t version) {
+  if (version == 0) {
     return;
   }
   // Subscribe to changes in the color scheme preference.
diff --git a/chrome/browser/ui/views/dark_mode_manager_linux.h b/chrome/browser/ui/views/dark_mode_manager_linux.h
index e4ad855..2bce8d68 100644
--- a/chrome/browser/ui/views/dark_mode_manager_linux.h
+++ b/chrome/browser/ui/views/dark_mode_manager_linux.h
@@ -81,7 +81,7 @@
   void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;
 
   // D-Bus async handlers
-  void OnPortalRequestResult(bool success);
+  void OnPortalRequestResult(uint32_t version);
   void OnSignalConnected(const std::string& interface_name,
                          const std::string& signal_name,
                          bool connected);
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
index 319ec7d6..f8dfb7d 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
@@ -1388,15 +1388,8 @@
     // there are no other buttons at the end.
     ProfileMenuViewBase::ActionableItem::kAutofillSettingsButton};
 
-// TODO(crbug.com/341975308): re-enable test.
-#if BUILDFLAG(IS_WIN)
-#define MAYBE_ProfileMenuClickTest_SyncEnabled \
-  DISABLED_ProfileMenuClickTest_SyncEnabled
-#else
-#define MAYBE_ProfileMenuClickTest_SyncEnabled ProfileMenuClickTest_SyncEnabled
-#endif
 PROFILE_MENU_CLICK_TEST(kActionableItems_SyncEnabled,
-                        MAYBE_ProfileMenuClickTest_SyncEnabled) {
+                        ProfileMenuClickTest_SyncEnabled) {
   EnableSync();
   RunTest();
 }
@@ -1450,15 +1443,8 @@
     // there are no other buttons at the end.
     ProfileMenuViewBase::ActionableItem::kSyncErrorButton};
 
-// TODO(crbug.com/40822972): flaky on Windows and Mac
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
-#define MAYBE_ProfileMenuClickTest_SyncPaused \
-  DISABLED_ProfileMenuClickTest_SyncPaused
-#else
-#define MAYBE_ProfileMenuClickTest_SyncPaused ProfileMenuClickTest_SyncPaused
-#endif
 PROFILE_MENU_CLICK_TEST(kActionableItems_SyncPaused,
-                        MAYBE_ProfileMenuClickTest_SyncPaused) {
+                        ProfileMenuClickTest_SyncPaused) {
   EnableSync();
   sync_harness()->EnterSyncPausedStateForPrimaryAccount();
   // Check that the setup was successful.
@@ -2058,17 +2044,9 @@
         // there are no other buttons at the end.
         ProfileMenuViewBase::ActionableItem::kSigninReauthButton};
 
-// TODO(crbug.com/40822972): flaky on Windows and Mac
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
-#define MAYBE_ProfileMenuClickTest_WithPendingAccount_ReplaceSyncPromosEnabled \
-  DISABLED_ProfileMenuClickTest_WithPendingAccount_ReplaceSyncPromosEnabled
-#else
-#define MAYBE_ProfileMenuClickTest_WithPendingAccount_ReplaceSyncPromosEnabled \
-  ProfileMenuClickTest_WithPendingAccount_ReplaceSyncPromosEnabled
-#endif
 PROFILE_MENU_CLICK_WITH_FEATURE_TEST(
     kActionableItems_WithPendingAccount_ReplaceSyncPromosEnabled,
-    MAYBE_ProfileMenuClickTest_WithPendingAccount_ReplaceSyncPromosEnabled,
+    ProfileMenuClickTest_WithPendingAccount_ReplaceSyncPromosEnabled,
     {syncer::kReplaceSyncPromosWithSignInPromos},
     {}) {
   AccountInfo account_info = signin::MakePrimaryAccountAvailable(
@@ -2107,17 +2085,9 @@
         // there are no other buttons at the end.
         ProfileMenuViewBase::ActionableItem::kSigninReauthButton};
 
-// TODO(crbug.com/40822972): flaky on Windows and Mac
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
-#define MAYBE_ProfileMenuClickTest_WithPendingAccount_ReplaceSyncPromosDisabled \
-  DISABLED_ProfileMenuClickTest_WithPendingAccount_ReplaceSyncPromosDisabled
-#else
-#define MAYBE_ProfileMenuClickTest_WithPendingAccount_ReplaceSyncPromosDisabled \
-  ProfileMenuClickTest_WithPendingAccount_ReplaceSyncPromosDisabled
-#endif
 PROFILE_MENU_CLICK_WITH_FEATURE_TEST(
     kActionableItems_WithPendingAccount_ReplaceSyncPromosDisabled,
-    MAYBE_ProfileMenuClickTest_WithPendingAccount_ReplaceSyncPromosDisabled,
+    ProfileMenuClickTest_WithPendingAccount_ReplaceSyncPromosDisabled,
     {},
     {syncer::kReplaceSyncPromosWithSignInPromos}) {
   AccountInfo account_info = signin::MakePrimaryAccountAvailable(
diff --git a/chrome/browser/ui/webui/regional_capabilities_internals/BUILD.gn b/chrome/browser/ui/webui/regional_capabilities_internals/BUILD.gn
index 3b53560..0bd3047 100644
--- a/chrome/browser/ui/webui/regional_capabilities_internals/BUILD.gn
+++ b/chrome/browser/ui/webui/regional_capabilities_internals/BUILD.gn
@@ -15,10 +15,12 @@
     "//chrome/browser:browser_process",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/regional_capabilities",
+    "//chrome/browser/search_engines",
     "//chrome/common",
     "//components/regional_capabilities",
     "//components/regional_capabilities:country_access_reason",
     "//components/resources",
+    "//components/search_engines",
     "//components/strings",
     "//components/webui/chrome_urls",
     "//components/webui/regional_capabilities_internals:constants",
diff --git a/chrome/browser/ui/webui/regional_capabilities_internals/regional_capabilities_internals_ui.cc b/chrome/browser/ui/webui/regional_capabilities_internals/regional_capabilities_internals_ui.cc
index 5ceac52..4fef089 100644
--- a/chrome/browser/ui/webui/regional_capabilities_internals/regional_capabilities_internals_ui.cc
+++ b/chrome/browser/ui/webui/regional_capabilities_internals/regional_capabilities_internals_ui.cc
@@ -7,11 +7,13 @@
 #include "base/check_deref.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/regional_capabilities/regional_capabilities_service_factory.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "components/grit/regional_capabilities_internals_resources.h"
 #include "components/grit/regional_capabilities_internals_resources_map.h"
 #include "components/regional_capabilities/access/country_access_reason.h"
 #include "components/regional_capabilities/regional_capabilities_internals_data_holder.h"
 #include "components/regional_capabilities/regional_capabilities_service.h"
+#include "components/search_engines/template_url_service.h"
 #include "components/webui/regional_capabilities_internals/constants.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/web_ui_data_source.h"
@@ -21,6 +23,24 @@
 using regional_capabilities::CountryAccessReason;
 using regional_capabilities::RegionalCapabilitiesServiceFactory;
 
+namespace {
+
+#if BUILDFLAG(IS_ANDROID)
+std::u16string GetExternalChoiceTemplateURL(Profile* profile) {
+  TemplateURLService* template_url_service =
+      TemplateURLServiceFactory::GetForProfile(profile);
+  for (const auto& template_url : template_url_service->GetTemplateURLs()) {
+    if (template_url->CreatedByRegulatoryProgram()) {
+      return template_url->keyword();
+    }
+  }
+
+  return u"NONE FOUND";
+}
+#endif
+
+}  // namespace
+
 RegionalCapabilitiesInternalsUI::RegionalCapabilitiesInternalsUI(
     content::WebUI* web_ui,
     const GURL& url)
@@ -40,6 +60,11 @@
     source->AddString(key, value);
   }
 
+#if BUILDFLAG(IS_ANDROID)
+  source->AddString(regional_capabilities::kExternalChoiceKeywordKey,
+                    GetExternalChoiceTemplateURL(profile));
+#endif
+
   webui::SetupWebUIDataSource(source, kRegionalCapabilitiesInternalsResources,
                               IDR_REGIONAL_CAPABILITIES_INTERNALS_INDEX_HTML);
 }
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index 8563be9e..95819f16 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1765173445-a0222e33c7298f767f55369284e5e04b428688c5-89e15c703a7f2034682e32241e39909027a35428.profdata
+chrome-android32-main-1765195063-effc20fbf9573c35953bd0d7f3be1d6def6c8298-3457ecae229e55e3260f1b3210acda332e80a8a5.profdata
diff --git a/chrome/build/android-desktop-x64.pgo.txt b/chrome/build/android-desktop-x64.pgo.txt
index 7890510..6e9e84ec 100644
--- a/chrome/build/android-desktop-x64.pgo.txt
+++ b/chrome/build/android-desktop-x64.pgo.txt
@@ -1 +1 @@
-chrome-android-desktop-x64-main-1765173445-021950a5f71b0cd10121f3d81a3c6276f681a9e1-89e15c703a7f2034682e32241e39909027a35428.profdata
+chrome-android-desktop-x64-main-1765195063-53599a94dbea7afc2c13e2fedcb1cd828817b170-3457ecae229e55e3260f1b3210acda332e80a8a5.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index f8bcdac1..e7f9c818 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1765150054-09565681b11d74d91a37eb511de9f3cfea4bedff-e8dc846fb8405aa740d4b659d6f0669b4f1a8591.profdata
+chrome-linux-main-1765195063-118e42d1bc3a8585be34ab95feeb2e6c718bf6e4-3457ecae229e55e3260f1b3210acda332e80a8a5.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index b24eb64..1d98ea3 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1765173445-62c05740b4e7f8f11dd6abbc555589a875ec56b8-89e15c703a7f2034682e32241e39909027a35428.profdata
+chrome-mac-arm-main-1765195063-f0f6d87e7b28478a29d42365c049b9c02618800b-3457ecae229e55e3260f1b3210acda332e80a8a5.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index acefc0e..4543180 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1765150054-923a2d510c8e0e0a35d76ab416d2e583e3e1adbb-e8dc846fb8405aa740d4b659d6f0669b4f1a8591.profdata
+chrome-mac-main-1765173445-1158ecae655b1a894fcf24a8866bba524ec947e2-89e15c703a7f2034682e32241e39909027a35428.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index 5f259b2..d683e53 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1765150054-79a1069f4808b840eb285e20b93873c48febd403-e8dc846fb8405aa740d4b659d6f0669b4f1a8591.profdata
+chrome-win-arm64-main-1765173445-bb072361def816ef35c60a2973216e501f3a7c00-89e15c703a7f2034682e32241e39909027a35428.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index f250e98..4bd4686 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1765150054-bd74b354d46c549e388d86b5bfa754446faaa8d9-e8dc846fb8405aa740d4b659d6f0669b4f1a8591.profdata
+chrome-win32-main-1765173445-fd311b18a0cff0a21f3e5c3a6e91d70bf9630bb5-89e15c703a7f2034682e32241e39909027a35428.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 2963c415..4c236ed 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1765105739-d2f83079a34ed5ed2d4e406f6e5f174386e2f549-b5f7f1049c1c66374a70dc4e9110c063c9c66aea.profdata
+chrome-win64-main-1765150054-55825df52e5b6d839071978c22c001ae188eb7e4-e8dc846fb8405aa740d4b659d6f0669b4f1a8591.profdata
diff --git a/chrome/renderer/accessibility/read_anything/read_anything_app_controller.cc b/chrome/renderer/accessibility/read_anything/read_anything_app_controller.cc
index 98a2815fc..9b8ea3e 100644
--- a/chrome/renderer/accessibility/read_anything/read_anything_app_controller.cc
+++ b/chrome/renderer/accessibility/read_anything/read_anything_app_controller.cc
@@ -2117,6 +2117,7 @@
   if (read_aloud_model_.speech_playing() && tab_active) {
     read_aloud_model_.LogSpeechStop(
         ReadAloudAppModel::ReadAloudStopSource::kCloseReadingMode);
+    ReadingModeWillClose();
   }
   RecordEstimatedWordsSeen();
   RecordEstimatedWordsHeard();
@@ -2127,11 +2128,20 @@
   if (read_aloud_model_.speech_playing()) {
     read_aloud_model_.LogSpeechStop(
         ReadAloudAppModel::ReadAloudStopSource::kCloseTabOrWindow);
+    ReadingModeWillClose();
   }
   RecordEstimatedWordsSeen();
   RecordEstimatedWordsHeard();
 }
 
+void ReadAnythingAppController::ReadingModeWillClose() {
+  if (!features::IsImmersiveReadAnythingEnabled()) {
+    return;
+  }
+
+  ExecuteJavaScript("chrome.readingMode.readingModeWillClose();");
+}
+
 void ReadAnythingAppController::OnTabMuteStateChange(bool muted) {
   ExecuteJavaScript("chrome.readingMode.onTabMuteStateChange(" +
                     base::ToString(muted) + ")");
diff --git a/chrome/renderer/accessibility/read_anything/read_anything_app_controller.h b/chrome/renderer/accessibility/read_anything/read_anything_app_controller.h
index 5750fe3..218dffb 100644
--- a/chrome/renderer/accessibility/read_anything/read_anything_app_controller.h
+++ b/chrome/renderer/accessibility/read_anything/read_anything_app_controller.h
@@ -386,6 +386,10 @@
   // processed accessibility events.
   void SendEventUpdates();
 
+  // Helper for forwarding reading mode hide events to the webui so we can
+  // perform cleaning operations on it.
+  void ReadingModeWillClose();
+
   // Records the number of selections that occurred for the active page. Called
   // when the active tree changes.
   void RecordNumSelections();
diff --git a/chrome/test/data/webui/side_panel/read_anything/speech_controller_test.ts b/chrome/test/data/webui/side_panel/read_anything/speech_controller_test.ts
index 040111c..4e24c27 100644
--- a/chrome/test/data/webui/side_panel/read_anything/speech_controller_test.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/speech_controller_test.ts
@@ -655,6 +655,26 @@
     assertEquals(0, speech.getCallCount('speak'));
   });
 
+  test('onReadingModeWillHide while playing cancels speech', () => {
+    onPlayPauseToggle('Sleepy jack the fire drill');
+    speech.reset();
+    assertTrue(speechController.isSpeechActive());
+
+    speechController.onReadingModeWillClose();
+
+    assertEquals(1, speech.getCallCount('cancel'));
+    assertEquals(0, speech.getCallCount('pause'));
+    assertEquals(0, speech.getCallCount('speak'));
+  });
+
+  test('onReadingModeWillHide while paused does nothing', () => {
+    speechController.onReadingModeWillClose();
+
+    assertEquals(0, speech.getCallCount('pause'));
+    assertEquals(0, speech.getCallCount('cancel'));
+    assertEquals(0, speech.getCallCount('speak'));
+  });
+
   test('onVoiceSelected sets current voice', () => {
     const voice1 = createSpeechSynthesisVoice({lang: 'pt-pt', name: 'Donkey'});
     const voice2 = createSpeechSynthesisVoice({lang: 'pt-br', name: 'Corgi'});
diff --git a/clank b/clank
index 78c4f12..fe18f15 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 78c4f1290f499ca246f0c7763f32c0c44a41a00d
+Subproject commit fe18f1532fab7fddfaac4b6fb1b53dd222e0a532
diff --git a/components/autofill/core/browser/filling/form_filler.cc b/components/autofill/core/browser/filling/form_filler.cc
index 916c5f0..63b928d7 100644
--- a/components/autofill/core/browser/filling/form_filler.cc
+++ b/components/autofill/core/browser/filling/form_filler.cc
@@ -277,8 +277,8 @@
   NOTREACHED();
 }
 
-// Called by `FormFiller::MaybeTriggerRefill()` and constructs a refill value in
-// case the website used JavaScript to reformat an expiration date like
+// Called by `FormFiller::MaybeTriggerAutomaticRefill()` and constructs a refill
+// value in case the website used JavaScript to reformat an expiration date like
 // "05/2023" into "05 / 20" (i.e. it broke the year by cutting the last two
 // digits instead of stripping the first two digits).
 std::optional<FormFiller::ValueAndType> GetRefillValueForExpirationDate(
@@ -1015,7 +1015,7 @@
       filling_payload, trigger_source, refill_trigger_reason);
 }
 
-void FormFiller::MaybeTriggerRefill(
+void FormFiller::MaybeTriggerAutomaticRefill(
     const FormData& form,
     const FormStructure& form_structure,
     RefillTriggerReason refill_trigger_reason,
diff --git a/components/autofill/core/browser/filling/form_filler.h b/components/autofill/core/browser/filling/form_filler.h
index 51a65918..6e8bd833 100644
--- a/components/autofill/core/browser/filling/form_filler.h
+++ b/components/autofill/core/browser/filling/form_filler.h
@@ -171,7 +171,7 @@
   // `RefillTriggerReason::kExpirationDateFormatted`, and in that case `field`
   // is the one that was reformatted and `old_value` is the value `field` had
   // before the reformatting.
-  void MaybeTriggerRefill(
+  void MaybeTriggerAutomaticRefill(
       const FormData& form,
       const FormStructure& form_structure,
       RefillTriggerReason refill_trigger_reason,
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager.cc b/components/autofill/core/browser/foundations/browser_autofill_manager.cc
index 404197c9..a8fdb99 100644
--- a/components/autofill/core/browser/foundations/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/foundations/browser_autofill_manager.cc
@@ -2351,10 +2351,10 @@
   if (!form_structure) {
     return;
   }
-  form_filler_->MaybeTriggerRefill(form, *form_structure,
-                                   RefillTriggerReason::kSelectOptionsChanged,
-                                   AutofillTriggerSource::kSelectOptionsChanged,
-                                   form_structure->GetFieldById(field_id));
+  form_filler_->MaybeTriggerAutomaticRefill(
+      form, *form_structure, RefillTriggerReason::kSelectOptionsChanged,
+      AutofillTriggerSource::kSelectOptionsChanged,
+      form_structure->GetFieldById(field_id));
 }
 
 void BrowserAutofillManager::OnJavaScriptChangedAutofilledValueImpl(
@@ -2405,7 +2405,7 @@
     return;
   }
   AnalyzeJavaScriptChangedAutofilledValue(*form_structure, *autofill_field);
-  form_filler_->MaybeTriggerRefill(
+  form_filler_->MaybeTriggerAutomaticRefill(
       form, *form_structure, RefillTriggerReason::kExpirationDateFormatted,
       AutofillTriggerSource::kJavaScriptChangedAutofilledValue, *autofill_field,
       old_value);
@@ -3034,9 +3034,9 @@
   // If a form with the same FormGlobalId was previously filled, the structure
   // of the form changed, and we might be able to refill the form with other
   // information.
-  form_filler_->MaybeTriggerRefill(form, form_structure,
-                                   RefillTriggerReason::kFormChanged,
-                                   AutofillTriggerSource::kFormsSeen);
+  form_filler_->MaybeTriggerAutomaticRefill(form, form_structure,
+                                            RefillTriggerReason::kFormChanged,
+                                            AutofillTriggerSource::kFormsSeen);
 }
 
 void BrowserAutofillManager::OnDidIdentifyFormForMetrics(
diff --git a/components/capture_mode/BUILD.gn b/components/capture_mode/BUILD.gn
index 07bbf64..7995351 100644
--- a/components/capture_mode/BUILD.gn
+++ b/components/capture_mode/BUILD.gn
@@ -20,6 +20,7 @@
     "//mojo/public/cpp/bindings",
     "//services/audio/public/cpp",
     "//services/video_capture/public/mojom",
+    "//ui/base:features",
     "//ui/compositor",
     "//ui/gfx",
   ]
diff --git a/components/capture_mode/DEPS b/components/capture_mode/DEPS
index b4f09b4..927dd96 100644
--- a/components/capture_mode/DEPS
+++ b/components/capture_mode/DEPS
@@ -5,11 +5,13 @@
   "+gpu/command_buffer/common/context_result.h",
   "+gpu/command_buffer/common/shared_image_capabilities.h",
   "+gpu/command_buffer/common/shared_image_usage.h",
+  "+gpu/config/gpu_feature_info.h",
   "+gpu/config/gpu_finch_features.h",
   "+media",
   "+mojo/public",
   "+services/audio/public/cpp/device_factory.h",
   "+services/video_capture/public",
+  "+ui/base/ui_base_features.h",
   "+ui/compositor/compositor.h",
   "+ui/gfx",
   "+ui/ozone/public",
diff --git a/components/capture_mode/camera_video_frame_handler.cc b/components/capture_mode/camera_video_frame_handler.cc
index 864a8bbc..bee03e5 100644
--- a/components/capture_mode/camera_video_frame_handler.cc
+++ b/components/capture_mode/camera_video_frame_handler.cc
@@ -19,12 +19,14 @@
 #include "gpu/command_buffer/client/shared_image_interface.h"
 #include "gpu/command_buffer/common/shared_image_capabilities.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
+#include "gpu/config/gpu_feature_info.h"
 #include "gpu/config/gpu_finch_features.h"
 #include "media/base/media_switches.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_types.h"
 #include "media/capture/video_capture_types.h"
 #include "mojo/public/cpp/system/buffer.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/compositor/compositor.h"
 #include "ui/gfx/buffer_types.h"
 #include "ui/gfx/geometry/size.h"
@@ -94,7 +96,11 @@
 bool IsGpuRasterizationSupported(ui::ContextFactory* context_factory) {
   DCHECK(context_factory);
   auto provider = context_factory->SharedMainThreadRasterContextProvider();
-  return provider && provider->ContextCapabilities().gpu_rasterization;
+  const auto& gpu_feature_info = provider->GetGpuFeatureInfo();
+  return features::IsUiGpuRasterizationEnabled() &&
+         gpu_feature_info
+                 .status_values[gpu::GPU_FEATURE_TYPE_GPU_TILE_RASTERIZATION] ==
+             gpu::kGpuFeatureStatusEnabled;
 }
 #endif
 
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index 64d1af9..5862548 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "77.6",
-  "log_list_timestamp": "2025-12-07T12:52:59Z",
+  "version": "77.7",
+  "log_list_timestamp": "2025-12-08T12:53:03Z",
   "operators": [
     {
       "name": "Google",
diff --git a/components/dbus/xdg/portal.cc b/components/dbus/xdg/portal.cc
index 76510e96..37e4414 100644
--- a/components/dbus/xdg/portal.cc
+++ b/components/dbus/xdg/portal.cc
@@ -41,7 +41,8 @@
     // otherwise add it to the callback list.
     if (state_ == PortalRegistrarState::kSuccess ||
         state_ == PortalRegistrarState::kFailed) {
-      std::move(callback).Run(state_ == PortalRegistrarState::kSuccess);
+      std::move(callback).Run(
+          state_ == PortalRegistrarState::kSuccess ? version_ : 0);
       return;
     }
     callbacks_.push_back(std::move(callback));
@@ -63,6 +64,7 @@
   void SetStateForTesting(PortalRegistrarState state) {
     state_ = state;
     bus_ = nullptr;
+    version_ = (state == PortalRegistrarState::kSuccess) ? 3 : 0;
     callbacks_.clear();
     weak_ptr_factory_.InvalidateWeakPtrs();
   }
@@ -87,7 +89,7 @@
     if (systemd_unit_status_ ==
             internal::SystemdUnitStatus::kUnitNotNecessary ||
         systemd_unit_status_ == internal::SystemdUnitStatus::kUnitStarted) {
-      SetStateAndRunCallbacks(PortalRegistrarState::kSuccess);
+      GetVersion();
       return;
     }
 
@@ -122,6 +124,34 @@
       LOG(WARNING) << "Failed to register with " << kRegistryInterface;
     }
 
+    GetVersion();
+  }
+
+  void GetVersion() {
+    dbus::ObjectProxy* proxy = bus_->GetObjectProxy(
+        kPortalServiceName, dbus::ObjectPath(kPortalObjectPath));
+
+    dbus::MethodCall method_call(DBUS_INTERFACE_PROPERTIES, "Get");
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendString(kFileChooserInterfaceName);
+    writer.AppendString("version");
+    proxy->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+                      base::BindOnce(&PortalRegistrar::OnGetVersionReply,
+                                     weak_ptr_factory_.GetWeakPtr()));
+  }
+
+  void OnGetVersionReply(dbus::Response* response) {
+    if (!response) {
+      SetStateAndRunCallbacks(PortalRegistrarState::kFailed);
+      return;
+    }
+
+    dbus::MessageReader reader(response);
+    if (!reader.PopVariantOfUint32(&version_)) {
+      SetStateAndRunCallbacks(PortalRegistrarState::kFailed);
+      return;
+    }
+
     SetStateAndRunCallbacks(PortalRegistrarState::kSuccess);
   }
 
@@ -135,17 +165,19 @@
 
   void SetStateAndRunCallbacks(PortalRegistrarState state) {
     state_ = state;
-    bool success = (state_ == PortalRegistrarState::kSuccess);
+    uint32_t version =
+        (state_ == PortalRegistrarState::kSuccess) ? version_ : 0;
     std::vector<PortalSetupCallback> callbacks;
     callbacks.swap(callbacks_);
     for (auto& callback : callbacks) {
-      std::move(callback).Run(success);
+      std::move(callback).Run(version);
     }
   }
 
   scoped_refptr<dbus::Bus> bus_;
   PortalRegistrarState state_ = PortalRegistrarState::kIdle;
   std::optional<internal::SystemdUnitStatus> systemd_unit_status_;
+  uint32_t version_ = 0;
   std::vector<PortalSetupCallback> callbacks_;
   base::WeakPtrFactory<PortalRegistrar> weak_ptr_factory_{this};
 };
diff --git a/components/dbus/xdg/portal.h b/components/dbus/xdg/portal.h
index 82fc24d..ca8bbbc 100644
--- a/components/dbus/xdg/portal.h
+++ b/components/dbus/xdg/portal.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_DBUS_XDG_PORTAL_H_
 #define COMPONENTS_DBUS_XDG_PORTAL_H_
 
+#include <cstdint>
+
 #include "base/component_export.h"
 #include "base/functional/callback_forward.h"
 
@@ -21,12 +23,13 @@
   kFailed,
 };
 
-using PortalSetupCallback = base::OnceCallback<void(bool success)>;
+using PortalSetupCallback = base::OnceCallback<void(uint32_t version)>;
 
 // Initializes the XDG desktop portal by setting the systemd scope unit name,
 // ensuring the portal service is started, and registering the application.
 // This function caches its results and may be called more than once.
-// `callback` is run with true iff the portal is available.
+// `callback` is run with the portal version if the portal is available, or 0
+// otherwise.
 COMPONENT_EXPORT(COMPONENTS_DBUS)
 void RequestXdgDesktopPortal(dbus::Bus* bus, PortalSetupCallback callback);
 
diff --git a/components/dbus/xdg/portal_constants.h b/components/dbus/xdg/portal_constants.h
index 510b8c8..3af1f2b 100644
--- a/components/dbus/xdg/portal_constants.h
+++ b/components/dbus/xdg/portal_constants.h
@@ -11,6 +11,8 @@
 inline constexpr char kPortalObjectPath[] = "/org/freedesktop/portal/desktop";
 inline constexpr char kRegistryInterface[] =
     "org.freedesktop.host.portal.Registry";
+inline constexpr char kFileChooserInterfaceName[] =
+    "org.freedesktop.portal.FileChooser";
 inline constexpr char kMethodRegister[] = "Register";
 
 }  // namespace dbus_xdg
diff --git a/components/dbus/xdg/portal_unittest.cc b/components/dbus/xdg/portal_unittest.cc
index fd9c75e..3f7e87b 100644
--- a/components/dbus/xdg/portal_unittest.cc
+++ b/components/dbus/xdg/portal_unittest.cc
@@ -101,18 +101,43 @@
   // Expect SetNameOwnerChangedCallback
   EXPECT_CALL(*mock_portal_proxy, SetNameOwnerChangedCallback(_));
 
-  bool success = false;
+  // Expect GetVersion call
+  EXPECT_CALL(*mock_portal_proxy, CallMethod(_, _, _))
+      .WillRepeatedly([](dbus::MethodCall* method_call, int timeout_ms,
+                         dbus::ObjectProxy::ResponseCallback callback) {
+        if (method_call->GetInterface() == DBUS_INTERFACE_PROPERTIES &&
+            method_call->GetMember() == "Get") {
+          dbus::MessageReader reader(method_call);
+          std::string interface_name;
+          std::string property_name;
+          reader.PopString(&interface_name);
+          reader.PopString(&property_name);
+
+          if (interface_name == kFileChooserInterfaceName &&
+              property_name == "version") {
+            auto response = dbus::Response::CreateEmpty();
+            dbus::MessageWriter writer(response.get());
+            writer.AppendVariantOfUint32(3);
+            std::move(callback).Run(response.get());
+            return;
+          }
+        }
+        std::move(callback).Run(nullptr);
+      });
+
+  uint32_t version = 0;
   base::RunLoop run_loop;
   RequestXdgDesktopPortal(
-      bus_.get(), base::BindOnce(
-                      [](bool* out, base::OnceClosure quit_closure, bool res) {
-                        *out = res;
-                        std::move(quit_closure).Run();
-                      },
-                      &success, run_loop.QuitClosure()));
+      bus_.get(),
+      base::BindOnce(
+          [](uint32_t* out, base::OnceClosure quit_closure, uint32_t res) {
+            *out = res;
+            std::move(quit_closure).Run();
+          },
+          &version, run_loop.QuitClosure()));
 
   run_loop.Run();
-  EXPECT_TRUE(success);
+  EXPECT_EQ(version, 3u);
 }
 
 TEST_F(RequestXdgDesktopPortalTest, RequestXdgDesktopPortalSuccessWithSystemd) {
@@ -199,24 +224,46 @@
                                     dbus::ObjectPath(kPortalObjectPath)))
       .WillRepeatedly(Return(mock_portal_proxy.get()));
 
-  // Expect NO Register call because systemd unit creation succeeded
-  EXPECT_CALL(*mock_portal_proxy, CallMethod(_, _, _)).Times(0);
-
   // Expect NO SetNameOwnerChangedCallback
   EXPECT_CALL(*mock_portal_proxy, SetNameOwnerChangedCallback(_)).Times(0);
 
-  bool success = false;
+  // Expect GetVersion call
+  EXPECT_CALL(*mock_portal_proxy, CallMethod(_, _, _))
+      .WillRepeatedly([](dbus::MethodCall* method_call, int timeout_ms,
+                         dbus::ObjectProxy::ResponseCallback callback) {
+        if (method_call->GetInterface() == DBUS_INTERFACE_PROPERTIES &&
+            method_call->GetMember() == "Get") {
+          dbus::MessageReader reader(method_call);
+          std::string interface_name;
+          std::string property_name;
+          reader.PopString(&interface_name);
+          reader.PopString(&property_name);
+
+          if (interface_name == kFileChooserInterfaceName &&
+              property_name == "version") {
+            auto response = dbus::Response::CreateEmpty();
+            dbus::MessageWriter writer(response.get());
+            writer.AppendVariantOfUint32(3);
+            std::move(callback).Run(response.get());
+            return;
+          }
+        }
+        std::move(callback).Run(nullptr);
+      });
+
+  uint32_t version = 0;
   base::RunLoop run_loop;
   RequestXdgDesktopPortal(
-      bus_.get(), base::BindOnce(
-                      [](bool* out, base::OnceClosure quit_closure, bool res) {
-                        *out = res;
-                        std::move(quit_closure).Run();
-                      },
-                      &success, run_loop.QuitClosure()));
+      bus_.get(),
+      base::BindOnce(
+          [](uint32_t* out, base::OnceClosure quit_closure, uint32_t res) {
+            *out = res;
+            std::move(quit_closure).Run();
+          },
+          &version, run_loop.QuitClosure()));
 
   run_loop.Run();
-  EXPECT_TRUE(success);
+  EXPECT_EQ(version, 3u);
 }
 
 }  // namespace
diff --git a/components/enterprise/BUILD.gn b/components/enterprise/BUILD.gn
index f668ed1..f3bb1faf 100644
--- a/components/enterprise/BUILD.gn
+++ b/components/enterprise/BUILD.gn
@@ -186,7 +186,6 @@
     "//components/enterprise/browser/identifiers:test_support",
     "//components/enterprise/connectors/core:constants",
     "//components/enterprise/device_attestation:test_support",
-    "//components/enterprise/signin:unit_tests",
     "//components/policy/core/common:test_support",
     "//components/prefs:test_support",
     "//components/version_info",
diff --git a/components/enterprise/obfuscation/core/utils.cc b/components/enterprise/obfuscation/core/utils.cc
index 232ceee..88390d0 100644
--- a/components/enterprise/obfuscation/core/utils.cc
+++ b/components/enterprise/obfuscation/core/utils.cc
@@ -67,6 +67,8 @@
 }  // namespace
 
 BASE_FEATURE(kEnterpriseFileObfuscation, base::FEATURE_ENABLED_BY_DEFAULT);
+BASE_FEATURE(kEnterpriseFileObfuscationArchiveAnalyzer,
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 bool IsFileObfuscationEnabled() {
   return base::FeatureList::IsEnabled(kEnterpriseFileObfuscation);
diff --git a/components/enterprise/obfuscation/core/utils.h b/components/enterprise/obfuscation/core/utils.h
index 4c8b6aa..224599731 100644
--- a/components/enterprise/obfuscation/core/utils.h
+++ b/components/enterprise/obfuscation/core/utils.h
@@ -49,6 +49,10 @@
 COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION)
 BASE_DECLARE_FEATURE(kEnterpriseFileObfuscation);
 
+// Feature to enable the archive analyzer for obfuscated files.
+COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION)
+BASE_DECLARE_FEATURE(kEnterpriseFileObfuscationArchiveAnalyzer);
+
 // Returns true if `kEnterpriseFileObfuscation` feature is enabled.
 COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION)
 bool IsFileObfuscationEnabled();
diff --git a/components/enterprise/signin/BUILD.gn b/components/enterprise/signin/BUILD.gn
deleted file mode 100644
index 6311b16d..0000000
--- a/components/enterprise/signin/BUILD.gn
+++ /dev/null
@@ -1,34 +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.
-
-import("//components/enterprise/buildflags/buildflags.gni")
-
-static_library("signin") {
-  sources = [ "enterprise_identity_service.cc" ]
-
-  public = [ "enterprise_identity_service.h" ]
-
-  deps = [
-    "//base",
-    "//components/signin/public/identity_manager",
-  ]
-
-  public_deps = [ "//components/keyed_service/core" ]
-}
-
-source_set("unit_tests") {
-  testonly = true
-
-  sources = [ "enterprise_identity_service_unittest.cc" ]
-
-  deps = [
-    ":signin",
-    "//base",
-    "//base/test:test_support",
-    "//components/signin/public/identity_manager",
-    "//components/signin/public/identity_manager:test_support",
-    "//testing/gmock",
-    "//testing/gtest",
-  ]
-}
diff --git a/components/enterprise/signin/DEPS b/components/enterprise/signin/DEPS
deleted file mode 100644
index 688775d..0000000
--- a/components/enterprise/signin/DEPS
+++ /dev/null
@@ -1,5 +0,0 @@
-include_rules = [
-  "+components/keyed_service/core",
-  "+components/signin/public/identity_manager",
-  "+google_apis/gaia",
-]
diff --git a/components/enterprise/signin/enterprise_identity_service.cc b/components/enterprise/signin/enterprise_identity_service.cc
deleted file mode 100644
index d9ece07..0000000
--- a/components/enterprise/signin/enterprise_identity_service.cc
+++ /dev/null
@@ -1,317 +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/enterprise/signin/enterprise_identity_service.h"
-
-#include "base/barrier_callback.h"
-#include "base/barrier_closure.h"
-#include "base/functional/bind.h"
-#include "base/functional/callback.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "base/time/time.h"
-#include "components/signin/public/base/oauth_consumer_id.h"
-#include "components/signin/public/identity_manager/access_token_info.h"
-#include "components/signin/public/identity_manager/account_info.h"
-#include "components/signin/public/identity_manager/account_managed_status_finder.h"
-#include "components/signin/public/identity_manager/identity_manager.h"
-#include "google_apis/gaia/google_service_auth_error.h"
-
-namespace enterprise {
-
-namespace {
-
-constexpr int kAccountTypeFetchTimeoutInMs = 20000;
-
-void HandleAccessTokenFetched(
-    base::OnceCallback<void(base::expected<signin::AccessTokenInfo,
-                                           GoogleServiceAuthError>)> callback,
-    GoogleServiceAuthError error,
-    signin::AccessTokenInfo token_info) {
-  if (error.state() == GoogleServiceAuthError::NONE) {
-    std::move(callback).Run(std::move(token_info));
-    return;
-  }
-
-  std::move(callback).Run(base::unexpected(std::move(error)));
-}
-
-}  // namespace
-
-using GetManagedAccountsCallback =
-    EnterpriseIdentityService::GetManagedAccountsCallback;
-
-class EnterpriseIdentityServiceImpl : public EnterpriseIdentityService,
-                                      public signin::IdentityManager::Observer {
- public:
-  explicit EnterpriseIdentityServiceImpl(
-      signin::IdentityManager* identity_manager);
-
-  ~EnterpriseIdentityServiceImpl() override;
-
-  // EnterpriseIdentityService:
-  void GetManagedAccountsWithRefreshTokens(
-      GetManagedAccountsCallback callback) override;
-  void GetManagedAccountsAccessTokens(
-      base::OnceCallback<void(std::vector<std::string>)> callback) override;
-  void AddObserver(EnterpriseIdentityService::Observer* observer) override;
-  void RemoveObserver(EnterpriseIdentityService::Observer* observer) override;
-
-  // signin::IdentityManager::Observer:
-  void OnRefreshTokensLoaded() override;
-  void OnRefreshTokenUpdatedForAccount(
-      const CoreAccountInfo& account_info) override;
-  void OnIdentityManagerShutdown(
-      signin::IdentityManager* identity_manager) override;
-
- private:
-  // Will invoke `callback` with the subset of `accounts` which end up being
-  // identified as managed.
-  void GetManagedAccounts(const std::vector<CoreAccountInfo>& accounts,
-                          GetManagedAccountsCallback callback);
-
-  void OnAccountTypesIdentified(
-      std::unique_ptr<std::vector<
-          std::unique_ptr<signin::AccountManagedStatusFinder>>> status_finders,
-      GetManagedAccountsCallback callback);
-
-  void OnManagedAccountsIdentified(
-      base::OnceCallback<void(std::vector<std::string>)> callback,
-      std::vector<CoreAccountInfo> managed_accounts);
-
-  void OnAccessTokensFetched(
-      std::unique_ptr<std::vector<std::unique_ptr<signin::AccessTokenFetcher>>>
-          token_fetchers,
-      base::OnceCallback<void(std::vector<std::string>)> callback,
-      std::vector<base::expected<signin::AccessTokenInfo,
-                                 GoogleServiceAuthError>> access_token_infos);
-
-  void OnRefreshTokenUpdatedForManagedAccounts(
-      std::vector<CoreAccountInfo> accounts);
-
-  bool refresh_tokens_loaded_{false};
-  std::vector<base::OnceClosure> pending_requests_;
-  const raw_ptr<signin::IdentityManager> identity_manager_;
-  base::ObserverList<EnterpriseIdentityService::Observer> observers_;
-
-  // Singular status finder used to verify if a single account is managed or
-  // not, for the purpose of notifying observers.
-  std::unique_ptr<signin::AccountManagedStatusFinder> status_finder_;
-
-  base::WeakPtrFactory<EnterpriseIdentityServiceImpl> weak_factory_{this};
-};
-
-// static
-std::unique_ptr<EnterpriseIdentityService> EnterpriseIdentityService::Create(
-    signin::IdentityManager* identity_manager) {
-  return std::make_unique<EnterpriseIdentityServiceImpl>(identity_manager);
-}
-
-EnterpriseIdentityServiceImpl::EnterpriseIdentityServiceImpl(
-    signin::IdentityManager* identity_manager)
-    : identity_manager_(identity_manager) {
-  CHECK(identity_manager_);
-
-  refresh_tokens_loaded_ = identity_manager_->AreRefreshTokensLoaded();
-  identity_manager_->AddObserver(this);
-}
-
-EnterpriseIdentityServiceImpl::~EnterpriseIdentityServiceImpl() {
-  identity_manager_->RemoveObserver(this);
-}
-
-void EnterpriseIdentityServiceImpl::GetManagedAccountsWithRefreshTokens(
-    GetManagedAccountsCallback callback) {
-  if (!refresh_tokens_loaded_) {
-    pending_requests_.push_back(base::BindOnce(
-        &EnterpriseIdentityServiceImpl::GetManagedAccountsWithRefreshTokens,
-        weak_factory_.GetWeakPtr(), std::move(callback)));
-    return;
-  }
-
-  GetManagedAccounts(identity_manager_->GetAccountsWithRefreshTokens(),
-                     std::move(callback));
-}
-
-void EnterpriseIdentityServiceImpl::GetManagedAccountsAccessTokens(
-    base::OnceCallback<void(std::vector<std::string>)> callback) {
-  GetManagedAccountsWithRefreshTokens(base::BindOnce(
-      &EnterpriseIdentityServiceImpl::OnManagedAccountsIdentified,
-      weak_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void EnterpriseIdentityServiceImpl::AddObserver(
-    EnterpriseIdentityService::Observer* observer) {
-  observers_.AddObserver(observer);
-}
-
-void EnterpriseIdentityServiceImpl::RemoveObserver(
-    EnterpriseIdentityService::Observer* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-void EnterpriseIdentityServiceImpl::OnRefreshTokensLoaded() {
-  if (refresh_tokens_loaded_) {
-    // No-op.
-    return;
-  }
-
-  refresh_tokens_loaded_ = true;
-
-  // Resume all pending requests.
-  for (auto& closure : pending_requests_) {
-    std::move(closure).Run();
-  }
-
-  pending_requests_.clear();
-}
-
-void EnterpriseIdentityServiceImpl::OnRefreshTokenUpdatedForAccount(
-    const CoreAccountInfo& account_info) {
-  if (!refresh_tokens_loaded_) {
-    return;
-  }
-
-  // Verify if `account_info` represents a managed account. If so, notify
-  // observers.
-  GetManagedAccounts(std::vector<CoreAccountInfo>{account_info},
-                     base::BindOnce(&EnterpriseIdentityServiceImpl::
-                                        OnRefreshTokenUpdatedForManagedAccounts,
-                                    weak_factory_.GetWeakPtr()));
-}
-
-void EnterpriseIdentityServiceImpl::OnIdentityManagerShutdown(
-    signin::IdentityManager* identity_manager) {
-  // Needs to be shutdown before IdentityManager.
-  NOTREACHED(base::NotFatalUntil::M142);
-}
-
-void EnterpriseIdentityServiceImpl::GetManagedAccounts(
-    const std::vector<CoreAccountInfo>& accounts,
-    GetManagedAccountsCallback callback) {
-  if (accounts.empty()) {
-    // No signed-in accounts.
-    std::move(callback).Run(std::vector<CoreAccountInfo>());
-    return;
-  }
-
-  // Using a unique pointer of a vector, as we'll need to fill-in the vector
-  // beyond transferring its ownership to the barrier closure.
-  auto status_finders = std::make_unique<
-      std::vector<std::unique_ptr<signin::AccountManagedStatusFinder>>>();
-  auto* status_finders_ptr = status_finders.get();
-  auto barrier_closure = base::BarrierClosure(
-      accounts.size(),
-      base::BindOnce(&EnterpriseIdentityServiceImpl::OnAccountTypesIdentified,
-                     weak_factory_.GetWeakPtr(), std::move(status_finders),
-                     std::move(callback)));
-  for (const auto& account : accounts) {
-    status_finders_ptr->push_back(
-        std::make_unique<signin::AccountManagedStatusFinder>(
-            identity_manager_, account, barrier_closure,
-            base::Milliseconds(kAccountTypeFetchTimeoutInMs)));
-
-    // If the account was resolved synchronously, `barrier_closure` needs to be
-    // invoked manually.
-    if (status_finders_ptr->back()->GetOutcome() !=
-        signin::AccountManagedStatusFinder::Outcome::kPending) {
-      barrier_closure.Run();
-    }
-  }
-}
-
-void EnterpriseIdentityServiceImpl::OnAccountTypesIdentified(
-    std::unique_ptr<std::vector<
-        std::unique_ptr<signin::AccountManagedStatusFinder>>> status_finders,
-    GetManagedAccountsCallback callback) {
-  std::vector<CoreAccountInfo> managed_accounts;
-  if (!status_finders) {
-    std::move(callback).Run(managed_accounts);
-    return;
-  }
-
-  for (const auto& status_finder : *status_finders) {
-    if (!status_finder) {
-      continue;
-    }
-
-    // Listing out all enum values to enforce all values are evaluated at
-    // compile-time.
-    switch (status_finder->GetOutcome()) {
-      case signin::AccountManagedStatusFinder::Outcome::kEnterpriseGoogleDotCom:
-      case signin::AccountManagedStatusFinder::Outcome::kEnterprise:
-        managed_accounts.push_back(status_finder->GetAccountInfo());
-        break;
-      case signin::AccountManagedStatusFinder::Outcome::kConsumerGmail:
-      case signin::AccountManagedStatusFinder::Outcome::kConsumerWellKnown:
-      case signin::AccountManagedStatusFinder::Outcome::kConsumerNotWellKnown:
-      case signin::AccountManagedStatusFinder::Outcome::kPending:
-      case signin::AccountManagedStatusFinder::Outcome::kError:
-      case signin::AccountManagedStatusFinder::Outcome::kTimeout:
-        continue;
-    }
-  }
-
-  std::move(callback).Run(managed_accounts);
-}
-
-void EnterpriseIdentityServiceImpl::OnManagedAccountsIdentified(
-    base::OnceCallback<void(std::vector<std::string>)> callback,
-    std::vector<CoreAccountInfo> managed_accounts) {
-  if (managed_accounts.empty()) {
-    std::move(callback).Run(std::vector<std::string>());
-    return;
-  }
-
-  // Have to bind the token fetchers to the barrier callback to ensure they
-  // remain alive while tokens are still being fetched.
-  auto token_fetchers = std::make_unique<
-      std::vector<std::unique_ptr<signin::AccessTokenFetcher>>>();
-  auto* token_fetchers_ptr = token_fetchers.get();
-  auto barrier_callback = base::BarrierCallback<
-      base::expected<signin::AccessTokenInfo, GoogleServiceAuthError>>(
-      managed_accounts.size(),
-      base::BindOnce(&EnterpriseIdentityServiceImpl::OnAccessTokensFetched,
-                     weak_factory_.GetWeakPtr(), std::move(token_fetchers),
-                     std::move(callback)));
-
-  for (const auto& account : managed_accounts) {
-    token_fetchers_ptr->push_back(
-        identity_manager_->CreateAccessTokenFetcherForAccount(
-            account.account_id,
-            signin::OAuthConsumerId::kEnterpriseIdentityService,
-            base::BindOnce(HandleAccessTokenFetched, barrier_callback),
-            signin::AccessTokenFetcher::Mode::kImmediate));
-  }
-}
-
-void EnterpriseIdentityServiceImpl::OnAccessTokensFetched(
-    std::unique_ptr<std::vector<std::unique_ptr<signin::AccessTokenFetcher>>>
-        token_fetchers,
-    base::OnceCallback<void(std::vector<std::string>)> callback,
-    std::vector<base::expected<signin::AccessTokenInfo, GoogleServiceAuthError>>
-        access_token_infos) {
-  std::vector<std::string> access_tokens;
-  for (const auto& access_token_info : access_token_infos) {
-    if (access_token_info.has_value()) {
-      access_tokens.push_back(access_token_info->token);
-    }
-  }
-  std::move(callback).Run(access_tokens);
-}
-
-void EnterpriseIdentityServiceImpl::OnRefreshTokenUpdatedForManagedAccounts(
-    std::vector<CoreAccountInfo> accounts) {
-  if (accounts.empty()) {
-    // Refresh tokens were updated for a consumer user, so no-op.
-    return;
-  }
-
-  // Notify observers.
-  observers_.Notify(
-      &EnterpriseIdentityService::Observer::OnManagedAccountSessionChanged);
-}
-
-}  // namespace enterprise
diff --git a/components/enterprise/signin/enterprise_identity_service.h b/components/enterprise/signin/enterprise_identity_service.h
deleted file mode 100644
index e7f7896..0000000
--- a/components/enterprise/signin/enterprise_identity_service.h
+++ /dev/null
@@ -1,67 +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 COMPONENTS_ENTERPRISE_SIGNIN_ENTERPRISE_IDENTITY_SERVICE_H_
-#define COMPONENTS_ENTERPRISE_SIGNIN_ENTERPRISE_IDENTITY_SERVICE_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/functional/callback_forward.h"
-#include "base/observer_list_types.h"
-#include "components/keyed_service/core/keyed_service.h"
-
-struct CoreAccountInfo;
-
-namespace signin {
-class IdentityManager;
-}
-
-namespace enterprise {
-
-class EnterpriseIdentityService : public KeyedService {
- public:
-  static std::unique_ptr<EnterpriseIdentityService> Create(
-      signin::IdentityManager* identity_manager);
-
-  class Observer : public base::CheckedObserver {
-   public:
-    ~Observer() override = default;
-
-    Observer(const Observer&) = delete;
-    Observer& operator=(const Observer&) = delete;
-
-    // Invoked when a managed account's session state has changed (e.g. account
-    // added, refresh tokens updated).
-    virtual void OnManagedAccountSessionChanged() {}
-
-   protected:
-    Observer() = default;
-  };
-
-  using GetManagedAccountsCallback =
-      base::OnceCallback<void(std::vector<CoreAccountInfo>)>;
-
-  // Will invoke `callback` with the list of valid managed accounts. Makes sure
-  // to wait for the extended account information to be available when needed
-  // before resolving the callback.
-  virtual void GetManagedAccountsWithRefreshTokens(
-      GetManagedAccountsCallback callback) = 0;
-
-  // Will invoke `callback` with a list of OAuth access tokens created with the
-  // DM server scope for each valid managed accounts.
-  virtual void GetManagedAccountsAccessTokens(
-      base::OnceCallback<void(std::vector<std::string>)> callback) = 0;
-
-  // Adds `observer` to the list of observers.
-  virtual void AddObserver(Observer* observer) = 0;
-
-  // Removes `observer` from the list of observers.
-  virtual void RemoveObserver(Observer* observer) = 0;
-};
-
-}  // namespace enterprise
-
-#endif  // COMPONENTS_ENTERPRISE_SIGNIN_ENTERPRISE_IDENTITY_SERVICE_H_
diff --git a/components/enterprise/signin/enterprise_identity_service_unittest.cc b/components/enterprise/signin/enterprise_identity_service_unittest.cc
deleted file mode 100644
index f6e4d049..0000000
--- a/components/enterprise/signin/enterprise_identity_service_unittest.cc
+++ /dev/null
@@ -1,320 +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/enterprise/signin/enterprise_identity_service.h"
-
-#include "base/run_loop.h"
-#include "base/test/task_environment.h"
-#include "base/test/test_future.h"
-#include "components/signin/public/identity_manager/account_info.h"
-#include "components/signin/public/identity_manager/identity_manager.h"
-#include "components/signin/public/identity_manager/identity_test_environment.h"
-#include "components/signin/public/identity_manager/identity_test_utils.h"
-#include "components/signin/public/identity_manager/scope_set.h"
-#include "google_apis/gaia/gaia_constants.h"
-#include "google_apis/gaia/google_service_auth_error.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace enterprise {
-
-using ::testing::StrictMock;
-
-namespace {
-
-constexpr char kAccessToken1[] = "access_token1";
-constexpr char kAccessToken2[] = "access_token2";
-
-class MockEnterpriseIdentityServiceObserver
-    : public EnterpriseIdentityService::Observer {
- public:
-  MockEnterpriseIdentityServiceObserver() = default;
-  ~MockEnterpriseIdentityServiceObserver() override = default;
-
-  MOCK_METHOD(void, OnManagedAccountSessionChanged, (), (override));
-};
-
-}  // namespace
-
-class EnterpriseIdentityServiceTest : public testing::Test {
- protected:
-  EnterpriseIdentityServiceTest() {
-    identity_env_.WaitForRefreshTokensLoaded();
-  }
-
-  std::unique_ptr<EnterpriseIdentityService> CreateService() {
-    return EnterpriseIdentityService::Create(identity_env_.identity_manager());
-  }
-
-  const signin::IdentityManager* identity_manager() const {
-    return identity_env_.identity_manager();
-  }
-
-  base::test::SingleThreadTaskEnvironment task_env_{
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
-  signin::IdentityTestEnvironment identity_env_;
-};
-
-TEST_F(EnterpriseIdentityServiceTest,
-       GetManagedAccountsWithRefreshTokens_NoUser) {
-  ASSERT_TRUE(identity_manager()->AreRefreshTokensLoaded());
-  ASSERT_TRUE(identity_manager()->GetAccountsWithRefreshTokens().empty());
-
-  auto service = CreateService();
-  ASSERT_TRUE(service);
-  base::test::TestFuture<std::vector<CoreAccountInfo>> test_future;
-  service->GetManagedAccountsWithRefreshTokens(test_future.GetCallback());
-
-  EXPECT_TRUE(test_future.Get().empty());
-}
-
-TEST_F(EnterpriseIdentityServiceTest,
-       GetManagedAccountsWithRefreshTokens_SingleManagedUser_Async) {
-  AccountInfo account =
-      identity_env_.MakeAccountAvailable("account@enterprise.com");
-
-  auto service = CreateService();
-  base::test::TestFuture<std::vector<CoreAccountInfo>> test_future;
-  service->GetManagedAccountsWithRefreshTokens(test_future.GetCallback());
-
-  // Value not already available.
-  EXPECT_FALSE(test_future.IsReady());
-
-  // Full info becomes available.
-  identity_env_.SimulateSuccessfulFetchOfAccountInfo(
-      account.account_id, account.email, account.gaia,
-      /*hosted_domain=*/"enterprise.com", "Full Name", "Given Name", "en-US",
-      /*picture_url=*/"");
-
-  auto managed_accounts = test_future.Get();
-  ASSERT_EQ(managed_accounts.size(), 1U);
-  EXPECT_EQ(managed_accounts.front(), account);
-}
-
-TEST_F(EnterpriseIdentityServiceTest,
-       GetManagedAccountsWithRefreshTokens_SingleManagedUser_Sync) {
-  // google.com accounts are determined as managed accounts synchronously.
-  AccountInfo account =
-      identity_env_.MakeAccountAvailable("account@google.com");
-
-  auto service = CreateService();
-  base::test::TestFuture<std::vector<CoreAccountInfo>> test_future;
-  service->GetManagedAccountsWithRefreshTokens(test_future.GetCallback());
-
-  // Value is already available.
-  EXPECT_TRUE(test_future.IsReady());
-
-  auto managed_accounts = test_future.Get();
-  ASSERT_EQ(managed_accounts.size(), 1U);
-  EXPECT_EQ(managed_accounts.front(), account);
-}
-
-TEST_F(EnterpriseIdentityServiceTest,
-       GetManagedAccountsWithRefreshTokens_NoRefreshTokens_ThenOneUser) {
-  AccountInfo account =
-      identity_env_.MakeAccountAvailable("account@enterprise.com");
-  identity_env_.ResetToAccountsNotYetLoadedFromDiskState();
-  EXPECT_FALSE(identity_manager()->AreRefreshTokensLoaded());
-
-  auto service = CreateService();
-  base::test::TestFuture<std::vector<CoreAccountInfo>> test_future;
-  service->GetManagedAccountsWithRefreshTokens(test_future.GetCallback());
-
-  // Value not already available, as the request is waiting for refresh tokens
-  // to have been loaded.
-  EXPECT_FALSE(test_future.IsReady());
-
-  identity_env_.ReloadAccountsFromDisk();
-  identity_env_.WaitForRefreshTokensLoaded();
-
-  EXPECT_FALSE(test_future.IsReady());
-
-  identity_env_.SimulateSuccessfulFetchOfAccountInfo(
-      account.account_id, account.email, account.gaia,
-      /*hosted_domain=*/"enterprise.com", "Full Name", "Given Name", "en-US",
-      /*picture_url=*/"");
-
-  auto managed_accounts = test_future.Get();
-  ASSERT_EQ(managed_accounts.size(), 1U);
-  EXPECT_EQ(managed_accounts.front(), account);
-}
-
-TEST_F(EnterpriseIdentityServiceTest,
-       GetManagedAccountsWithRefreshTokens_MultipleMixedUsers) {
-  AccountInfo google_account =
-      identity_env_.MakeAccountAvailable("account@google.com");
-  AccountInfo async_enterprise_account =
-      identity_env_.MakeAccountAvailable("account@enterprise.com");
-  AccountInfo gmail_account =
-      identity_env_.MakeAccountAvailable("account@gmail.com");
-  AccountInfo async_consumer_account =
-      identity_env_.MakeAccountAvailable("account@consumer.com");
-
-  auto service = CreateService();
-  base::test::TestFuture<std::vector<CoreAccountInfo>> test_future;
-  service->GetManagedAccountsWithRefreshTokens(test_future.GetCallback());
-
-  EXPECT_FALSE(test_future.IsReady());
-
-  identity_env_.SimulateSuccessfulFetchOfAccountInfo(
-      async_enterprise_account.account_id, async_enterprise_account.email,
-      async_enterprise_account.gaia,
-      /*hosted_domain=*/"enterprise.com", "Full Name", "Given Name", "en-US",
-      /*picture_url=*/"");
-
-  EXPECT_FALSE(test_future.IsReady());
-
-  identity_env_.SimulateSuccessfulFetchOfAccountInfo(
-      async_consumer_account.account_id, async_consumer_account.email,
-      async_consumer_account.gaia,
-      /*hosted_domain=*/"", "Full Name", "Given Name", "en-US",
-      /*picture_url=*/"");
-
-  auto managed_accounts = test_future.Get();
-  ASSERT_EQ(managed_accounts.size(), 2U);
-  ASSERT_THAT(managed_accounts, testing::UnorderedElementsAre(
-                                    google_account, async_enterprise_account));
-}
-
-TEST_F(EnterpriseIdentityServiceTest,
-       GetManagedAccountsAccessTokens_SingleManagedUser_Success) {
-  AccountInfo account =
-      identity_env_.MakeAccountAvailable("account@enterprise.com");
-  identity_env_.SimulateSuccessfulFetchOfAccountInfo(
-      account.account_id, account.email, account.gaia,
-      /*hosted_domain=*/"enterprise.com", "Full Name", "Given Name", "en-US",
-      /*picture_url=*/"");
-
-  auto service = CreateService();
-  base::test::TestFuture<std::vector<std::string>> test_future;
-  service->GetManagedAccountsAccessTokens(test_future.GetCallback());
-
-  identity_env_
-      .WaitForAccessTokenRequestIfNecessaryAndRespondWithTokenForScopes(
-          kAccessToken1, base::Time::Max(), /*id_token=*/std::string(),
-          signin::ScopeSet{GaiaConstants::kDeviceManagementServiceOAuth});
-
-  EXPECT_THAT(test_future.Get(), testing::ElementsAre(kAccessToken1));
-}
-
-TEST_F(EnterpriseIdentityServiceTest,
-       GetManagedAccountsAccessTokens_SingleManagedUser_Error) {
-  AccountInfo account =
-      identity_env_.MakeAccountAvailable("account@enterprise.com");
-  identity_env_.SimulateSuccessfulFetchOfAccountInfo(
-      account.account_id, account.email, account.gaia,
-      /*hosted_domain=*/"enterprise.com", "Full Name", "Given Name", "en-US",
-      /*picture_url=*/"");
-
-  auto service = CreateService();
-  base::test::TestFuture<std::vector<std::string>> test_future;
-  service->GetManagedAccountsAccessTokens(test_future.GetCallback());
-
-  identity_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
-      GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE));
-
-  EXPECT_TRUE(test_future.Get().empty());
-}
-
-TEST_F(EnterpriseIdentityServiceTest,
-       GetManagedAccountsAccessTokens_MixedUsers) {
-  AccountInfo google_account =
-      identity_env_.MakeAccountAvailable("account@google.com");
-  AccountInfo async_enterprise_account =
-      identity_env_.MakeAccountAvailable("account@enterprise.com");
-  AccountInfo gmail_account =
-      identity_env_.MakeAccountAvailable("account@gmail.com");
-  AccountInfo async_consumer_account =
-      identity_env_.MakeAccountAvailable("account@consumer.com");
-
-  identity_env_.SimulateSuccessfulFetchOfAccountInfo(
-      async_enterprise_account.account_id, async_enterprise_account.email,
-      async_enterprise_account.gaia,
-      /*hosted_domain=*/"enterprise.com", "Full Name", "Given Name", "en-US",
-      /*picture_url=*/"");
-  identity_env_.SimulateSuccessfulFetchOfAccountInfo(
-      async_consumer_account.account_id, async_consumer_account.email,
-      async_consumer_account.gaia,
-      /*hosted_domain=*/"", "Full Name", "Given Name", "en-US",
-      /*picture_url=*/"");
-
-  auto service = CreateService();
-  base::test::TestFuture<std::vector<std::string>> test_future;
-  service->GetManagedAccountsAccessTokens(test_future.GetCallback());
-
-  identity_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
-      google_account.account_id, kAccessToken1, base::Time::Max());
-  identity_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
-      async_enterprise_account.account_id, kAccessToken2, base::Time::Max());
-
-  EXPECT_THAT(test_future.Get(),
-              testing::UnorderedElementsAre(kAccessToken1, kAccessToken2));
-}
-
-TEST_F(EnterpriseIdentityServiceTest,
-       Observer_OnManagedAccountSessionChanged_SyncManagedUser) {
-  StrictMock<MockEnterpriseIdentityServiceObserver> observer;
-  EXPECT_CALL(observer, OnManagedAccountSessionChanged).Times(1);
-
-  auto service = CreateService();
-  service->AddObserver(&observer);
-  identity_env_.MakeAccountAvailable("account@google.com");
-
-  service->RemoveObserver(&observer);
-}
-
-TEST_F(EnterpriseIdentityServiceTest,
-       Observer_OnManagedAccountSessionChanged_SyncConsumerUser) {
-  StrictMock<MockEnterpriseIdentityServiceObserver> observer;
-  EXPECT_CALL(observer, OnManagedAccountSessionChanged).Times(0);
-
-  auto service = CreateService();
-  service->AddObserver(&observer);
-  identity_env_.MakeAccountAvailable("account@gmail.com");
-
-  service->RemoveObserver(&observer);
-}
-
-TEST_F(EnterpriseIdentityServiceTest,
-       Observer_OnManagedAccountSessionChanged_AsyncManagedUser) {
-  base::RunLoop run_loop;
-  StrictMock<MockEnterpriseIdentityServiceObserver> observer;
-  EXPECT_CALL(observer, OnManagedAccountSessionChanged).WillOnce([&run_loop]() {
-    run_loop.Quit();
-  });
-
-  auto service = CreateService();
-  service->AddObserver(&observer);
-  auto async_enterprise_account =
-      identity_env_.MakeAccountAvailable("account@enterprise.com");
-  identity_env_.SimulateSuccessfulFetchOfAccountInfo(
-      async_enterprise_account.account_id, async_enterprise_account.email,
-      async_enterprise_account.gaia,
-      /*hosted_domain=*/"enterprise.com", "Full Name", "Given Name", "en-US",
-      /*picture_url=*/"");
-
-  run_loop.Run();
-
-  service->RemoveObserver(&observer);
-}
-
-TEST_F(EnterpriseIdentityServiceTest,
-       Observer_OnManagedAccountSessionChanged_ManagedUserRefresh) {
-  auto account = identity_env_.MakeAccountAvailable("account@google.com");
-
-  StrictMock<MockEnterpriseIdentityServiceObserver> observer;
-  auto service = CreateService();
-  service->AddObserver(&observer);
-
-  base::RunLoop run_loop;
-  EXPECT_CALL(observer, OnManagedAccountSessionChanged).WillOnce([&run_loop]() {
-    run_loop.Quit();
-  });
-  identity_env_.SetRefreshTokenForAccount(account.account_id);
-  run_loop.Run();
-
-  service->RemoveObserver(&observer);
-}
-
-}  // namespace enterprise
diff --git a/components/enterprise/signin/mock_enterprise_identity_service.h b/components/enterprise/signin/mock_enterprise_identity_service.h
deleted file mode 100644
index 4ee7e9cf..0000000
--- a/components/enterprise/signin/mock_enterprise_identity_service.h
+++ /dev/null
@@ -1,40 +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 COMPONENTS_ENTERPRISE_SIGNIN_MOCK_ENTERPRISE_IDENTITY_SERVICE_H_
-#define COMPONENTS_ENTERPRISE_SIGNIN_MOCK_ENTERPRISE_IDENTITY_SERVICE_H_
-
-#include "base/functional/callback.h"
-#include "components/enterprise/signin/enterprise_identity_service.h"
-#include "components/signin/public/identity_manager/account_info.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace enterprise {
-
-class MockEnterpriseIdentityService : public EnterpriseIdentityService {
- public:
-  MockEnterpriseIdentityService();
-  ~MockEnterpriseIdentityService() override;
-
-  MOCK_METHOD(void,
-              GetManagedAccountsWithRefreshTokens,
-              (GetManagedAccountsCallback),
-              (override));
-  MOCK_METHOD(void,
-              GetManagedAccountsAccessTokens,
-              (base::OnceCallback<void(std::vector<std::string>)>),
-              (override));
-  MOCK_METHOD(void,
-              AddObserver,
-              (EnterpriseIdentityService::Observer*),
-              (override));
-  MOCK_METHOD(void,
-              RemoveObserver,
-              (EnterpriseIdentityService::Observer*),
-              (override));
-};
-
-}  // namespace enterprise
-
-#endif  // COMPONENTS_ENTERPRISE_SIGNIN_MOCK_ENTERPRISE_IDENTITY_SERVICE_H_
diff --git a/components/os_crypt/async/browser/secret_portal_key_provider.cc b/components/os_crypt/async/browser/secret_portal_key_provider.cc
index cb5455a..fdc5dbb 100644
--- a/components/os_crypt/async/browser/secret_portal_key_provider.cc
+++ b/components/os_crypt/async/browser/secret_portal_key_provider.cc
@@ -84,9 +84,9 @@
   return false;
 }
 
-void SecretPortalKeyProvider::OnPortalServiceStarted(bool service_started) {
+void SecretPortalKeyProvider::OnPortalServiceStarted(uint32_t version) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (!service_started) {
+  if (version == 0) {
     return Finalize(InitStatus::kNoService);
   }
 
diff --git a/components/os_crypt/async/browser/secret_portal_key_provider.h b/components/os_crypt/async/browser/secret_portal_key_provider.h
index eb64734f..98dc8cd1 100644
--- a/components/os_crypt/async/browser/secret_portal_key_provider.h
+++ b/components/os_crypt/async/browser/secret_portal_key_provider.h
@@ -107,7 +107,7 @@
   bool UseForEncryption() override;
   bool IsCompatibleWithOsCryptSync() override;
 
-  void OnPortalServiceStarted(bool service_started);
+  void OnPortalServiceStarted(uint32_t version);
 
   void OnRetrieveSecret(
       base::expected<dbus_xdg::Dictionary, dbus_xdg::ResponseError> results);
diff --git a/components/regional_capabilities/regional_capabilities_internals_data_holder.cc b/components/regional_capabilities/regional_capabilities_internals_data_holder.cc
index bd86264..1923f1a 100644
--- a/components/regional_capabilities/regional_capabilities_internals_data_holder.cc
+++ b/components/regional_capabilities/regional_capabilities_internals_data_holder.cc
@@ -5,36 +5,47 @@
 #include "components/regional_capabilities/regional_capabilities_internals_data_holder.h"
 
 #include "base/check_is_test.h"
+#include "base/notreached.h"
 #include "components/regional_capabilities/access/country_access_reason.h"
 #include "components/regional_capabilities/regional_capabilities_service.h"
 #include "components/webui/regional_capabilities_internals/constants.h"
 
 namespace regional_capabilities {
 
+namespace {
+std::string ProgramToString(Program program) {
+  switch (program) {
+    case Program::kDefault:
+      return "Default";
+    case Program::kTaiyaki:
+      return "Taiyaki";
+    case Program::kWaffle:
+      return "Waffle";
+  }
+  NOTREACHED();
+}
+}  // namespace
+
 InternalsDataHolder::InternalsDataHolder(
     RegionalCapabilitiesService& regional_capabilities) {
-  std::string active_program_name = "Unknown Program";
-  switch (regional_capabilities.GetActiveProgramSettings().program) {
-    case Program::kDefault:
-      active_program_name = "Default";
-      break;
-    case Program::kTaiyaki:
-      active_program_name = "Taiyaki";
-      break;
-    case Program::kWaffle:
-      active_program_name = "Waffle";
-      break;
-  }
-  data_.insert_or_assign(kActiveProgramNameKey, active_program_name);
+  data_.insert_or_assign(
+      kActiveProgramNameKey,
+      ProgramToString(
+          regional_capabilities.GetActiveProgramSettings().program));
 
   data_.insert_or_assign(
       kActiveCountryCodeKey,
       regional_capabilities.GetCountryIdInternal().CountryCode());
 
-  // DO_NOT_SUBMIT: Ensure this doesn't cause histograms to be recorded first.
   data_.insert_or_assign(
       kPrefsCountryCodeKey,
       regional_capabilities.GetPersistedCountryId().CountryCode());
+
+#if BUILDFLAG(IS_ANDROID)
+  data_.insert_or_assign(
+      kDeviceDeterminedProgramKey,
+      ProgramToString(regional_capabilities.client_->GetDeviceProgram()));
+#endif
 }
 
 InternalsDataHolder::~InternalsDataHolder() = default;
diff --git a/components/signin/DESKTOP_OWNERS b/components/signin/DESKTOP_OWNERS
index 7d5c51b..89c7a5a 100644
--- a/components/signin/DESKTOP_OWNERS
+++ b/components/signin/DESKTOP_OWNERS
@@ -1,11 +1,19 @@
+# Note: Unless you want a specific reviewer's expertise, please send CLs to
+# chrome-signin-desktop-reviews@google.com rather than to specific individuals.
+#
+# These CLs will be automatically reassigned to a reviewer within
+# about 5 minutes. This approach helps our team to load-balance incoming
+# reviews.
+chrome-signin-desktop-reviews@google.com
+
 # keep-sorted start
-alexilin@chromium.org
-amelies@google.com
-anthie@google.com
-ddac@chromium.org
-droger@chromium.org
-ernn@google.com
-msalama@chromium.org
-msarda@chromium.org
-rsult@google.com
+alexilin@chromium.org  #{LAST_RESORT_SUGGESTION}
+amelies@google.com     #{LAST_RESORT_SUGGESTION}
+anthie@google.com      #{LAST_RESORT_SUGGESTION}
+ddac@chromium.org      #{LAST_RESORT_SUGGESTION}
+droger@chromium.org    #{LAST_RESORT_SUGGESTION}
+ernn@google.com        #{LAST_RESORT_SUGGESTION}
+msalama@chromium.org   #{LAST_RESORT_SUGGESTION}
+msarda@chromium.org    #{LAST_RESORT_SUGGESTION}
+rsult@google.com       #{LAST_RESORT_SUGGESTION}
 # keep-sorted end
diff --git a/components/signin/public/base/oauth_consumer_id.h b/components/signin/public/base/oauth_consumer_id.h
index 8580eab28..30d19c7 100644
--- a/components/signin/public/base/oauth_consumer_id.h
+++ b/components/signin/public/base/oauth_consumer_id.h
@@ -10,7 +10,8 @@
 namespace oauth_consumer_name {
 inline extern const char kEnterprisePlusAddressName[] =
     "enterprise_plus_address";
-}
+inline extern const char kGlicUserStatusName[] = "glic_user_status";
+}  // namespace oauth_consumer_name
 
 // LINT.IfChange(OAuthConsumerId)
 // These values are persisted to logs. Entries should not be renumbered and
@@ -68,7 +69,7 @@
   kEduCoexistenceLoginHandler = 48,
   kEduAccountLoginHandler = 49,
   kChromeosFamilyLinkUserMetricsProvider = 50,
-  kEnterpriseIdentityService = 51,
+  // kEnterpriseIdentityService = 51, // Removed due to deprecation.
   kPromotionEligibilityChecker = 52,
   kPasswordManagerLeakDetection = 53,
   kAndroidManagementClient = 54,
@@ -97,7 +98,9 @@
   kYouTubeMusic = 77,
   kContextualTasks = 78,
   kEnterprisePlusAddress = 79,
-  kMaxValue = kEnterprisePlusAddress,
+  kGlicUserStatus = 80,
+  kDevtoolsGdp = 81,
+  kMaxValue = kDevtoolsGdp,
 };
 // LINT.ThenChange(//tools/metrics/histograms/metadata/signin/enums.xml:OAuthConsumerId)
 
diff --git a/components/signin/public/base/oauth_consumer_registry.cc b/components/signin/public/base/oauth_consumer_registry.cc
index 515526b..a5e6e56 100644
--- a/components/signin/public/base/oauth_consumer_registry.cc
+++ b/components/signin/public/base/oauth_consumer_registry.cc
@@ -76,7 +76,6 @@
 constexpr char kEduAccountLoginHandlerName[] = "edu_account_login_handler";
 constexpr char kChromeosFamilyLinkUserMetricsProviderName[] =
     "chromeos_family_link_user_metrics_provider";
-constexpr char kEnterpriseIdentityServiceName[] = "enterprise_identity_service";
 constexpr char kPromotionEligibilityCheckerName[] =
     "promotion_eligibility_checker";
 constexpr char kPasswordManagerLeakDetectionName[] =
@@ -110,6 +109,7 @@
 constexpr char kAuthServiceTasksClientName[] = "auth_service_tasks_client";
 constexpr char kYouTubeMusicName[] = "youtube_music";
 constexpr char kContextualTasksName[] = "contextual_tasks";
+constexpr char kDevtoolsGdpName[] = "devtools_gdp_client";
 
 }  // namespace
 
@@ -351,10 +351,6 @@
       return OAuthConsumer(
           /*name=*/kChromeosFamilyLinkUserMetricsProviderName,
           /*scopes=*/{});
-    case OAuthConsumerId::kEnterpriseIdentityService:
-      return OAuthConsumer(
-          /*name=*/kEnterpriseIdentityServiceName,
-          /*scopes=*/{GaiaConstants::kDeviceManagementServiceOAuth});
     case OAuthConsumerId::kPromotionEligibilityChecker:
       return OAuthConsumer(
           /*name=*/kPromotionEligibilityCheckerName,
@@ -484,6 +480,12 @@
                       GaiaConstants::kClearCutOAuth2Scope});
     case OAuthConsumerId::kEnterprisePlusAddress:
       return GetOAuthConsumerForEnterprisePlusAddress();
+    case OAuthConsumerId::kGlicUserStatus:
+      return GetOAuthConsumerForGlicUserStatus();
+    case OAuthConsumerId::kDevtoolsGdp:
+      return OAuthConsumer(
+          /*name=*/kDevtoolsGdpName,
+          /*scopes=*/{GaiaConstants::kGdpOAuth2Scope});
   }
 }
 
diff --git a/components/signin/public/base/oauth_consumer_registry.h b/components/signin/public/base/oauth_consumer_registry.h
index 64fa2296..026c33976 100644
--- a/components/signin/public/base/oauth_consumer_registry.h
+++ b/components/signin/public/base/oauth_consumer_registry.h
@@ -31,6 +31,7 @@
 
  protected:
   virtual OAuthConsumer GetOAuthConsumerForEnterprisePlusAddress() const = 0;
+  virtual OAuthConsumer GetOAuthConsumerForGlicUserStatus() const = 0;
 };
 
 }  // namespace signin
diff --git a/components/signin/public/base/test_signin_client.cc b/components/signin/public/base/test_signin_client.cc
index 142ca96c..402c142 100644
--- a/components/signin/public/base/test_signin_client.cc
+++ b/components/signin/public/base/test_signin_client.cc
@@ -30,6 +30,10 @@
         signin::oauth_consumer_name::kEnterprisePlusAddressName,
         {plus_addresses::features::kEnterprisePlusAddressOAuthScope.Get()});
   }
+
+  signin::OAuthConsumer GetOAuthConsumerForGlicUserStatus() const override {
+    NOTREACHED();
+  }
 };
 
 }  // namespace
diff --git a/components/signin/public/webdata/token_service_table.cc b/components/signin/public/webdata/token_service_table.cc
index 0d09d86b..fd7faa31 100644
--- a/components/signin/public/webdata/token_service_table.cc
+++ b/components/signin/public/webdata/token_service_table.cc
@@ -5,6 +5,7 @@
 #include "components/signin/public/webdata/token_service_table.h"
 
 #include <map>
+#include <optional>
 #include <string>
 
 #include "base/logging.h"
@@ -16,6 +17,7 @@
 #include "components/webdata/common/web_database.h"
 #include "sql/statement.h"
 #include "sql/transaction.h"
+#include "third_party/abseil-cpp/absl/cleanup/cleanup.h"
 
 namespace {
 
@@ -46,6 +48,19 @@
   kMaxValue = kSqlFailure,
 };
 
+// Entries in the `Signin.TokenTable.GetAllWrappedBindingKeysResult` histogram.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+//
+// LINT.IfChange(GetAllWrappedBindingKeysResult)
+enum class GetAllWrappedBindingKeysResult {
+  kSuccess = 0,
+  kSqlInvalidStatement = 1,
+  kSqlFailure = 2,
+  kMaxValue = kSqlFailure,
+};
+// LINT.ThenChange(//tools/metrics/histograms/metadata/signin/enums.xml:SigninTokenTableGetAllWrappedBindingKeysResult)
+
 void RecordRemoveOtherTokensHistogram(size_t remove_count) {
   base::UmaHistogramCounts100("Signin.TokenTable.RemoveOtherTokensCount",
                               remove_count);
@@ -235,6 +250,37 @@
   return read_all_tokens_result;
 }
 
+std::optional<absl::flat_hash_set<std::vector<uint8_t>>>
+TokenServiceTable::GetAllWrappedBindingKeys() {
+  GetAllWrappedBindingKeysResult result =
+      GetAllWrappedBindingKeysResult::kSuccess;
+
+  absl::Cleanup record_result = [&result] {
+    base::UmaHistogramEnumeration(
+        "Signin.TokenTable.GetAllWrappedBindingKeysResult", result);
+  };
+
+  sql::Statement s(
+      db()->GetUniqueStatement("SELECT binding_key FROM token_service"));
+
+  if (!s.is_valid()) {
+    result = GetAllWrappedBindingKeysResult::kSqlInvalidStatement;
+    return std::nullopt;
+  }
+
+  absl::flat_hash_set<std::vector<uint8_t>> wrapped_binding_keys;
+  while (s.Step()) {
+    wrapped_binding_keys.insert(s.ColumnBlobAsVector(0));
+  }
+
+  if (!s.Succeeded()) {
+    result = GetAllWrappedBindingKeysResult::kSqlFailure;
+    return std::nullopt;
+  }
+
+  return wrapped_binding_keys;
+}
+
 bool TokenServiceTable::MigrateToVersion130AddBindingKeyColumn() {
   sql::Transaction transaction(db());
   return transaction.Begin() &&
diff --git a/components/signin/public/webdata/token_service_table.h b/components/signin/public/webdata/token_service_table.h
index 7c38aa9..d7285cf 100644
--- a/components/signin/public/webdata/token_service_table.h
+++ b/components/signin/public/webdata/token_service_table.h
@@ -6,11 +6,12 @@
 #define COMPONENTS_SIGNIN_PUBLIC_WEBDATA_TOKEN_SERVICE_TABLE_H_
 
 #include <map>
+#include <optional>
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
 #include "components/webdata/common/web_database_table.h"
+#include "third_party/abseil-cpp/absl/container/flat_hash_set.h"
 
 class WebDatabase;
 
@@ -72,6 +73,11 @@
   Result GetAllTokens(std::map<std::string, TokenWithBindingKey>* tokens,
                       bool& should_reencrypt);
 
+  // Retrieves all wrapped binding keys previously set with
+  // `SetTokenForService`. Returns nullopt if there was a failure somehow.
+  std::optional<absl::flat_hash_set<std::vector<uint8_t>>>
+  GetAllWrappedBindingKeys();
+
   // Stores a token with an optional binding key in the token_service table.
   // Token is stored encrypted. May cause a mac keychain popup.
   // Returns true if we encrypted a token and stored it, false otherwise.
diff --git a/components/signin/public/webdata/token_service_table_unittest.cc b/components/signin/public/webdata/token_service_table_unittest.cc
index 3e28700..02373552 100644
--- a/components/signin/public/webdata/token_service_table_unittest.cc
+++ b/components/signin/public/webdata/token_service_table_unittest.cc
@@ -24,8 +24,10 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using ::base::Time;
+using ::testing::ElementsAre;
 using ::testing::IsEmpty;
 using ::testing::Key;
+using ::testing::Optional;
 using ::testing::SizeIs;
 using ::testing::UnorderedElementsAre;
 using ::testing::UnorderedElementsAreArray;
@@ -93,6 +95,23 @@
   EXPECT_EQ(TokenWithBindingKey("cheese"), out_map.find(service)->second);
 }
 
+TEST_F(TokenServiceTableTest, TokenServiceGetAllWrappedBindingKeys) {
+  EXPECT_THAT(table_->GetAllWrappedBindingKeys(), Optional(IsEmpty()));
+
+  EXPECT_TRUE(table_->SetTokenForService("service1", "token1", {1, 2, 3}));
+  EXPECT_TRUE(table_->SetTokenForService("service2", "token2", {4, 5, 6}));
+  EXPECT_TRUE(table_->SetTokenForService("service3", "token3", {7, 8, 9}));
+  EXPECT_THAT(
+      table_->GetAllWrappedBindingKeys(),
+      Optional(UnorderedElementsAre(ElementsAre(1, 2, 3), ElementsAre(4, 5, 6),
+                                    ElementsAre(7, 8, 9))));
+
+  EXPECT_TRUE(table_->RemoveTokenForService("service1"));
+  EXPECT_THAT(table_->GetAllWrappedBindingKeys(),
+              Optional(UnorderedElementsAre(ElementsAre(4, 5, 6),
+                                            ElementsAre(7, 8, 9))));
+}
+
 TEST_F(TokenServiceTableTest, TokenServiceGetSet) {
   std::map<std::string, TokenWithBindingKey> out_map;
   std::string service;
@@ -265,6 +284,15 @@
     histograms.ExpectUniqueSample("Signin.TokenTable.ReadTokenFromDBResult",
                                   /*READ_ONE_TOKEN_SUCCESS*/ 0, 1u);
   }
+
+  {
+    base::HistogramTester histograms;
+    EXPECT_THAT(table_->GetAllWrappedBindingKeys(),
+                Optional(UnorderedElementsAre(IsEmpty())));
+    histograms.ExpectUniqueSample(
+        "Signin.TokenTable.GetAllWrappedBindingKeysResult",
+        /*kSuccess*/ 0, 1u);
+  }
 }
 
 class TokenServiceTableEncryptionOptionsTest : public testing::Test {
diff --git a/components/signin/public/webdata/token_web_data.cc b/components/signin/public/webdata/token_web_data.cc
index 1748c3e..1d9bdbb 100644
--- a/components/signin/public/webdata/token_web_data.cc
+++ b/components/signin/public/webdata/token_web_data.cc
@@ -5,12 +5,15 @@
 #include "components/signin/public/webdata/token_web_data.h"
 
 #include <memory>
+#include <optional>
 
 #include "base/functional/bind.h"
 #include "base/memory/ref_counted_delete_on_sequence.h"
 #include "base/task/sequenced_task_runner.h"
+#include "base/types/expected_macros.h"
 #include "components/signin/public/webdata/token_service_table.h"
 #include "components/webdata/common/web_database_service.h"
+#include "third_party/abseil-cpp/absl/container/flat_hash_set.h"
 
 using base::BindOnce;
 
@@ -68,6 +71,17 @@
                                                    std::move(result));
   }
 
+  std::unique_ptr<WDTypedResult> GetAllWrappedBindingKeys(WebDatabase* db) {
+    ASSIGN_OR_RETURN(
+        absl::flat_hash_set<std::vector<uint8_t>> keys,
+        TokenServiceTable::FromWebDatabase(db)->GetAllWrappedBindingKeys(),
+        [] -> std::unique_ptr<WDTypedResult> { return nullptr; });
+
+    return std::make_unique<
+        WDResult<absl::flat_hash_set<std::vector<uint8_t>>>>(
+        WRAPPED_BINDING_KEYS_RESULT, std::move(keys));
+  }
+
  protected:
   virtual ~TokenWebDataBackend() = default;
 
@@ -126,4 +140,13 @@
       consumer);
 }
 
+// Null on failure. Success is WDResult<std::vector<std::vector<uint8_t>>>
+WebDataServiceBase::Handle TokenWebData::GetAllWrappedBindingKeys(
+    WebDataServiceConsumer* consumer) {
+  return wdbs_->ScheduleDBTaskWithResult(
+      FROM_HERE,
+      BindOnce(&TokenWebDataBackend::GetAllWrappedBindingKeys, token_backend_),
+      consumer);
+}
+
 TokenWebData::~TokenWebData() = default;
diff --git a/components/signin/public/webdata/token_web_data.h b/components/signin/public/webdata/token_web_data.h
index e5583d9..0249236 100644
--- a/components/signin/public/webdata/token_web_data.h
+++ b/components/signin/public/webdata/token_web_data.h
@@ -67,9 +67,12 @@
   // service is present in `services_to_keep`.
   void RemoveOtherTokens(const std::vector<std::string>& services_to_keep);
 
-  // Null on failure. Success is `WDResult<std::vector<std::string>>`.
+  // Null on failure. Success is `WDResult<TokenResult>`.
   virtual Handle GetAllTokens(WebDataServiceConsumer* consumer);
 
+  // Null on failure. Success is `WDResult<std::vector<std::vector<uint8_t>>>`.
+  virtual Handle GetAllWrappedBindingKeys(WebDataServiceConsumer* consumer);
+
  protected:
   ~TokenWebData() override;
 
diff --git a/components/tabs/impl/tab_strip_collection.cc b/components/tabs/impl/tab_strip_collection.cc
index fd10031..24109a6 100644
--- a/components/tabs/impl/tab_strip_collection.cc
+++ b/components/tabs/impl/tab_strip_collection.cc
@@ -339,7 +339,7 @@
 void TabStripCollection::InsertTabCollectionAt(
     std::unique_ptr<TabCollection> collection,
     int index,
-    int pinned,
+    bool pinned,
     std::optional<tab_groups::TabGroupId> parent_group) {
   TabCollection::Position insertion_details =
       GetInsertionDetails(index, pinned, parent_group);
@@ -728,7 +728,7 @@
 
 TabCollection::Position TabStripCollection::GetInsertionDetails(
     int index,
-    int pinned,
+    bool pinned,
     std::optional<tab_groups::TabGroupId> group) {
   size_t direct_dst_index;
   TabCollection* insert_collection = nullptr;
diff --git a/components/tabs/public/tab_strip_collection.h b/components/tabs/public/tab_strip_collection.h
index 43cae28..b703709 100644
--- a/components/tabs/public/tab_strip_collection.h
+++ b/components/tabs/public/tab_strip_collection.h
@@ -72,7 +72,7 @@
   void InsertTabCollectionAt(
       std::unique_ptr<TabCollection> collection,
       int index,
-      int pinned,
+      bool pinned,
       std::optional<tab_groups::TabGroupId> parent_group);
 
   // Remove a tab collection and send the appropriate notifications.
@@ -187,7 +187,7 @@
   // recursive index, pinned state and group to insert.
   TabCollection::Position GetInsertionDetails(
       int index,
-      int pinned,
+      bool pinned,
       std::optional<tab_groups::TabGroupId> group);
 
   // Returns the parent collection and the direct child index within that
diff --git a/components/wallet/core/browser/data_models/boarding_pass.cc b/components/wallet/core/browser/data_models/boarding_pass.cc
index 4856d91..87fb099 100644
--- a/components/wallet/core/browser/data_models/boarding_pass.cc
+++ b/components/wallet/core/browser/data_models/boarding_pass.cc
@@ -90,6 +90,13 @@
 constexpr int kFlightCodeLength = 5;
 constexpr int kDateLength = 3;
 
+// Removes leading zeros from a string, e.g., "007" becomes "7". If the string
+// is "000", it becomes "0".
+std::string RemoveLeadingZeros(std::string_view s) {
+  std::string_view trimmed = base::TrimString(s, "0", base::TRIM_LEADING);
+  return (trimmed.empty() && !s.empty()) ? "0" : std::string(trimmed);
+}
+
 }  // namespace
 
 // static
@@ -122,7 +129,7 @@
   pass.origin = value.GetStripped(kOriginLength);
   pass.destination = value.GetStripped(kDestinationLength);
   pass.airline = value.GetStripped(kAirlineLength);
-  pass.flight_code = value.GetStripped(kFlightCodeLength);
+  pass.flight_code = RemoveLeadingZeros(value.GetStripped(kFlightCodeLength));
   pass.date = value.GetStripped(kDateLength);
   pass.barcode = barcode;
 
diff --git a/components/wallet/core/browser/data_models/boarding_pass_unittest.cc b/components/wallet/core/browser/data_models/boarding_pass_unittest.cc
index f8e83ff..be22bf1 100644
--- a/components/wallet/core/browser/data_models/boarding_pass_unittest.cc
+++ b/components/wallet/core/browser/data_models/boarding_pass_unittest.cc
@@ -92,8 +92,30 @@
       ExpectedBoardingPass{.origin = "PPT",
                            .destination = "CDG",
                            .airline = "AF",
-                           .flight_code = "0077",
+                           .flight_code = "77",
                            .date = "137"});
 }
 
+TEST(BoardingPassTest, ParseBoardingPass_FlightCodeLeadingZeros) {
+  // Flight codes with leading zeros should have them removed.
+  TestValue("M1PASSENGER NAME      EABCDEFGSFOJFKUA 0007 123Y12A 00001100",
+            ExpectedBoardingPass{.origin = "SFO",
+                                 .destination = "JFK",
+                                 .airline = "UA",
+                                 .flight_code = "7",
+                                 .date = "123"});
+  TestValue("M1PASSENGER NAME      EABCDEFGSFOJFKUA 0707 123Y12A 00001100",
+            ExpectedBoardingPass{.origin = "SFO",
+                                 .destination = "JFK",
+                                 .airline = "UA",
+                                 .flight_code = "707",
+                                 .date = "123"});
+  TestValue("M1PASSENGER NAME      EABCDEFGSFOJFKUA 0000 123Y12A 00001100",
+            ExpectedBoardingPass{.origin = "SFO",
+                                 .destination = "JFK",
+                                 .airline = "UA",
+                                 .flight_code = "0",
+                                 .date = "123"});
+}
+
 }  // namespace wallet
diff --git a/components/webdata/common/web_data_results.h b/components/webdata/common/web_data_results.h
index 231787c4..2050a6bb 100644
--- a/components/webdata/common/web_data_results.h
+++ b/components/webdata/common/web_data_results.h
@@ -52,6 +52,7 @@
                                      //     sync_pb::PaymentInstrument>>
   PAYMENT_INSTRUMENT_CREATION_OPTION_RESULT,  // WDResult<std::vector<
                                               //     sync_pb::PaymentInstrumentCreationOption>>
+  WRAPPED_BINDING_KEYS_RESULT,  // WDResult<absl::flat_hash_set<std::vector<uint8_t>>>
 #if BUILDFLAG(USE_BLINK)  //
   // The browser bound key id is retrieved by the payments component
   // during secure payment confirmation requests and payment credential
diff --git a/components/webui/regional_capabilities_internals/constants.cc b/components/webui/regional_capabilities_internals/constants.cc
index 0a771ff..ca0524d 100644
--- a/components/webui/regional_capabilities_internals/constants.cc
+++ b/components/webui/regional_capabilities_internals/constants.cc
@@ -10,5 +10,7 @@
 const char kActiveProgramNameKey[] = "activeProgramName";
 const char kActiveCountryCodeKey[] = "activeCountryCode";
 const char kPrefsCountryCodeKey[] = "prefsCountryCode";
+const char kDeviceDeterminedProgramKey[] = "deviceDeterminedProgram";
+const char kExternalChoiceKeywordKey[] = "externalChoiceKeyword";
 
 }  // namespace regional_capabilities
diff --git a/components/webui/regional_capabilities_internals/constants.h b/components/webui/regional_capabilities_internals/constants.h
index a39ac414..a1b7439 100644
--- a/components/webui/regional_capabilities_internals/constants.h
+++ b/components/webui/regional_capabilities_internals/constants.h
@@ -14,6 +14,8 @@
 extern const char kActiveProgramNameKey[];
 extern const char kActiveCountryCodeKey[];
 extern const char kPrefsCountryCodeKey[];
+extern const char kDeviceDeterminedProgramKey[];
+extern const char kExternalChoiceKeywordKey[];
 
 }  // namespace regional_capabilities
 
diff --git a/components/webui/regional_capabilities_internals/resources/app.ts b/components/webui/regional_capabilities_internals/resources/app.ts
index 3c244ae..11cbf8c6 100644
--- a/components/webui/regional_capabilities_internals/resources/app.ts
+++ b/components/webui/regional_capabilities_internals/resources/app.ts
@@ -24,16 +24,22 @@
   return tr;
 }
 
+function appendRow(
+    tableElement: HTMLElement, headerName: string, dataKey: string) {
+  if (loadTimeData.valueExists(dataKey)) {
+    tableElement.appendChild(buildTableRow(headerName, dataKey));
+  }
+}
 
 /* All the work we do onload. */
 function initialize() {
-  const tableElement = getRequiredElement('data-table');
-  tableElement.textContent = '';
-  tableElement.appendChild(
-      buildTableRow('Active Program', 'activeProgramName'));
-  tableElement.appendChild(
-      buildTableRow('Active Country', 'activeCountryCode'));
-  tableElement.appendChild(
-      buildTableRow('Country in prefs', 'prefsCountryCode'));
+  const tableEl = getRequiredElement('data-table');
+  tableEl.textContent = '';
+
+  appendRow(tableEl, 'Active Program', 'activeProgramName');
+  appendRow(tableEl, 'Device Determined Program', 'deviceDeterminedProgram');
+  appendRow(tableEl, 'Active Country', 'activeCountryCode');
+  appendRow(tableEl, 'Country in prefs', 'prefsCountryCode');
+  appendRow(tableEl, 'External Choice', 'externalChoiceKeyword');
 }
 document.addEventListener('DOMContentLoaded', initialize);
diff --git a/content/browser/media/capture/pip_screen_capture_coordinator.cc b/content/browser/media/capture/pip_screen_capture_coordinator.cc
index 120d4443..ae988e2 100644
--- a/content/browser/media/capture/pip_screen_capture_coordinator.cc
+++ b/content/browser/media/capture/pip_screen_capture_coordinator.cc
@@ -40,7 +40,8 @@
 void PipScreenCaptureCoordinator::OnPipShown(WebContents& pip_web_contents) {
 #if BUILDFLAG(IS_MAC)
   if (auto* instance = PipScreenCaptureCoordinatorImpl::GetInstance()) {
-    instance->OnPipShown(pip_web_contents);
+    instance->OnPipShown(pip_web_contents,
+                         GetWebContents().GetPrimaryMainFrame()->GetGlobalId());
   }
 #endif
 }
diff --git a/content/browser/media/capture/pip_screen_capture_coordinator_impl.cc b/content/browser/media/capture/pip_screen_capture_coordinator_impl.cc
index 82dbf37..1d388bd0 100644
--- a/content/browser/media/capture/pip_screen_capture_coordinator_impl.cc
+++ b/content/browser/media/capture/pip_screen_capture_coordinator_impl.cc
@@ -9,6 +9,7 @@
 #include "build/build_config.h"
 #include "content/browser/media/capture/pip_screen_capture_coordinator_proxy_impl.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "media/capture/capture_switches.h"
 
@@ -60,24 +61,26 @@
 PipScreenCaptureCoordinatorImpl::~PipScreenCaptureCoordinatorImpl() = default;
 
 void PipScreenCaptureCoordinatorImpl::OnPipShown(
-    WebContents& pip_web_contents) {
+    WebContents& pip_web_contents,
+    const GlobalRenderFrameHostId& new_pip_owner_render_frame_host_id) {
   std::optional<NativeWindowId> new_pip_window_id;
   new_pip_window_id = GetNativeWindowIdMac(pip_web_contents);
   if (new_pip_window_id) {
-    OnPipShown(*new_pip_window_id);
+    OnPipShown(*new_pip_window_id, new_pip_owner_render_frame_host_id);
   }
 }
 
 void PipScreenCaptureCoordinatorImpl::OnPipShown(
-    NativeWindowId new_pip_window_id) {
-  if (pip_window_id_ == new_pip_window_id) {
+    NativeWindowId new_pip_window_id,
+    const GlobalRenderFrameHostId& new_pip_owner_render_frame_host_id) {
+  if (pip_window_id_ == new_pip_window_id &&
+      pip_owner_render_frame_host_id_ == new_pip_owner_render_frame_host_id) {
     return;
   }
 
   pip_window_id_ = new_pip_window_id;
-  for (Observer& obs : observers_) {
-    obs.OnPipWindowIdChanged(pip_window_id_);
-  }
+  pip_owner_render_frame_host_id_ = new_pip_owner_render_frame_host_id;
+  NotifyStateChanged();
 }
 
 void PipScreenCaptureCoordinatorImpl::OnPipClosed() {
@@ -85,9 +88,8 @@
     return;
   }
   pip_window_id_ = std::nullopt;
-  for (Observer& obs : observers_) {
-    obs.OnPipWindowIdChanged(pip_window_id_);
-  }
+  pip_owner_render_frame_host_id_ = {};
+  NotifyStateChanged();
 }
 
 std::optional<NativeWindowId> PipScreenCaptureCoordinatorImpl::PipWindowId()
@@ -95,6 +97,11 @@
   return pip_window_id_;
 }
 
+GlobalRenderFrameHostId
+PipScreenCaptureCoordinatorImpl::GetPipOwnerRenderFrameHostId() const {
+  return pip_owner_render_frame_host_id_;
+}
+
 std::vector<PipScreenCaptureCoordinatorProxy::CaptureInfo>
 PipScreenCaptureCoordinatorImpl::Captures() const {
   return captures_;
@@ -103,9 +110,7 @@
 void PipScreenCaptureCoordinatorImpl::AddCaptureOnUIThread(
     PipScreenCaptureCoordinatorProxy::CaptureInfo capture_info) {
   captures_.push_back(std::move(capture_info));
-  for (Observer& obs : observers_) {
-    obs.OnCapturesChanged(captures_);
-  }
+  NotifyStateChanged();
 }
 
 void PipScreenCaptureCoordinatorImpl::RemoveCaptureOnUIThread(
@@ -115,15 +120,21 @@
                                    return c.session_id == session_id;
                                  }),
                   captures_.end());
+  NotifyStateChanged();
+}
+
+void PipScreenCaptureCoordinatorImpl::NotifyStateChanged() {
   for (Observer& obs : observers_) {
-    obs.OnCapturesChanged(captures_);
+    obs.OnStateChanged(pip_window_id_, pip_owner_render_frame_host_id_,
+                       captures_);
   }
 }
 
 std::unique_ptr<PipScreenCaptureCoordinatorProxy>
 PipScreenCaptureCoordinatorImpl::CreateProxy() {
   return std::make_unique<PipScreenCaptureCoordinatorProxyImpl>(
-      weak_factory_.GetWeakPtr(), PipWindowId(), captures_);
+      weak_factory_.GetWeakPtr(), PipWindowId(), GetPipOwnerRenderFrameHostId(),
+      captures_);
 }
 
 void PipScreenCaptureCoordinatorImpl::AddObserver(Observer* observer) {
@@ -136,6 +147,7 @@
 
 void PipScreenCaptureCoordinatorImpl::ResetForTesting() {
   pip_window_id_ = std::nullopt;
+  pip_owner_render_frame_host_id_ = {};
   observers_.Clear();
   captures_.clear();
   weak_factory_.InvalidateWeakPtrs();
diff --git a/content/browser/media/capture/pip_screen_capture_coordinator_impl.h b/content/browser/media/capture/pip_screen_capture_coordinator_impl.h
index 597aa41de..9f858bcd 100644
--- a/content/browser/media/capture/pip_screen_capture_coordinator_impl.h
+++ b/content/browser/media/capture/pip_screen_capture_coordinator_impl.h
@@ -27,12 +27,10 @@
 
   class Observer : public base::CheckedObserver {
    public:
-    // Called with the NativeWindowId of the PiP window when it is
-    // shown, or nullopt when it is closed.
-    virtual void OnPipWindowIdChanged(
-        std::optional<NativeWindowId> new_pip_window_id) = 0;
-    // Called when the list of captures changes.
-    virtual void OnCapturesChanged(
+    // Called when the state of the coordinator changes.
+    virtual void OnStateChanged(
+        std::optional<NativeWindowId> new_pip_window_id,
+        const GlobalRenderFrameHostId& new_pip_owner_render_frame_host_id,
         const std::vector<PipScreenCaptureCoordinatorProxy::CaptureInfo>&
             captures) = 0;
   };
@@ -44,11 +42,16 @@
   PipScreenCaptureCoordinatorImpl& operator=(
       const PipScreenCaptureCoordinatorImpl&) = delete;
 
-  void OnPipShown(WebContents& pip_web_contents);
-  void OnPipShown(NativeWindowId pip_window_id);
+  void OnPipShown(
+      WebContents& pip_web_contents,
+      const GlobalRenderFrameHostId& pip_owner_render_frame_host_id);
+  void OnPipShown(
+      NativeWindowId pip_window_id,
+      const GlobalRenderFrameHostId& pip_owner_render_frame_host_id);
   void OnPipClosed();
 
   std::optional<NativeWindowId> PipWindowId() const;
+  GlobalRenderFrameHostId GetPipOwnerRenderFrameHostId() const;
   std::vector<PipScreenCaptureCoordinatorProxy::CaptureInfo> Captures() const;
 
   std::unique_ptr<PipScreenCaptureCoordinatorProxy> CreateProxy();
@@ -62,10 +65,12 @@
   void AddCaptureOnUIThread(
       PipScreenCaptureCoordinatorProxy::CaptureInfo capture_info);
   void RemoveCaptureOnUIThread(const base::UnguessableToken& session_id);
+  void NotifyStateChanged();
   friend class base::NoDestructor<PipScreenCaptureCoordinatorImpl>;
   PipScreenCaptureCoordinatorImpl();
 
   std::optional<NativeWindowId> pip_window_id_;
+  GlobalRenderFrameHostId pip_owner_render_frame_host_id_;
   base::ObserverList<Observer> observers_;
   std::vector<PipScreenCaptureCoordinatorProxy::CaptureInfo> captures_;
   base::WeakPtrFactory<PipScreenCaptureCoordinatorImpl> weak_factory_{this};
diff --git a/content/browser/media/capture/pip_screen_capture_coordinator_impl_unittest.cc b/content/browser/media/capture/pip_screen_capture_coordinator_impl_unittest.cc
index fdc305e..4b8c9ae 100644
--- a/content/browser/media/capture/pip_screen_capture_coordinator_impl_unittest.cc
+++ b/content/browser/media/capture/pip_screen_capture_coordinator_impl_unittest.cc
@@ -27,14 +27,12 @@
   MockObserver() = default;
   ~MockObserver() override = default;
 
-  MOCK_METHOD(void,
-              OnPipWindowIdChanged,
-              (std::optional<NativeWindowId>),
-              (override));
   MOCK_METHOD(
       void,
-      OnCapturesChanged,
-      (const std::vector<PipScreenCaptureCoordinatorProxy::CaptureInfo>&),
+      OnStateChanged,
+      (std::optional<NativeWindowId>,
+       const GlobalRenderFrameHostId&,
+       const std::vector<PipScreenCaptureCoordinatorProxy::CaptureInfo>&),
       (override));
 };
 
@@ -43,31 +41,32 @@
   MockProxyObserver() = default;
   ~MockProxyObserver() override = default;
 
-  MOCK_METHOD(void,
-              OnPipWindowIdChanged,
-              (const std::optional<NativeWindowId>&),
-              (override));
   MOCK_METHOD(
       void,
-      OnCapturesChanged,
-      (const std::vector<PipScreenCaptureCoordinatorProxy::CaptureInfo>&),
+      OnStateChanged,
+      ((const std::optional<NativeWindowId>&),
+       (const GlobalRenderFrameHostId&),
+       (const std::vector<PipScreenCaptureCoordinatorProxy::CaptureInfo>&)),
       (override));
 };
 
 void CallOnPipShownAndWaitUntilDone(
     content::BrowserTaskEnvironment& task_environment,
     PipScreenCaptureCoordinatorImpl* coordinator,
-    NativeWindowId window_id) {
+    NativeWindowId window_id,
+    const GlobalRenderFrameHostId& owner_id) {
   base::RunLoop run_loop;
   task_environment.GetMainThreadTaskRunner()->PostTask(
       FROM_HERE,
       base::BindOnce(
           [](PipScreenCaptureCoordinatorImpl* coordinator,
-             NativeWindowId window_id, base::OnceClosure quit_closure) {
-            coordinator->OnPipShown(window_id);
+             NativeWindowId window_id, const GlobalRenderFrameHostId& owner_id,
+             base::OnceClosure quit_closure) {
+            coordinator->OnPipShown(window_id, owner_id);
             std::move(quit_closure).Run();
           },
-          base::Unretained(coordinator), window_id, run_loop.QuitClosure()));
+          base::Unretained(coordinator), window_id, owner_id,
+          run_loop.QuitClosure()));
   run_loop.Run();
 }
 
@@ -76,8 +75,10 @@
     PipScreenCaptureCoordinatorImpl* coordinator,
     MockProxyObserver& observer) {
   base::RunLoop run_loop;
-  EXPECT_CALL(observer, OnPipWindowIdChanged(std::optional<NativeWindowId>()))
-      .WillOnce([&run_loop](const auto&) { run_loop.Quit(); });
+  EXPECT_CALL(observer, OnStateChanged(std::optional<NativeWindowId>(), _, _))
+      .WillOnce([&run_loop](const auto&, const auto&, const auto&) {
+        run_loop.Quit();
+      });
   task_environment.GetMainThreadTaskRunner()->PostTask(
       FROM_HERE, base::BindOnce(
                      [](PipScreenCaptureCoordinatorImpl* coordinator) {
@@ -91,16 +92,22 @@
     content::BrowserTaskEnvironment& task_environment,
     PipScreenCaptureCoordinatorImpl* coordinator,
     MockProxyObserver& observer,
-    const std::optional<NativeWindowId>& new_pip_window_id) {
+    const std::optional<NativeWindowId>& new_pip_window_id,
+    const GlobalRenderFrameHostId& new_pip_owner_id) {
   base::RunLoop run_loop;
-  EXPECT_CALL(observer, OnPipWindowIdChanged(new_pip_window_id))
-      .WillOnce([&run_loop](const auto&) { run_loop.Quit(); });
+  EXPECT_CALL(observer, OnStateChanged(new_pip_window_id, new_pip_owner_id, _))
+      .WillOnce([&run_loop](const auto&, const auto&, const auto&) {
+        run_loop.Quit();
+      });
   task_environment.GetMainThreadTaskRunner()->PostTask(
       FROM_HERE,
       base::BindOnce(
           [](PipScreenCaptureCoordinatorImpl* coordinator,
-             NativeWindowId window_id) { coordinator->OnPipShown(window_id); },
-          base::Unretained(coordinator), *new_pip_window_id));
+             NativeWindowId window_id,
+             const GlobalRenderFrameHostId& owner_id) {
+            coordinator->OnPipShown(window_id, owner_id);
+          },
+          base::Unretained(coordinator), *new_pip_window_id, new_pip_owner_id));
   run_loop.Run();
 }
 
@@ -121,15 +128,21 @@
   raw_ptr<PipScreenCaptureCoordinatorImpl> coordinator_;
 };
 
-TEST_F(PipScreenCaptureCoordinatorImplTest, PipWindowId) {
+TEST_F(PipScreenCaptureCoordinatorImplTest, PipStateAccessors) {
   EXPECT_EQ(coordinator_->PipWindowId(), std::nullopt);
+  EXPECT_EQ(coordinator_->GetPipOwnerRenderFrameHostId(),
+            GlobalRenderFrameHostId());
 
   const NativeWindowId pip_window_id = 123;
-  coordinator_->OnPipShown(pip_window_id);
+  const GlobalRenderFrameHostId pip_owner_id(1, 1);
+  coordinator_->OnPipShown(pip_window_id, pip_owner_id);
   EXPECT_EQ(coordinator_->PipWindowId(), pip_window_id);
+  EXPECT_EQ(coordinator_->GetPipOwnerRenderFrameHostId(), pip_owner_id);
 
   coordinator_->OnPipClosed();
   EXPECT_EQ(coordinator_->PipWindowId(), std::nullopt);
+  EXPECT_EQ(coordinator_->GetPipOwnerRenderFrameHostId(),
+            GlobalRenderFrameHostId());
 }
 
 TEST_F(PipScreenCaptureCoordinatorImplTest, OnPipShownNotifiesObservers) {
@@ -137,15 +150,16 @@
   coordinator_->AddObserver(&observer);
 
   const NativeWindowId pip_window_id = 123;
-  EXPECT_CALL(observer,
-              OnPipWindowIdChanged(std::make_optional(pip_window_id)));
-  coordinator_->OnPipShown(pip_window_id);
+  const GlobalRenderFrameHostId pip_owner_id(1, 1);
+  EXPECT_CALL(observer, OnStateChanged(std::make_optional(pip_window_id),
+                                       pip_owner_id, _));
+  coordinator_->OnPipShown(pip_window_id, pip_owner_id);
 
   EXPECT_EQ(coordinator_->PipWindowId(), pip_window_id);
 
   // Calling again with the same ID should not notify.
-  EXPECT_CALL(observer, OnPipWindowIdChanged(_)).Times(0);
-  coordinator_->OnPipShown(pip_window_id);
+  EXPECT_CALL(observer, OnStateChanged(_, _, _)).Times(0);
+  coordinator_->OnPipShown(pip_window_id, pip_owner_id);
 
   coordinator_->RemoveObserver(&observer);
 }
@@ -155,12 +169,14 @@
   coordinator_->AddObserver(&observer);
 
   const NativeWindowId pip_window_id = 123;
-  EXPECT_CALL(observer,
-              OnPipWindowIdChanged(std::make_optional(pip_window_id)));
-  coordinator_->OnPipShown(pip_window_id);
+  const GlobalRenderFrameHostId pip_owner_id(1, 1);
+  EXPECT_CALL(observer, OnStateChanged(std::make_optional(pip_window_id),
+                                       pip_owner_id, _));
+  coordinator_->OnPipShown(pip_window_id, pip_owner_id);
   testing::Mock::VerifyAndClearExpectations(&observer);
 
-  EXPECT_CALL(observer, OnPipWindowIdChanged(testing::Eq(std::nullopt)));
+  EXPECT_CALL(observer, OnStateChanged(testing::Eq(std::nullopt),
+                                       GlobalRenderFrameHostId(), _));
   coordinator_->OnPipClosed();
 
   coordinator_->RemoveObserver(&observer);
@@ -174,21 +190,23 @@
   coordinator_->AddObserver(&observer2);
 
   const NativeWindowId pip_window_id = 123;
-  EXPECT_CALL(observer1,
-              OnPipWindowIdChanged(std::make_optional(pip_window_id)));
-  EXPECT_CALL(observer2,
-              OnPipWindowIdChanged(std::make_optional(pip_window_id)));
-  coordinator_->OnPipShown(pip_window_id);
+  const GlobalRenderFrameHostId pip_owner_id(1, 1);
+  EXPECT_CALL(observer1, OnStateChanged(std::make_optional(pip_window_id),
+                                        pip_owner_id, _));
+  EXPECT_CALL(observer2, OnStateChanged(std::make_optional(pip_window_id),
+                                        pip_owner_id, _));
+  coordinator_->OnPipShown(pip_window_id, pip_owner_id);
   testing::Mock::VerifyAndClearExpectations(&observer1);
   testing::Mock::VerifyAndClearExpectations(&observer2);
 
   coordinator_->RemoveObserver(&observer1);
 
   const NativeWindowId new_pip_window_id = 456;
-  EXPECT_CALL(observer1, OnPipWindowIdChanged(_)).Times(0);
-  EXPECT_CALL(observer2,
-              OnPipWindowIdChanged(std::make_optional(new_pip_window_id)));
-  coordinator_->OnPipShown(new_pip_window_id);
+  const GlobalRenderFrameHostId new_pip_owner_id(2, 2);
+  EXPECT_CALL(observer1, OnStateChanged(_, _, _)).Times(0);
+  EXPECT_CALL(observer2, OnStateChanged(std::make_optional(new_pip_window_id),
+                                        new_pip_owner_id, _));
+  coordinator_->OnPipShown(new_pip_window_id, new_pip_owner_id);
 
   coordinator_->RemoveObserver(&observer2);
 }
@@ -196,8 +214,9 @@
 TEST_F(PipScreenCaptureCoordinatorImplTest, CreateProxy) {
   // The proxy should start with the current ID.
   const NativeWindowId pip_window_id = 123;
-  CallOnPipShownAndWaitUntilDone(task_environment_, coordinator_,
-                                 pip_window_id);
+  const GlobalRenderFrameHostId pip_owner_id(1, 1);
+  CallOnPipShownAndWaitUntilDone(task_environment_, coordinator_, pip_window_id,
+                                 pip_owner_id);
   auto proxy = coordinator_->CreateProxy();
   ASSERT_TRUE(proxy);
 
@@ -205,16 +224,20 @@
   MockProxyObserver observer;
   proxy->AddObserver(&observer);
   EXPECT_EQ(proxy->PipWindowId(), pip_window_id);
+  EXPECT_EQ(proxy->GetPipOwnerRenderFrameHostId(), pip_owner_id);
 
   // The proxy should be updated when the ID changes.
   const std::optional<NativeWindowId> new_pip_window_id = 456;
+  const GlobalRenderFrameHostId new_pip_owner_id(2, 2);
   CallOnPipShownAndWaitForObserver(task_environment_, coordinator_, observer,
-                                   new_pip_window_id);
+                                   new_pip_window_id, new_pip_owner_id);
   EXPECT_EQ(proxy->PipWindowId(), new_pip_window_id);
+  EXPECT_EQ(proxy->GetPipOwnerRenderFrameHostId(), new_pip_owner_id);
 
   // The proxy should be updated when the pip window is closed.
   CallOnPipClosedAndWaitForObserver(task_environment_, coordinator_, observer);
   EXPECT_EQ(proxy->PipWindowId(), std::nullopt);
+  EXPECT_EQ(proxy->GetPipOwnerRenderFrameHostId(), GlobalRenderFrameHostId());
 
   proxy->RemoveObserver(&observer);
 }
@@ -233,8 +256,9 @@
           .render_frame_host_id = render_frame_host_id,
           .desktop_media_id = desktop_media_id};
 
-  EXPECT_CALL(observer, OnCapturesChanged(testing::ElementsAre(
-                            testing::Eq(std::ref(expected_capture_info)))));
+  EXPECT_CALL(observer, OnStateChanged(_, _,
+                                       testing::ElementsAre(testing::Eq(
+                                           std::ref(expected_capture_info)))));
   coordinator_->AddCapture(expected_capture_info);
 
   coordinator_->RemoveObserver(&observer);
@@ -254,11 +278,11 @@
           .render_frame_host_id = render_frame_host_id,
           .desktop_media_id = desktop_media_id};
 
-  EXPECT_CALL(observer, OnCapturesChanged(_)).Times(1);
+  EXPECT_CALL(observer, OnStateChanged(_, _, _)).Times(1);
   coordinator_->AddCapture(expected_capture_info);
   testing::Mock::VerifyAndClearExpectations(&observer);
 
-  EXPECT_CALL(observer, OnCapturesChanged(testing::IsEmpty()));
+  EXPECT_CALL(observer, OnStateChanged(_, _, testing::IsEmpty()));
   coordinator_->RemoveCapture(session_id);
 
   coordinator_->RemoveObserver(&observer);
@@ -288,23 +312,28 @@
           .render_frame_host_id = render_frame_host_id2,
           .desktop_media_id = desktop_media_id2};
 
-  EXPECT_CALL(observer, OnCapturesChanged(testing::ElementsAre(
-                            testing::Eq(std::ref(expected_capture_info1)))));
+  EXPECT_CALL(observer, OnStateChanged(_, _,
+                                       testing::ElementsAre(testing::Eq(
+                                           std::ref(expected_capture_info1)))));
   coordinator_->AddCapture(expected_capture_info1);
   testing::Mock::VerifyAndClearExpectations(&observer);
 
-  EXPECT_CALL(observer, OnCapturesChanged(testing::UnorderedElementsAre(
-                            testing::Eq(std::ref(expected_capture_info1)),
-                            testing::Eq(std::ref(expected_capture_info2)))));
+  EXPECT_CALL(
+      observer,
+      OnStateChanged(_, _,
+                     testing::UnorderedElementsAre(
+                         testing::Eq(std::ref(expected_capture_info1)),
+                         testing::Eq(std::ref(expected_capture_info2)))));
   coordinator_->AddCapture(expected_capture_info2);
   testing::Mock::VerifyAndClearExpectations(&observer);
 
-  EXPECT_CALL(observer, OnCapturesChanged(testing::ElementsAre(
-                            testing::Eq(std::ref(expected_capture_info2)))));
+  EXPECT_CALL(observer, OnStateChanged(_, _,
+                                       testing::ElementsAre(testing::Eq(
+                                           std::ref(expected_capture_info2)))));
   coordinator_->RemoveCapture(session_id1);
   testing::Mock::VerifyAndClearExpectations(&observer);
 
-  EXPECT_CALL(observer, OnCapturesChanged(testing::IsEmpty()));
+  EXPECT_CALL(observer, OnStateChanged(_, _, testing::IsEmpty()));
   coordinator_->RemoveCapture(session_id2);
 
   coordinator_->RemoveObserver(&observer);
@@ -339,36 +368,51 @@
 
   {
     base::RunLoop run_loop;
-    EXPECT_CALL(observer, OnCapturesChanged(testing::ElementsAre(
-                              testing::Eq(std::ref(expected_capture_info1)))))
-        .WillOnce([&run_loop](const auto&) { run_loop.Quit(); });
+    EXPECT_CALL(observer,
+                OnStateChanged(_, _,
+                               testing::ElementsAre(testing::Eq(
+                                   std::ref(expected_capture_info1)))))
+        .WillOnce([&run_loop](const auto&, const auto&, const auto&) {
+          run_loop.Quit();
+        });
     PipScreenCaptureCoordinatorImpl::AddCapture(expected_capture_info1);
     run_loop.Run();
   }
 
   {
     base::RunLoop run_loop;
-    EXPECT_CALL(observer, OnCapturesChanged(testing::UnorderedElementsAre(
-                              testing::Eq(std::ref(expected_capture_info1)),
-                              testing::Eq(std::ref(expected_capture_info2)))))
-        .WillOnce([&run_loop](const auto&) { run_loop.Quit(); });
+    EXPECT_CALL(
+        observer,
+        OnStateChanged(_, _,
+                       testing::UnorderedElementsAre(
+                           testing::Eq(std::ref(expected_capture_info1)),
+                           testing::Eq(std::ref(expected_capture_info2)))))
+        .WillOnce([&run_loop](const auto&, const auto&, const auto&) {
+          run_loop.Quit();
+        });
     PipScreenCaptureCoordinatorImpl::AddCapture(expected_capture_info2);
     run_loop.Run();
   }
 
   {
     base::RunLoop run_loop;
-    EXPECT_CALL(observer, OnCapturesChanged(testing::ElementsAre(
-                              testing::Eq(std::ref(expected_capture_info2)))))
-        .WillOnce([&run_loop](const auto&) { run_loop.Quit(); });
+    EXPECT_CALL(observer,
+                OnStateChanged(_, _,
+                               testing::ElementsAre(testing::Eq(
+                                   std::ref(expected_capture_info2)))))
+        .WillOnce([&run_loop](const auto&, const auto&, const auto&) {
+          run_loop.Quit();
+        });
     PipScreenCaptureCoordinatorImpl::RemoveCapture(session_id1);
     run_loop.Run();
   }
 
   {
     base::RunLoop run_loop;
-    EXPECT_CALL(observer, OnCapturesChanged(testing::IsEmpty()))
-        .WillOnce([&run_loop](const auto&) { run_loop.Quit(); });
+    EXPECT_CALL(observer, OnStateChanged(_, _, testing::IsEmpty()))
+        .WillOnce([&run_loop](const auto&, const auto&, const auto&) {
+          run_loop.Quit();
+        });
     PipScreenCaptureCoordinatorImpl::RemoveCapture(session_id2);
     run_loop.Run();
   }
diff --git a/content/browser/media/capture/pip_screen_capture_coordinator_proxy.h b/content/browser/media/capture/pip_screen_capture_coordinator_proxy.h
index f99c103b..5b9a237 100644
--- a/content/browser/media/capture/pip_screen_capture_coordinator_proxy.h
+++ b/content/browser/media/capture/pip_screen_capture_coordinator_proxy.h
@@ -33,9 +33,9 @@
 
   class Observer : public base::CheckedObserver {
    public:
-    virtual void OnPipWindowIdChanged(
-        const std::optional<NativeWindowId>& new_pip_window_id) = 0;
-    virtual void OnCapturesChanged(
+    virtual void OnStateChanged(
+        const std::optional<NativeWindowId>& new_pip_window_id,
+        const GlobalRenderFrameHostId& new_pip_owner_render_frame_host_id,
         const std::vector<CaptureInfo>& captures) = 0;
   };
 
@@ -43,6 +43,7 @@
 
   // Returns the tracked PiP window ID.
   virtual std::optional<NativeWindowId> PipWindowId() const = 0;
+  virtual GlobalRenderFrameHostId GetPipOwnerRenderFrameHostId() const = 0;
   virtual const std::vector<CaptureInfo>& Captures() const = 0;
 
   virtual void AddObserver(Observer* observer) = 0;
diff --git a/content/browser/media/capture/pip_screen_capture_coordinator_proxy_impl.cc b/content/browser/media/capture/pip_screen_capture_coordinator_proxy_impl.cc
index 67dd48cc..9614cdd 100644
--- a/content/browser/media/capture/pip_screen_capture_coordinator_proxy_impl.cc
+++ b/content/browser/media/capture/pip_screen_capture_coordinator_proxy_impl.cc
@@ -36,29 +36,24 @@
       coordinator_->AddObserver(this);
 
       // Update the proxy with the latest state
-      OnPipWindowIdChanged(coordinator_->PipWindowId());
-      OnCapturesChanged(coordinator_->Captures());
+      OnStateChanged(coordinator_->PipWindowId(),
+                     coordinator_->GetPipOwnerRenderFrameHostId(),
+                     coordinator_->Captures());
     }
   }
 
   // PipScreenCaptureCoordinatorImpl::Observer:
-  void OnPipWindowIdChanged(
-      std::optional<NativeWindowId> new_pip_window_id) override {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(ui_thread_sequence_checker_);
-    proxy_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&PipScreenCaptureCoordinatorProxyImpl::SetPipWindowId,
-                       proxy_, new_pip_window_id));
-  }
-
-  void OnCapturesChanged(
+  void OnStateChanged(
+      std::optional<NativeWindowId> new_pip_window_id,
+      const GlobalRenderFrameHostId& new_pip_owner_render_frame_host_id,
       const std::vector<PipScreenCaptureCoordinatorProxy::CaptureInfo>&
           captures) override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(ui_thread_sequence_checker_);
     proxy_task_runner_->PostTask(
         FROM_HERE,
-        base::BindOnce(&PipScreenCaptureCoordinatorProxyImpl::SetCaptures,
-                       proxy_, captures));
+        base::BindOnce(&PipScreenCaptureCoordinatorProxyImpl::UpdateState,
+                       proxy_, new_pip_window_id,
+                       new_pip_owner_render_frame_host_id, captures));
   }
 
  private:
@@ -71,9 +66,11 @@
 PipScreenCaptureCoordinatorProxyImpl::PipScreenCaptureCoordinatorProxyImpl(
     base::WeakPtr<PipScreenCaptureCoordinatorImpl> coordinator,
     std::optional<NativeWindowId> initial_pip_window_id,
+    GlobalRenderFrameHostId initial_pip_owner_render_frame_host_id,
     const std::vector<CaptureInfo>& initial_captures)
     : coordinator_(std::move(coordinator)),
       pip_window_id_(initial_pip_window_id),
+      pip_owner_render_frame_host_id_(initial_pip_owner_render_frame_host_id),
       captures_(initial_captures),
       ui_thread_observer_(
           nullptr,
@@ -95,6 +92,12 @@
   return pip_window_id_;
 }
 
+GlobalRenderFrameHostId
+PipScreenCaptureCoordinatorProxyImpl::GetPipOwnerRenderFrameHostId() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return pip_owner_render_frame_host_id_;
+}
+
 const std::vector<PipScreenCaptureCoordinatorProxy::CaptureInfo>&
 PipScreenCaptureCoordinatorProxyImpl::Captures() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -136,27 +139,22 @@
   }
 }
 
-void PipScreenCaptureCoordinatorProxyImpl::SetPipWindowId(
-    const std::optional<NativeWindowId>& new_pip_window_id) {
+void PipScreenCaptureCoordinatorProxyImpl::UpdateState(
+    const std::optional<NativeWindowId>& new_pip_window_id,
+    const GlobalRenderFrameHostId& new_pip_owner_render_frame_host_id,
+    const std::vector<CaptureInfo>& new_captures) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (pip_window_id_ == new_pip_window_id) {
+  if (pip_window_id_ == new_pip_window_id &&
+      pip_owner_render_frame_host_id_ == new_pip_owner_render_frame_host_id &&
+      captures_ == new_captures) {
     return;
   }
   pip_window_id_ = new_pip_window_id;
+  pip_owner_render_frame_host_id_ = new_pip_owner_render_frame_host_id;
+  captures_ = new_captures;
   for (Observer& obs : observers_) {
-    obs.OnPipWindowIdChanged(pip_window_id_);
-  }
-}
-
-void PipScreenCaptureCoordinatorProxyImpl::SetCaptures(
-    const std::vector<CaptureInfo>& captures) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (captures_ == captures) {
-    return;
-  }
-  captures_ = captures;
-  for (Observer& obs : observers_) {
-    obs.OnCapturesChanged(captures_);
+    obs.OnStateChanged(pip_window_id_, pip_owner_render_frame_host_id_,
+                       captures_);
   }
 }
 
diff --git a/content/browser/media/capture/pip_screen_capture_coordinator_proxy_impl.h b/content/browser/media/capture/pip_screen_capture_coordinator_proxy_impl.h
index d1778036..ed158d9 100644
--- a/content/browser/media/capture/pip_screen_capture_coordinator_proxy_impl.h
+++ b/content/browser/media/capture/pip_screen_capture_coordinator_proxy_impl.h
@@ -21,11 +21,13 @@
   PipScreenCaptureCoordinatorProxyImpl(
       base::WeakPtr<PipScreenCaptureCoordinatorImpl> coordinator,
       std::optional<NativeWindowId> initial_pip_window_id,
+      GlobalRenderFrameHostId initial_pip_owner_render_frame_host_id,
       const std::vector<CaptureInfo>& initial_captures);
 
   ~PipScreenCaptureCoordinatorProxyImpl() override;
 
   std::optional<NativeWindowId> PipWindowId() const override;
+  GlobalRenderFrameHostId GetPipOwnerRenderFrameHostId() const override;
   const std::vector<CaptureInfo>& Captures() const override;
 
   void AddObserver(Observer* observer) override;
@@ -35,13 +37,17 @@
   class UiThreadObserver;
   friend class UiThreadObserver;
 
-  void SetPipWindowId(const std::optional<NativeWindowId>& new_pip_window_id);
-  void SetCaptures(const std::vector<CaptureInfo>& captures);
+  void UpdateState(
+      const std::optional<NativeWindowId>& new_pip_window_id,
+      const GlobalRenderFrameHostId& new_pip_owner_render_frame_host_id,
+      const std::vector<CaptureInfo>& new_captures);
 
   base::WeakPtr<PipScreenCaptureCoordinatorImpl> coordinator_
       GUARDED_BY_CONTEXT(sequence_checker_);
   std::optional<NativeWindowId> pip_window_id_
       GUARDED_BY_CONTEXT(sequence_checker_);
+  GlobalRenderFrameHostId pip_owner_render_frame_host_id_
+      GUARDED_BY_CONTEXT(sequence_checker_);
   std::vector<CaptureInfo> captures_ GUARDED_BY_CONTEXT(sequence_checker_);
   scoped_refptr<base::SequencedTaskRunner> bound_sequence_task_runner_
       GUARDED_BY_CONTEXT(sequence_checker_);
diff --git a/content/browser/media/capture/screen_capture_kit_device_mac.mm b/content/browser/media/capture/screen_capture_kit_device_mac.mm
index db54df43..9b666086 100644
--- a/content/browser/media/capture/screen_capture_kit_device_mac.mm
+++ b/content/browser/media/capture/screen_capture_kit_device_mac.mm
@@ -585,8 +585,11 @@
   }
 
   // PipScreenCaptureCoordinatorProxy::Observer:
-  void OnPipWindowIdChanged(
-      const std::optional<NativeWindowId>& new_pip_window_id) override {
+  void OnStateChanged(
+      const std::optional<NativeWindowId>& new_pip_window_id,
+      const GlobalRenderFrameHostId& new_pip_owner_render_frame_host_id,
+      const std::vector<PipScreenCaptureCoordinatorProxy::CaptureInfo>&
+          captures) override {
     DCHECK(device_task_runner_->RunsTasksInCurrentSequence());
 
     if (!stream_) {
@@ -607,9 +610,6 @@
     };
     [SCShareableContent getShareableContentWithCompletionHandler:handler];
   }
-  void OnCapturesChanged(
-      const std::vector<PipScreenCaptureCoordinatorProxy::CaptureInfo>&
-          captures) override {}
 
   // IOSurfaceCaptureDeviceBase:
   void OnStart() override {
diff --git a/content/browser/preloading/prerender/prerender_host_registry.h b/content/browser/preloading/prerender/prerender_host_registry.h
index 581b9b9..cc4f2a75 100644
--- a/content/browser/preloading/prerender/prerender_host_registry.h
+++ b/content/browser/preloading/prerender/prerender_host_registry.h
@@ -387,8 +387,6 @@
 
   // Hosts that are not reserved for activation yet. This map also includes the
   // hosts still waiting for their start.
-  // TODO(crbug.com/40150744): Expire prerendered contents if they are
-  // not used for a while.
   base::flat_map<FrameTreeNodeId, std::unique_ptr<PrerenderHost>>
       prerender_host_by_frame_tree_node_id_;
 
diff --git a/content/browser/preloading/prerenderer_impl.cc b/content/browser/preloading/prerenderer_impl.cc
index 00957881..cb5a5b18 100644
--- a/content/browser/preloading/prerenderer_impl.cc
+++ b/content/browser/preloading/prerenderer_impl.cc
@@ -10,6 +10,7 @@
 #include "base/compiler_specific.h"
 #include "base/feature_list.h"
 #include "base/strings/stringprintf.h"
+#include "base/trace_event/named_trigger.h"
 #include "content/browser/preloading/prefetch/no_vary_search_helper.h"
 #include "content/browser/preloading/prefetch/prefetch_document_manager.h"
 #include "content/browser/preloading/preloading.h"
@@ -446,6 +447,9 @@
       case blink::mojom::SpeculationTargetHint::kSelf: {
         if (base::FeatureList::IsEnabled(
                 features::kPrerender2FallbackPrefetchSpecRules)) {
+          base::trace_event::EmitNamedTrigger(
+              "specrules-prerender-trigger-prefetch");
+
           auto* prefetch_document_manager =
               content::PrefetchDocumentManager::GetOrCreateForCurrentDocument(
                   web_contents->GetPrimaryMainFrame());
diff --git a/content/renderer/webgraphicscontext3d_provider_impl.cc b/content/renderer/webgraphicscontext3d_provider_impl.cc
index 17d5081..1d89abeb 100644
--- a/content/renderer/webgraphicscontext3d_provider_impl.cc
+++ b/content/renderer/webgraphicscontext3d_provider_impl.cc
@@ -163,7 +163,6 @@
 
 cc::ImageDecodeCache* WebGraphicsContext3DProviderImpl::ImageDecodeCache(
     SkColorType color_type) {
-  CHECK(GetCapabilities().gpu_rasterization);
   auto cache_iterator = image_decode_cache_map_.find(color_type);
   if (cache_iterator != image_decode_cache_map_.end())
     return cache_iterator->second.get();
diff --git a/docs/website b/docs/website
index 105a469..1e6b908 160000
--- a/docs/website
+++ b/docs/website
@@ -1 +1 @@
-Subproject commit 105a46915f47f94998e4a3084520835f24ea5a6c
+Subproject commit 1e6b9080b485c33e823208661cebb5e1f470960c
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 321f8be..04efc21 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -3890,9 +3890,9 @@
       }
       UNSAFE_TODO(source += num_rows * pixels_padded_row_size);
       if (unpack_image_height_ > height && num_image_paddings > 0) {
-        UNSAFE_TODO(source +=
-                    num_image_paddings * (unpack_image_height_ - height)) *
-            pixels_padded_row_size;
+        UNSAFE_TODO(source += num_image_paddings *
+                              (unpack_image_height_ - height) *
+                              pixels_padded_row_size);
       }
     }
   }
diff --git a/gpu/command_buffer/client/internal/mappable_buffer_dxgi.cc b/gpu/command_buffer/client/internal/mappable_buffer_dxgi.cc
index 2f538d3..e047bace 100644
--- a/gpu/command_buffer/client/internal/mappable_buffer_dxgi.cc
+++ b/gpu/command_buffer/client/internal/mappable_buffer_dxgi.cc
@@ -226,8 +226,8 @@
                                   .data();
   // This is safe, since we already checked that the requested plane is
   // valid for current format.
-  UNSAFE_TODO(plane_addr += viz)::SharedMemoryOffsetForSharedImageFormat(
-      format_, plane, size_);
+  UNSAFE_TODO(plane_addr += viz::SharedMemoryOffsetForSharedImageFormat(
+                  format_, plane, size_));
   return plane_addr;
 }
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 0bb2581f..2c42b6b 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -11368,8 +11368,7 @@
         copy_binder = std::make_unique<ScopedFramebufferCopyBinder>(this);
       }
       if (y < 0) {
-        UNSAFE_TODO(pixels += static_cast<uint32_t>(-y)) * padded_row_size;
-        ;
+        UNSAFE_TODO(pixels += static_cast<uint32_t>(-y) * padded_row_size);
       }
       if (x < 0) {
         uint32_t group_size = GLES2Util::ComputeImageGroupSize(format, type);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
index d9fe1d60..2e65e4e 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
@@ -982,7 +982,7 @@
   EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ALIGNMENT, 1))
       .Times(1)
       .RetiresOnSaturation();
-  UNSAFE_TODO(offset += (kWidth * kBytesPerPixel + kPadding)) * (kHeight - 1);
+  UNSAFE_TODO(offset += (kWidth * kBytesPerPixel + kPadding) * (kHeight - 1));
   EXPECT_CALL(*gl_,
               ReadPixels(0, kHeight - 1, kWidth, 1, kFormat, kType, offset))
       .Times(1)
diff --git a/gpu/config/software_rendering_list.json b/gpu/config/software_rendering_list.json
index a4ca69c..33d51c5 100644
--- a/gpu/config/software_rendering_list.json
+++ b/gpu/config/software_rendering_list.json
@@ -1450,15 +1450,15 @@
     },
     {
       "id": 184,
-      "cr_bugs": [383521542],
+      "cr_bugs": [383521542, 458062283],
       "description": "Disable Graphite on very old Intel drivers",
       "os": {
         "type": "win"
       },
       "vendor_id": "0x8086",
       "driver_version": {
-        "op": "<=",
-        "value": "10.18.10.5161"
+        "op": "<",
+        "value": "31.0.101.2121"
       },
       "features": [
         "skia_graphite"
@@ -1492,6 +1492,22 @@
       "features": [
         "webgpu_on_vk_via_gl_interop"
       ]
+    },
+    {
+      "id": 187,
+      "cr_bugs": [458062283],
+      "description": "Disable Graphite on very old Intel GPU generations due to crashiness",
+      "os": {
+        "type": "win"
+      },
+      "vendor_id": "0x8086",
+      "intel_gpu_generation": {
+        "op": "<=",
+        "value": "8"
+      },
+      "features": [
+        "skia_graphite"
+      ]
     }
   ]
 }
diff --git a/infra/config/autoshard_exceptions.json b/infra/config/autoshard_exceptions.json
index 950b0f9..e7abb05e 100644
--- a/infra/config/autoshard_exceptions.json
+++ b/infra/config/autoshard_exceptions.json
@@ -190,7 +190,7 @@
                 "try_builder": "linux_chromium_asan_rel_ng"
             },
             "sync_integration_tests": {
-                "shards": 13,
+                "shards": 12,
                 "try_builder": "linux_chromium_asan_rel_ng"
             },
             "unit_tests": {
diff --git a/infra/config/generated/builders/alerting-builders.txt b/infra/config/generated/builders/alerting-builders.txt
index 07edc79c..8a30bdf1 100644
--- a/infra/config/generated/builders/alerting-builders.txt
+++ b/infra/config/generated/builders/alerting-builders.txt
@@ -330,6 +330,7 @@
 ci/chromeos-arm64-generic-rel
 ci/chromeos-jacuzzi-rel
 ci/chromeos-octopus-rel
+ci/chromeos-x64-libfuzzer-asan-rel-tests
 ci/fuchsia-angle-builder
 ci/fuchsia-arm64-cast-receiver-rel
 ci/fuchsia-fyi-arm64-dbg
@@ -380,12 +381,19 @@
 ci/linux-wayland-weston-rel-tests
 ci/linux-win-cross-clang-tot-rel
 ci/linux-win-cross-rel
+ci/linux-x64-centipede-asan-rel-tests
+ci/linux-x64-libfuzzer-asan-dbg-tests
+ci/linux-x64-libfuzzer-asan-rel-tests
+ci/linux-x64-libfuzzer-msan-rel-tests
+ci/linux-x64-libfuzzer-ubsan-rel-tests
+ci/linux-x86-libfuzzer-asan-rel-tests
 ci/mac-angle-chromium-amd
 ci/mac-angle-chromium-builder
 ci/mac-angle-chromium-intel
 ci/mac-archive-rel
 ci/mac-arm64-archive-rel
 ci/mac-arm64-dbg
+ci/mac-arm64-libfuzzer-asan-rel-tests
 ci/mac-arm64-on-arm64-rel
 ci/mac-arm64-rel
 ci/mac-official
@@ -410,6 +418,7 @@
 ci/win-swangle-tot-swiftshader-x86
 ci/win-swangle-x64
 ci/win-swangle-x86
+ci/win-x64-libfuzzer-asan-rel-tests
 ci/win10-angle-chromium-x64-intel
 ci/win10-angle-chromium-x64-nvidia
 ci/win11-arm64-rel-tests
@@ -497,6 +506,7 @@
 try/chromeos-js-coverage-rel
 try/chromeos-libfuzzer-asan-rel
 try/chromeos-octopus-rel
+try/chromeos-x64-libfuzzer-asan-rel-tests
 try/compile-size
 try/fuchsia-angle-try
 try/fuchsia-arm64-cast-receiver-rel
@@ -639,6 +649,12 @@
 try/linux-wayland-mutter-rel
 try/linux-wayland-weston-rel
 try/linux-win-cross-rel
+try/linux-x64-centipede-asan-rel-tests
+try/linux-x64-libfuzzer-asan-dbg-tests
+try/linux-x64-libfuzzer-asan-rel-tests
+try/linux-x64-libfuzzer-msan-rel-tests
+try/linux-x64-libfuzzer-ubsan-rel-tests
+try/linux-x86-libfuzzer-asan-rel-tests
 try/linux_chromium_archive_rel_ng
 try/linux_chromium_asan_rel_ng
 try/linux_chromium_cfi_rel_ng
@@ -652,6 +668,7 @@
 try/linux_chromium_ubsan_rel_ng
 try/mac-angle-chromium-try
 try/mac-arm64-clobber-rel
+try/mac-arm64-libfuzzer-asan-rel-tests
 try/mac-arm64-on-arm64-rel
 try/mac-asan-media-rel
 try/mac-asan-rel
@@ -713,6 +730,7 @@
 try/win-updater-try-builder-dbg
 try/win-updater-try-builder-rel
 try/win-utr-tester
+try/win-x64-libfuzzer-asan-rel-tests
 try/win10-dbg
 try/win11-rel
 try/win32-clobber-rel
diff --git a/infra/config/generated/builders/ci/Linux ASan LSan Builder/targets/chromium.memory.json b/infra/config/generated/builders/ci/Linux ASan LSan Builder/targets/chromium.memory.json
index a7dc77b..6eb011a 100644
--- a/infra/config/generated/builders/ci/Linux ASan LSan Builder/targets/chromium.memory.json
+++ b/infra/config/generated/builders/ci/Linux ASan LSan Builder/targets/chromium.memory.json
@@ -1503,7 +1503,7 @@
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 13
+          "shards": 12
         },
         "test": "sync_integration_tests",
         "test_id_prefix": "ninja://chrome/test:sync_integration_tests/"
diff --git "a/infra/config/generated/builders/ci/Linux ASan LSan Tests \0501\051/targets/chromium.memory.json" "b/infra/config/generated/builders/ci/Linux ASan LSan Tests \0501\051/targets/chromium.memory.json"
index a7dc77b..6eb011a 100644
--- "a/infra/config/generated/builders/ci/Linux ASan LSan Tests \0501\051/targets/chromium.memory.json"
+++ "b/infra/config/generated/builders/ci/Linux ASan LSan Tests \0501\051/targets/chromium.memory.json"
@@ -1503,7 +1503,7 @@
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 13
+          "shards": 12
         },
         "test": "sync_integration_tests",
         "test_id_prefix": "ninja://chrome/test:sync_integration_tests/"
diff --git a/infra/config/generated/builders/ci/chromeos-x64-libfuzzer-asan-rel-tests/properties.json b/infra/config/generated/builders/ci/chromeos-x64-libfuzzer-asan-rel-tests/properties.json
index cfc544e..7f3f869 100644
--- a/infra/config/generated/builders/ci/chromeos-x64-libfuzzer-asan-rel-tests/properties.json
+++ b/infra/config/generated/builders/ci/chromeos-x64-libfuzzer-asan-rel-tests/properties.json
@@ -72,5 +72,11 @@
     ]
   },
   "builder_group": "chromium.fuzz",
-  "recipe": "chromium"
+  "gardener_rotations": [
+    "chromium"
+  ],
+  "recipe": "chromium",
+  "sheriff_rotations": [
+    "chromium"
+  ]
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/linux-x64-centipede-asan-rel-tests/properties.json b/infra/config/generated/builders/ci/linux-x64-centipede-asan-rel-tests/properties.json
index ba38522..24b8f5a 100644
--- a/infra/config/generated/builders/ci/linux-x64-centipede-asan-rel-tests/properties.json
+++ b/infra/config/generated/builders/ci/linux-x64-centipede-asan-rel-tests/properties.json
@@ -69,5 +69,11 @@
     ]
   },
   "builder_group": "chromium.fuzz",
-  "recipe": "chromium"
+  "gardener_rotations": [
+    "chromium"
+  ],
+  "recipe": "chromium",
+  "sheriff_rotations": [
+    "chromium"
+  ]
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/linux-x64-libfuzzer-asan-dbg-tests/properties.json b/infra/config/generated/builders/ci/linux-x64-libfuzzer-asan-dbg-tests/properties.json
index eb5b6f0..77d9582 100644
--- a/infra/config/generated/builders/ci/linux-x64-libfuzzer-asan-dbg-tests/properties.json
+++ b/infra/config/generated/builders/ci/linux-x64-libfuzzer-asan-dbg-tests/properties.json
@@ -69,5 +69,11 @@
     ]
   },
   "builder_group": "chromium.fuzz",
-  "recipe": "chromium"
+  "gardener_rotations": [
+    "chromium"
+  ],
+  "recipe": "chromium",
+  "sheriff_rotations": [
+    "chromium"
+  ]
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/linux-x64-libfuzzer-asan-rel-tests/properties.json b/infra/config/generated/builders/ci/linux-x64-libfuzzer-asan-rel-tests/properties.json
index 2177e5f..fd76981 100644
--- a/infra/config/generated/builders/ci/linux-x64-libfuzzer-asan-rel-tests/properties.json
+++ b/infra/config/generated/builders/ci/linux-x64-libfuzzer-asan-rel-tests/properties.json
@@ -69,5 +69,11 @@
     ]
   },
   "builder_group": "chromium.fuzz",
-  "recipe": "chromium"
+  "gardener_rotations": [
+    "chromium"
+  ],
+  "recipe": "chromium",
+  "sheriff_rotations": [
+    "chromium"
+  ]
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/linux-x64-libfuzzer-msan-rel-tests/properties.json b/infra/config/generated/builders/ci/linux-x64-libfuzzer-msan-rel-tests/properties.json
index cffc941..76544012 100644
--- a/infra/config/generated/builders/ci/linux-x64-libfuzzer-msan-rel-tests/properties.json
+++ b/infra/config/generated/builders/ci/linux-x64-libfuzzer-msan-rel-tests/properties.json
@@ -70,5 +70,11 @@
     ]
   },
   "builder_group": "chromium.fuzz",
-  "recipe": "chromium"
+  "gardener_rotations": [
+    "chromium"
+  ],
+  "recipe": "chromium",
+  "sheriff_rotations": [
+    "chromium"
+  ]
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/linux-x64-libfuzzer-ubsan-rel-tests/properties.json b/infra/config/generated/builders/ci/linux-x64-libfuzzer-ubsan-rel-tests/properties.json
index 11a2753d..08b456c 100644
--- a/infra/config/generated/builders/ci/linux-x64-libfuzzer-ubsan-rel-tests/properties.json
+++ b/infra/config/generated/builders/ci/linux-x64-libfuzzer-ubsan-rel-tests/properties.json
@@ -69,5 +69,11 @@
     ]
   },
   "builder_group": "chromium.fuzz",
-  "recipe": "chromium"
+  "gardener_rotations": [
+    "chromium"
+  ],
+  "recipe": "chromium",
+  "sheriff_rotations": [
+    "chromium"
+  ]
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/linux-x86-libfuzzer-asan-rel-tests/properties.json b/infra/config/generated/builders/ci/linux-x86-libfuzzer-asan-rel-tests/properties.json
index 13777765..61b1d5e 100644
--- a/infra/config/generated/builders/ci/linux-x86-libfuzzer-asan-rel-tests/properties.json
+++ b/infra/config/generated/builders/ci/linux-x86-libfuzzer-asan-rel-tests/properties.json
@@ -69,5 +69,11 @@
     ]
   },
   "builder_group": "chromium.fuzz",
-  "recipe": "chromium"
+  "gardener_rotations": [
+    "chromium"
+  ],
+  "recipe": "chromium",
+  "sheriff_rotations": [
+    "chromium"
+  ]
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/mac-arm64-libfuzzer-asan-rel-tests/properties.json b/infra/config/generated/builders/ci/mac-arm64-libfuzzer-asan-rel-tests/properties.json
index 26082fd2a..19539f3 100644
--- a/infra/config/generated/builders/ci/mac-arm64-libfuzzer-asan-rel-tests/properties.json
+++ b/infra/config/generated/builders/ci/mac-arm64-libfuzzer-asan-rel-tests/properties.json
@@ -70,5 +70,11 @@
     ]
   },
   "builder_group": "chromium.fuzz",
-  "recipe": "chromium"
+  "gardener_rotations": [
+    "chromium"
+  ],
+  "recipe": "chromium",
+  "sheriff_rotations": [
+    "chromium"
+  ]
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/win-x64-libfuzzer-asan-rel-tests/properties.json b/infra/config/generated/builders/ci/win-x64-libfuzzer-asan-rel-tests/properties.json
index a15e5e6..76e500e6 100644
--- a/infra/config/generated/builders/ci/win-x64-libfuzzer-asan-rel-tests/properties.json
+++ b/infra/config/generated/builders/ci/win-x64-libfuzzer-asan-rel-tests/properties.json
@@ -69,5 +69,11 @@
     ]
   },
   "builder_group": "chromium.fuzz",
-  "recipe": "chromium"
+  "gardener_rotations": [
+    "chromium"
+  ],
+  "recipe": "chromium",
+  "sheriff_rotations": [
+    "chromium"
+  ]
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/targets/chromium.memory.json b/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/targets/chromium.memory.json
index a7dc77b..6eb011a 100644
--- a/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/targets/chromium.memory.json
+++ b/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/targets/chromium.memory.json
@@ -1503,7 +1503,7 @@
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 13
+          "shards": 12
         },
         "test": "sync_integration_tests",
         "test_id_prefix": "ninja://chrome/test:sync_integration_tests/"
diff --git a/infra/config/generated/cq-usage/mega_cq_bots.txt b/infra/config/generated/cq-usage/mega_cq_bots.txt
index 593a8d4..5670f8a3 100644
--- a/infra/config/generated/cq-usage/mega_cq_bots.txt
+++ b/infra/config/generated/cq-usage/mega_cq_bots.txt
@@ -71,6 +71,7 @@
 chromium/try/chromeos-jacuzzi-rel
 chromium/try/chromeos-libfuzzer-asan-rel
 chromium/try/chromeos-octopus-rel
+chromium/try/chromeos-x64-libfuzzer-asan-rel-tests
 chromium/try/fuchsia-arm64-cast-receiver-rel
 chromium/try/fuchsia-fyi-arm64-dbg
 chromium/try/fuchsia-fyi-x64-asan
@@ -128,6 +129,12 @@
 chromium/try/linux-wayland-mutter-rel
 chromium/try/linux-wayland-weston-rel
 chromium/try/linux-win-cross-rel
+chromium/try/linux-x64-centipede-asan-rel-tests
+chromium/try/linux-x64-libfuzzer-asan-dbg-tests
+chromium/try/linux-x64-libfuzzer-asan-rel-tests
+chromium/try/linux-x64-libfuzzer-msan-rel-tests
+chromium/try/linux-x64-libfuzzer-ubsan-rel-tests
+chromium/try/linux-x86-libfuzzer-asan-rel-tests
 chromium/try/linux_chromium_archive_rel_ng
 chromium/try/linux_chromium_asan_rel_ng
 chromium/try/linux_chromium_cfi_rel_ng
@@ -140,6 +147,7 @@
 chromium/try/linux_chromium_tsan_rel_ng
 chromium/try/linux_chromium_ubsan_rel_ng
 chromium/try/mac-arm64-clobber-rel
+chromium/try/mac-arm64-libfuzzer-asan-rel-tests
 chromium/try/mac-arm64-on-arm64-rel
 chromium/try/mac-asan-media-rel
 chromium/try/mac-asan-rel
@@ -168,6 +176,7 @@
 chromium/try/win-libfuzzer-asan-rel
 chromium/try/win-official
 chromium/try/win-rel
+chromium/try/win-x64-libfuzzer-asan-rel-tests
 chromium/try/win10-dbg
 chromium/try/win11-rel
 chromium/try/win32-clobber-rel
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 7e66ecb..7f246074 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -49893,9 +49893,16 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "chromium.fuzz",'
+        '  "gardener_rotations": ['
+        '    "chromium"'
+        '  ],'
         '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium"'
+        '  "recipe": "chromium",'
+        '  "sheriff_rotations": ['
+        '    "chromium"'
+        '  ]'
         '}'
       execution_timeout_secs: 21600
       build_numbers: YES
@@ -49945,6 +49952,11 @@
       }
       contact_team_email: "chrome-fuzzing-core@google.com"
       custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/alerts_enabled_count"
+        predicates: "has(build.input.properties.alerts_enabled)"
+        predicates: "string(build.input.properties.alerts_enabled) == \"true\""
+      }
+      custom_metric_definitions {
         name: "/chrome/infra/browser/builds/cached_count"
         predicates: "has(build.output.properties.is_cached)"
         predicates: "string(build.output.properties.is_cached) == \"true\""
@@ -61839,9 +61851,16 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "chromium.fuzz",'
+        '  "gardener_rotations": ['
+        '    "chromium"'
+        '  ],'
         '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium"'
+        '  "recipe": "chromium",'
+        '  "sheriff_rotations": ['
+        '    "chromium"'
+        '  ]'
         '}'
       execution_timeout_secs: 18000
       build_numbers: YES
@@ -61891,6 +61910,11 @@
       }
       contact_team_email: "chrome-fuzzing-core@google.com"
       custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/alerts_enabled_count"
+        predicates: "has(build.input.properties.alerts_enabled)"
+        predicates: "string(build.input.properties.alerts_enabled) == \"true\""
+      }
+      custom_metric_definitions {
         name: "/chrome/infra/browser/builds/cached_count"
         predicates: "has(build.output.properties.is_cached)"
         predicates: "string(build.output.properties.is_cached) == \"true\""
@@ -62054,9 +62078,16 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "chromium.fuzz",'
+        '  "gardener_rotations": ['
+        '    "chromium"'
+        '  ],'
         '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium"'
+        '  "recipe": "chromium",'
+        '  "sheriff_rotations": ['
+        '    "chromium"'
+        '  ]'
         '}'
       execution_timeout_secs: 14400
       build_numbers: YES
@@ -62106,6 +62137,11 @@
       }
       contact_team_email: "chrome-fuzzing-core@google.com"
       custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/alerts_enabled_count"
+        predicates: "has(build.input.properties.alerts_enabled)"
+        predicates: "string(build.input.properties.alerts_enabled) == \"true\""
+      }
+      custom_metric_definitions {
         name: "/chrome/infra/browser/builds/cached_count"
         predicates: "has(build.output.properties.is_cached)"
         predicates: "string(build.output.properties.is_cached) == \"true\""
@@ -62161,9 +62197,16 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "chromium.fuzz",'
+        '  "gardener_rotations": ['
+        '    "chromium"'
+        '  ],'
         '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium"'
+        '  "recipe": "chromium",'
+        '  "sheriff_rotations": ['
+        '    "chromium"'
+        '  ]'
         '}'
       execution_timeout_secs: 14400
       build_numbers: YES
@@ -62213,6 +62256,11 @@
       }
       contact_team_email: "chrome-fuzzing-core@google.com"
       custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/alerts_enabled_count"
+        predicates: "has(build.input.properties.alerts_enabled)"
+        predicates: "string(build.input.properties.alerts_enabled) == \"true\""
+      }
+      custom_metric_definitions {
         name: "/chrome/infra/browser/builds/cached_count"
         predicates: "has(build.output.properties.is_cached)"
         predicates: "string(build.output.properties.is_cached) == \"true\""
@@ -62268,9 +62316,16 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "chromium.fuzz",'
+        '  "gardener_rotations": ['
+        '    "chromium"'
+        '  ],'
         '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium"'
+        '  "recipe": "chromium",'
+        '  "sheriff_rotations": ['
+        '    "chromium"'
+        '  ]'
         '}'
       execution_timeout_secs: 10800
       build_numbers: YES
@@ -62320,6 +62375,11 @@
       }
       contact_team_email: "chrome-fuzzing-core@google.com"
       custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/alerts_enabled_count"
+        predicates: "has(build.input.properties.alerts_enabled)"
+        predicates: "string(build.input.properties.alerts_enabled) == \"true\""
+      }
+      custom_metric_definitions {
         name: "/chrome/infra/browser/builds/cached_count"
         predicates: "has(build.output.properties.is_cached)"
         predicates: "string(build.output.properties.is_cached) == \"true\""
@@ -62375,9 +62435,16 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "chromium.fuzz",'
+        '  "gardener_rotations": ['
+        '    "chromium"'
+        '  ],'
         '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium"'
+        '  "recipe": "chromium",'
+        '  "sheriff_rotations": ['
+        '    "chromium"'
+        '  ]'
         '}'
       execution_timeout_secs: 18000
       build_numbers: YES
@@ -62427,6 +62494,11 @@
       }
       contact_team_email: "chrome-fuzzing-core@google.com"
       custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/alerts_enabled_count"
+        predicates: "has(build.input.properties.alerts_enabled)"
+        predicates: "string(build.input.properties.alerts_enabled) == \"true\""
+      }
+      custom_metric_definitions {
         name: "/chrome/infra/browser/builds/cached_count"
         predicates: "has(build.output.properties.is_cached)"
         predicates: "string(build.output.properties.is_cached) == \"true\""
@@ -62482,9 +62554,16 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "chromium.fuzz",'
+        '  "gardener_rotations": ['
+        '    "chromium"'
+        '  ],'
         '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium"'
+        '  "recipe": "chromium",'
+        '  "sheriff_rotations": ['
+        '    "chromium"'
+        '  ]'
         '}'
       execution_timeout_secs: 10800
       build_numbers: YES
@@ -62534,6 +62613,11 @@
       }
       contact_team_email: "chrome-fuzzing-core@google.com"
       custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/alerts_enabled_count"
+        predicates: "has(build.input.properties.alerts_enabled)"
+        predicates: "string(build.input.properties.alerts_enabled) == \"true\""
+      }
+      custom_metric_definitions {
         name: "/chrome/infra/browser/builds/cached_count"
         predicates: "has(build.output.properties.is_cached)"
         predicates: "string(build.output.properties.is_cached) == \"true\""
@@ -63575,9 +63659,16 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "chromium.fuzz",'
+        '  "gardener_rotations": ['
+        '    "chromium"'
+        '  ],'
         '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium"'
+        '  "recipe": "chromium",'
+        '  "sheriff_rotations": ['
+        '    "chromium"'
+        '  ]'
         '}'
       execution_timeout_secs: 10800
       build_numbers: YES
@@ -63627,6 +63718,11 @@
       }
       contact_team_email: "chrome-fuzzing-core@google.com"
       custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/alerts_enabled_count"
+        predicates: "has(build.input.properties.alerts_enabled)"
+        predicates: "string(build.input.properties.alerts_enabled) == \"true\""
+      }
+      custom_metric_definitions {
         name: "/chrome/infra/browser/builds/cached_count"
         predicates: "has(build.output.properties.is_cached)"
         predicates: "string(build.output.properties.is_cached) == \"true\""
@@ -72301,9 +72397,16 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "chromium.fuzz",'
+        '  "gardener_rotations": ['
+        '    "chromium"'
+        '  ],'
         '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium"'
+        '  "recipe": "chromium",'
+        '  "sheriff_rotations": ['
+        '    "chromium"'
+        '  ]'
         '}'
       execution_timeout_secs: 28800
       build_numbers: YES
@@ -72353,6 +72456,11 @@
       }
       contact_team_email: "chrome-fuzzing-core@google.com"
       custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/alerts_enabled_count"
+        predicates: "has(build.input.properties.alerts_enabled)"
+        predicates: "string(build.input.properties.alerts_enabled) == \"true\""
+      }
+      custom_metric_definitions {
         name: "/chrome/infra/browser/builds/cached_count"
         predicates: "has(build.output.properties.is_cached)"
         predicates: "string(build.output.properties.is_cached) == \"true\""
@@ -93365,6 +93473,7 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "tryserver.chromium.fuzz",'
         '  "led_builder_is_bootstrapped": true,'
         '  "recipe": "chromium_trybot"'
@@ -118258,6 +118367,7 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "tryserver.chromium.fuzz",'
         '  "led_builder_is_bootstrapped": true,'
         '  "recipe": "chromium_trybot"'
@@ -118371,6 +118481,7 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "tryserver.chromium.fuzz",'
         '  "led_builder_is_bootstrapped": true,'
         '  "recipe": "chromium_trybot"'
@@ -118484,6 +118595,7 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "tryserver.chromium.fuzz",'
         '  "led_builder_is_bootstrapped": true,'
         '  "recipe": "chromium_trybot"'
@@ -118597,6 +118709,7 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "tryserver.chromium.fuzz",'
         '  "led_builder_is_bootstrapped": true,'
         '  "recipe": "chromium_trybot"'
@@ -118710,6 +118823,7 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "tryserver.chromium.fuzz",'
         '  "led_builder_is_bootstrapped": true,'
         '  "recipe": "chromium_trybot"'
@@ -118823,6 +118937,7 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "tryserver.chromium.fuzz",'
         '  "led_builder_is_bootstrapped": true,'
         '  "recipe": "chromium_trybot"'
@@ -121418,6 +121533,7 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "tryserver.chromium.fuzz",'
         '  "led_builder_is_bootstrapped": true,'
         '  "recipe": "chromium_trybot"'
@@ -132986,6 +133102,7 @@
         '      }'
         '    }'
         '  },'
+        '  "alerts_enabled": true,'
         '  "builder_group": "tryserver.chromium.fuzz",'
         '  "led_builder_is_bootstrapped": true,'
         '  "recipe": "chromium_trybot"'
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg
index 3a91a9c6..e9ff747 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -6671,6 +6671,11 @@
     short_name: "cent high"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/linux-x64-centipede-asan-rel-tests"
+    category: "chromium.fuzz|centipede-tests"
+    short_name: "cent"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/ChromiumOS ASAN Release"
     category: "chromium.fuzz|cros asan"
     short_name: "rel"
@@ -6741,6 +6746,46 @@
     short_name: "win-asan"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/chromeos-x64-libfuzzer-asan-rel-tests"
+    category: "chromium.fuzz|libfuzzer-tests"
+    short_name: "chromeos-asan"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.ci/linux-x64-libfuzzer-asan-rel-tests"
+    category: "chromium.fuzz|libfuzzer-tests"
+    short_name: "linux"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.ci/linux-x64-libfuzzer-asan-dbg-tests"
+    category: "chromium.fuzz|libfuzzer-tests"
+    short_name: "linux-dbg"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.ci/linux-x64-libfuzzer-msan-rel-tests"
+    category: "chromium.fuzz|libfuzzer-tests"
+    short_name: "linux-msan"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.ci/linux-x64-libfuzzer-ubsan-rel-tests"
+    category: "chromium.fuzz|libfuzzer-tests"
+    short_name: "linux-ubsan"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.ci/linux-x86-libfuzzer-asan-rel-tests"
+    category: "chromium.fuzz|libfuzzer-tests"
+    short_name: "linux32"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.ci/mac-arm64-libfuzzer-asan-rel-tests"
+    category: "chromium.fuzz|libfuzzer-tests"
+    short_name: "mac-arm64-asan"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.ci/win-x64-libfuzzer-asan-rel-tests"
+    category: "chromium.fuzz|libfuzzer-tests"
+    short_name: "win-asan"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/UBSan Release"
     category: "chromium.fuzz|linux UBSan"
     short_name: "rel"
diff --git a/infra/config/generated/luci/luci-notify.cfg b/infra/config/generated/luci/luci-notify.cfg
index aa41b2097..881ccce1 100644
--- a/infra/config/generated/luci/luci-notify.cfg
+++ b/infra/config/generated/luci/luci-notify.cfg
@@ -4758,6 +4758,42 @@
     bucket: "ci"
     name: "Libfuzzer Upload iOS Catalyst Debug"
   }
+  builders {
+    bucket: "ci"
+    name: "chromeos-x64-libfuzzer-asan-rel-tests"
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-x64-centipede-asan-rel-tests"
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-x64-libfuzzer-asan-dbg-tests"
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-x64-libfuzzer-asan-rel-tests"
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-x64-libfuzzer-msan-rel-tests"
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-x64-libfuzzer-ubsan-rel-tests"
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-x86-libfuzzer-asan-rel-tests"
+  }
+  builders {
+    bucket: "ci"
+    name: "mac-arm64-libfuzzer-asan-rel-tests"
+  }
+  builders {
+    bucket: "ci"
+    name: "win-x64-libfuzzer-asan-rel-tests"
+  }
 }
 builder_health_notifier {
   owner_email: "chrome-gpu-infra@google.com"
diff --git a/infra/config/generated/sheriff-rotations/chromium.txt b/infra/config/generated/sheriff-rotations/chromium.txt
index 28838fe..d88f434 100644
--- a/infra/config/generated/sheriff-rotations/chromium.txt
+++ b/infra/config/generated/sheriff-rotations/chromium.txt
@@ -77,6 +77,7 @@
 ci/chromeos-arm-generic-dbg
 ci/chromeos-arm-generic-rel
 ci/chromeos-arm64-generic-rel
+ci/chromeos-x64-libfuzzer-asan-rel-tests
 ci/fuchsia-arm64-cast-receiver-rel
 ci/fuchsia-x64-cast-receiver-dbg
 ci/fuchsia-x64-cast-receiver-rel
@@ -107,9 +108,16 @@
 ci/linux-wayland-mutter-rel-tests
 ci/linux-wayland-weston-rel-tests
 ci/linux-win-cross-rel
+ci/linux-x64-centipede-asan-rel-tests
+ci/linux-x64-libfuzzer-asan-dbg-tests
+ci/linux-x64-libfuzzer-asan-rel-tests
+ci/linux-x64-libfuzzer-msan-rel-tests
+ci/linux-x64-libfuzzer-ubsan-rel-tests
+ci/linux-x86-libfuzzer-asan-rel-tests
 ci/mac-archive-rel
 ci/mac-arm64-archive-rel
 ci/mac-arm64-dbg
+ci/mac-arm64-libfuzzer-asan-rel-tests
 ci/mac-arm64-on-arm64-rel
 ci/mac-arm64-rel
 ci/mac-official
@@ -124,6 +132,7 @@
 ci/win-asan
 ci/win-official
 ci/win-presubmit
+ci/win-x64-libfuzzer-asan-rel-tests
 ci/win11-arm64-rel-tests
 ci/win32-archive-rel
 ci/win32-official
diff --git a/infra/config/subprojects/chromium/ci/chromium.fuzz.star b/infra/config/subprojects/chromium/ci/chromium.fuzz.star
index 8ccce51..1b3a75d 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fuzz.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fuzz.star
@@ -347,9 +347,6 @@
                 targets.mixin(args = ["--asan-detect-odr-violation=0"]),
             ] + swarming_mixins,
         ),
-        # TODO(https://crbug.com/432407787): Add to a gardening rotation
-        # once the bots are proven green enough.
-        gardener_rotations = args.ignore_default(None),
         console_category = fuzzing_engine + "-tests",
         **kwargs
     )
diff --git a/internal b/internal
index cac0eda..96d5677 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit cac0eda4f931b94c714acd417202a318f49cc1cd
+Subproject commit 96d567763cde6fce93437285efeffbe518734435
diff --git a/ios/chrome/app/profile/BUILD.gn b/ios/chrome/app/profile/BUILD.gn
index 610b4d9..a15f8e0 100644
--- a/ios/chrome/app/profile/BUILD.gn
+++ b/ios/chrome/app/profile/BUILD.gn
@@ -41,6 +41,7 @@
     ":first_run_profile_agent",
     ":identity_confirmation_profile_agent",
     ":multi_profile_forced_migration_profile_agent",
+    ":otr_profile_destroyer_profile_agent",
     ":post_restore_profile_agent",
     ":profile",
     ":search_engine_choice_profile_agent",
@@ -374,6 +375,27 @@
   ]
 }
 
+source_set("otr_profile_destroyer_profile_agent") {
+  sources = [
+    "otr_profile_destroyer_profile_agent.h",
+    "otr_profile_destroyer_profile_agent.mm",
+  ]
+  deps = [
+    ":profile",
+    "//base",
+    "//ios/chrome/browser/browsing_data/model",
+    "//ios/chrome/browser/browsing_data/model:model_remove_mask",
+    "//ios/chrome/browser/crash_report/model",
+    "//ios/chrome/browser/shared/coordinator/scene:scene_state_header",
+    "//ios/chrome/browser/shared/coordinator/scene:scene_state_header_for_otr_profile_deletion",
+    "//ios/chrome/browser/shared/model/browser",
+    "//ios/chrome/browser/shared/model/profile",
+    "//ios/chrome/browser/shared/model/profile:incognito_session_tracker",
+    "//ios/chrome/browser/web_state_list/model/web_usage_enabler",
+    "//ios/web/public/thread",
+  ]
+}
+
 source_set("test_utils") {
   testonly = true
   sources = [
diff --git a/ios/chrome/app/profile/otr_profile_destroyer_profile_agent.h b/ios/chrome/app/profile/otr_profile_destroyer_profile_agent.h
new file mode 100644
index 0000000..1c48444
--- /dev/null
+++ b/ios/chrome/app/profile/otr_profile_destroyer_profile_agent.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_APP_PROFILE_OTR_PROFILE_DESTROYER_PROFILE_AGENT_H_
+#define IOS_CHROME_APP_PROFILE_OTR_PROFILE_DESTROYER_PROFILE_AGENT_H_
+
+#import "ios/chrome/app/profile/profile_state_agent.h"
+
+// ProfileAgent responsible for destroying and recreating the OTR profile
+// when the last incognito tab is closed.
+@interface OTRPRofileDestroyerProfileAgent : NSObject <ProfileStateAgent>
+@end
+
+#endif  // IOS_CHROME_APP_PROFILE_OTR_PROFILE_DESTROYER_PROFILE_AGENT_H_
diff --git a/ios/chrome/app/profile/otr_profile_destroyer_profile_agent.mm b/ios/chrome/app/profile/otr_profile_destroyer_profile_agent.mm
new file mode 100644
index 0000000..2f116953
--- /dev/null
+++ b/ios/chrome/app/profile/otr_profile_destroyer_profile_agent.mm
@@ -0,0 +1,166 @@
+// 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/app/profile/otr_profile_destroyer_profile_agent.h"
+
+#import "base/callback_list.h"
+#import "base/check.h"
+#import "base/check_op.h"
+#import "base/functional/bind.h"
+#import "base/functional/callback.h"
+#import "base/functional/callback_helpers.h"
+#import "base/sequence_checker.h"
+#import "ios/chrome/app/profile/profile_init_stage.h"
+#import "ios/chrome/app/profile/profile_state.h"
+#import "ios/chrome/browser/browsing_data/model/browsing_data_remove_mask.h"
+#import "ios/chrome/browser/browsing_data/model/browsing_data_remover.h"
+#import "ios/chrome/browser/browsing_data/model/browsing_data_remover_factory.h"
+#import "ios/chrome/browser/crash_report/model/crash_keys_helper.h"
+#import "ios/chrome/browser/shared/coordinator/scene/scene_controller+OTRProfileDeletion.h"
+#import "ios/chrome/browser/shared/coordinator/scene/scene_controller.h"
+#import "ios/chrome/browser/shared/coordinator/scene/scene_state.h"
+#import "ios/chrome/browser/shared/model/browser/browser_list.h"
+#import "ios/chrome/browser/shared/model/browser/browser_list_factory.h"
+#import "ios/chrome/browser/shared/model/profile/profile_incognito_session_tracker.h"
+#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
+#import "ios/chrome/browser/web_state_list/model/web_usage_enabler/web_usage_enabler_browser_agent.h"
+#import "ios/web/public/thread/web_task_traits.h"
+#import "ios/web/public/thread/web_thread.h"
+
+namespace {
+
+// For readability of the loop in -onBrowsingDataRemoved.
+constexpr BrowserList::BrowserType kRegularAndIncognito =
+    BrowserList::BrowserType::kRegularAndIncognito;
+
+}  // namespace
+
+@implementation OTRPRofileDestroyerProfileAgent {
+  // The owning ProfileState.
+  __weak ProfileState* _profileState;
+
+  // Subscription to listen for the profile destruction.
+  base::CallbackListSubscription _profileSubscription;
+
+  // Used to track whether the profile has any open off-the-record tabs.
+  std::unique_ptr<ProfileIncognitoSessionTracker> _tracker;
+
+  // Ensure sequence-affinity.
+  SEQUENCE_CHECKER(_sequenceChecker);
+}
+
+#pragma mark - ProfileStateAgent
+
+- (void)setProfileState:(ProfileState*)profileState {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
+  CHECK_GE(profileState.initStage, ProfileInitStage::kProfileLoaded);
+  _profileState = profileState;
+
+  ProfileIOS* profile = _profileState.profile;
+  CHECK(profile);
+
+  __weak OTRPRofileDestroyerProfileAgent* weakSelf = self;
+  _profileSubscription =
+      profile->RegisterProfileDestroyedCallback(base::BindOnce(^{
+        [weakSelf onProfileDestroyed];
+      }));
+
+  _tracker = std::make_unique<ProfileIncognitoSessionTracker>(
+      BrowserListFactory::GetForProfile(profile),
+      base::BindRepeating(^(bool has_incognito_tabs) {
+        [weakSelf onHasIncognitoTabsChanged:has_incognito_tabs];
+      }));
+}
+
+#pragma mark - Private methods
+
+- (void)onProfileDestroyed {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
+  _profileState = nil;
+  _tracker.reset();
+}
+
+- (void)onHasIncognitoTabsChanged:(bool)hasIncognitoTabs {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
+  if (!hasIncognitoTabs) {
+    // The last incognito tab has been closed, and the off-the-record profile
+    // must be destroyed and recreated. Queue an empty task on the IO thread
+    // to give a chance for the task in progress to complete before destroying
+    // the profile.
+    __weak OTRPRofileDestroyerProfileAgent* weakSelf = self;
+    web::GetIOThreadTaskRunner({})->PostTaskAndReply(
+        FROM_HERE, base::DoNothing(), base::BindOnce(^{
+          [weakSelf maybeDestroyAndRecreateOTRProfile];
+        }));
+  }
+}
+
+- (void)maybeDestroyAndRecreateOTRProfile {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
+  // It is possible for new incognito tabs to have been opened while waiting
+  // for the IO requests to finish. If this is the case, do nothing. Profile
+  // will be destroyed the next time the last incognito tab is closed.
+  if (_tracker && !_tracker->has_incognito_tabs()) {
+    [self destroyAndRecreateOTRProfile];
+  }
+}
+
+- (void)destroyAndRecreateOTRProfile {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
+  crash_keys::SetDestroyingAndRebuildingIncognitoBrowserState(true);
+
+  ProfileIOS* profile = _profileState.profile;
+  CHECK(profile->HasOffTheRecordProfile());
+
+  // Notify all connected scenes that the incognito profile will be destroyed.
+  for (SceneState* sceneState in _profileState.connectedScenes) {
+    [sceneState.controller willDestroyIncognitoProfile];
+  }
+
+  // Clears incognito data that is specific to iOS and won't be cleared by
+  // deleting the profile.
+  __weak OTRPRofileDestroyerProfileAgent* weakSelf = self;
+  BrowsingDataRemoverFactory::GetForProfile(profile->GetOffTheRecordProfile())
+      ->Remove(browsing_data::TimePeriod::ALL_TIME,
+               BrowsingDataRemoveMask::REMOVE_ALL, base::BindOnce(^{
+                 [weakSelf onBrowsingDataRemoved];
+               }));
+
+  // Destroy and recreate the incognito profile.
+  profile->DestroyOffTheRecordProfile();
+  CHECK(!profile->HasOffTheRecordProfile());
+
+  profile->GetOffTheRecordProfile();
+  CHECK(profile->HasOffTheRecordProfile());
+
+  // Notify all connected scenes that the incognito profile has been recreated.
+  for (SceneState* sceneState in _profileState.connectedScenes) {
+    [sceneState.controller incognitoProfileCreated];
+  }
+
+  crash_keys::SetDestroyingAndRebuildingIncognitoBrowserState(false);
+}
+
+- (void)onBrowsingDataRemoved {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
+  ProfileIOS* profile = _profileState.profile;
+  if (!profile) {
+    // If the profile has already been destroyed, there is nothing to do.
+    return;
+  }
+
+  if (BrowsingDataRemover* remover =
+          BrowsingDataRemoverFactory::GetForProfileIfExists(profile);
+      remover && remover->IsRemoving()) {
+    // If data removing is in progress, then do not enable web usage.
+    return;
+  }
+
+  BrowserList* browser_list = BrowserListFactory::GetForProfile(profile);
+  for (Browser* browser : browser_list->BrowsersOfType(kRegularAndIncognito)) {
+    WebUsageEnablerBrowserAgent::FromBrowser(browser)->SetWebUsageEnabled(true);
+  }
+}
+
+@end
diff --git a/ios/chrome/app/profile/profile_controller.mm b/ios/chrome/app/profile/profile_controller.mm
index 428a90a..c7ce80a 100644
--- a/ios/chrome/app/profile/profile_controller.mm
+++ b/ios/chrome/app/profile/profile_controller.mm
@@ -44,6 +44,7 @@
 #import "ios/chrome/app/profile/first_run_profile_agent.h"
 #import "ios/chrome/app/profile/identity_confirmation_profile_agent.h"
 #import "ios/chrome/app/profile/multi_profile_forced_migration_profile_agent.h"
+#import "ios/chrome/app/profile/otr_profile_destroyer_profile_agent.h"
 #import "ios/chrome/app/profile/post_restore_profile_agent.h"
 #import "ios/chrome/app/profile/profile_state.h"
 #import "ios/chrome/app/profile/profile_state_observer.h"
@@ -647,6 +648,7 @@
 }
 
 - (void)attachProfileAgents {
+  [_state addAgent:[[OTRPRofileDestroyerProfileAgent alloc] init]];
   [_state addAgent:[[CertificatePolicyProfileAgent alloc] init]];
   [_state addAgent:[[FirstRunProfileAgent alloc] init]];
   [_state addAgent:[[MultiProfileForcedMigrationProfileAgent alloc] init]];
diff --git a/ios/chrome/browser/authentication/account_menu/coordinator/account_menu_coordinator.mm b/ios/chrome/browser/authentication/account_menu/coordinator/account_menu_coordinator.mm
index c26fe0bc..173ea83 100644
--- a/ios/chrome/browser/authentication/account_menu/coordinator/account_menu_coordinator.mm
+++ b/ios/chrome/browser/authentication/account_menu/coordinator/account_menu_coordinator.mm
@@ -161,6 +161,8 @@
   DCHECK(!_mediator);
 }
 
+#pragma mark - ChromeCoordinator
+
 - (void)start {
   ProfileIOS* profile = self.profile;
   _identityManager = IdentityManagerFactory::GetForProfile(profile);
diff --git a/ios/chrome/browser/authentication/account_menu/ui/account_menu_view_controller.mm b/ios/chrome/browser/authentication/account_menu/ui/account_menu_view_controller.mm
index 691ddae..3e3bf2ff 100644
--- a/ios/chrome/browser/authentication/account_menu/ui/account_menu_view_controller.mm
+++ b/ios/chrome/browser/authentication/account_menu/ui/account_menu_view_controller.mm
@@ -476,20 +476,16 @@
   presentationController.prefersEdgeAttachedInCompactHeight = YES;
   presentationController.widthFollowsPreferredContentSizeWhenEdgeAttached = YES;
 
-  // In case of compact width only, adjust detents.
-  if (self.traitCollection.horizontalSizeClass ==
-      UIUserInterfaceSizeClassCompact) {
-    __weak __typeof(self) weakSelf = self;
-    auto preferredHeightForSheetContent = ^CGFloat(
-        id<UISheetPresentationControllerDetentResolutionContext> context) {
-      return [weakSelf preferredHeightForSheetContent];
-    };
-    UISheetPresentationControllerDetent* customDetent =
-        [UISheetPresentationControllerDetent
-            customDetentWithIdentifier:kCustomMinimizedDetentIdentifier
-                              resolver:preferredHeightForSheetContent];
-    presentationController.detents = @[ customDetent ];
-  }
+  __weak __typeof(self) weakSelf = self;
+  auto preferredHeightForSheetContent = ^CGFloat(
+      id<UISheetPresentationControllerDetentResolutionContext> context) {
+    return [weakSelf preferredHeightForSheetContent];
+  };
+  UISheetPresentationControllerDetent* customDetent =
+      [UISheetPresentationControllerDetent
+          customDetentWithIdentifier:kCustomMinimizedDetentIdentifier
+                            resolver:preferredHeightForSheetContent];
+  presentationController.detents = @[ customDetent ];
 
   presentationController.selectedDetentIdentifier =
       kCustomMinimizedDetentIdentifier;
diff --git a/ios/chrome/browser/autocomplete/model/BUILD.gn b/ios/chrome/browser/autocomplete/model/BUILD.gn
index e73577bf..08acac06 100644
--- a/ios/chrome/browser/autocomplete/model/BUILD.gn
+++ b/ios/chrome/browser/autocomplete/model/BUILD.gn
@@ -4,6 +4,8 @@
 
 source_set("model") {
   sources = [
+    "autocomplete_browser_agent.h",
+    "autocomplete_browser_agent.mm",
     "autocomplete_classifier_factory.cc",
     "autocomplete_classifier_factory.h",
     "autocomplete_provider_client_impl.h",
@@ -12,10 +14,6 @@
     "autocomplete_scheme_classifier_impl.mm",
     "autocomplete_scoring_model_service_factory.h",
     "autocomplete_scoring_model_service_factory.mm",
-    "autocomplete_service.h",
-    "autocomplete_service.mm",
-    "autocomplete_service_factory.h",
-    "autocomplete_service_factory.mm",
     "in_memory_url_index_factory.cc",
     "in_memory_url_index_factory.h",
     "omnibox_pedal_implementation.h",
diff --git a/ios/chrome/browser/autocomplete/model/autocomplete_service.h b/ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.h
similarity index 76%
rename from ios/chrome/browser/autocomplete/model/autocomplete_service.h
rename to ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.h
index 4f458486..b1b31b1 100644
--- a/ios/chrome/browser/autocomplete/model/autocomplete_service.h
+++ b/ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.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 IOS_CHROME_BROWSER_AUTOCOMPLETE_MODEL_AUTOCOMPLETE_SERVICE_H_
-#define IOS_CHROME_BROWSER_AUTOCOMPLETE_MODEL_AUTOCOMPLETE_SERVICE_H_
+#ifndef IOS_CHROME_BROWSER_AUTOCOMPLETE_MODEL_AUTOCOMPLETE_BROWSER_AGENT_H_
+#define IOS_CHROME_BROWSER_AUTOCOMPLETE_MODEL_AUTOCOMPLETE_BROWSER_AGENT_H_
 
 #import <map>
 #import <memory>
@@ -12,9 +12,9 @@
 #import "base/functional/callback.h"
 #import "base/memory/raw_ptr.h"
 #import "base/memory/weak_ptr.h"
-#import "components/keyed_service/core/keyed_service.h"
 #import "ios/chrome/browser/autocomplete/model/omnibox_shortcuts_helper.h"
 #import "ios/chrome/browser/omnibox/public/omnibox_presentation_context.h"
+#import "ios/chrome/browser/shared/model/browser/browser_user_data.h"
 #import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/shared/model/web_state_list/web_state_list_observer.h"
 #import "ios/web/public/web_state.h"
@@ -22,21 +22,16 @@
 
 @class ZeroSuggestPrefetcher;
 class AutocompleteController;
-class AutocompleteProviderClient;
-class ShortcutsBackend;
+class Browser;
 
 /// Keyed Service that owns and manages long-lived Omnibox objects
 /// (AutocompleteController, etc.) per presentation context.
-class AutocompleteService : public KeyedService {
+class AutocompleteBrowserAgent
+    : public BrowserUserData<AutocompleteBrowserAgent> {
  public:
-  explicit AutocompleteService(
-      base::RepeatingCallback<std::unique_ptr<AutocompleteProviderClient>()>
-          client_factory,
-      ShortcutsBackend* shortcuts_backend);
-  ~AutocompleteService() override;
-
-  // KeyedService implementation.
-  void Shutdown() override;
+  AutocompleteBrowserAgent(const AutocompleteBrowserAgent&) = delete;
+  AutocompleteBrowserAgent& operator=(const AutocompleteBrowserAgent&) = delete;
+  ~AutocompleteBrowserAgent() override;
 
   // Returns the AutocompleteController for the given context.
   // If it doesn't exist, it creates one.
@@ -75,20 +70,20 @@
   // Unregisters a single WebState for prefetching.
   void UnregisterWebStateForPrefetching(web::WebState* web_state);
 
-  base::WeakPtr<AutocompleteService> AsWeakPtr() {
+  base::WeakPtr<AutocompleteBrowserAgent> AsWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
   }
 
  private:
+  friend class BrowserUserData<AutocompleteBrowserAgent>;
+
+  explicit AutocompleteBrowserAgent(Browser* browser);
+
   // Creates a new AutocompleteController.
   std::unique_ptr<AutocompleteController> CreateAutocompleteController();
   // Creates a new OmniboxShortcutsHelper for the given context.
   std::unique_ptr<OmniboxShortcutsHelper> CreateOmniboxShortcutsHelper();
 
-  base::RepeatingCallback<std::unique_ptr<AutocompleteProviderClient>()>
-      client_factory_;
-  raw_ptr<ShortcutsBackend> shortcuts_backend_;
-
   std::map<OmniboxPresentationContext, std::unique_ptr<AutocompleteController>>
       controllers_;
   std::map<OmniboxPresentationContext, std::unique_ptr<OmniboxShortcutsHelper>>
@@ -96,7 +91,7 @@
   std::map<WebStateList*, ZeroSuggestPrefetcher*> web_state_list_prefetchers_;
   std::map<web::WebState*, ZeroSuggestPrefetcher*> web_state_prefetchers_;
 
-  base::WeakPtrFactory<AutocompleteService> weak_ptr_factory_{this};
+  base::WeakPtrFactory<AutocompleteBrowserAgent> weak_ptr_factory_{this};
 };
 
-#endif  // IOS_CHROME_BROWSER_AUTOCOMPLETE_MODEL_AUTOCOMPLETE_SERVICE_H_
+#endif  // IOS_CHROME_BROWSER_AUTOCOMPLETE_MODEL_AUTOCOMPLETE_BROWSER_AGENT_H_
diff --git a/ios/chrome/browser/autocomplete/model/autocomplete_service.mm b/ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.mm
similarity index 73%
rename from ios/chrome/browser/autocomplete/model/autocomplete_service.mm
rename to ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.mm
index 89d0311..09eca91a 100644
--- a/ios/chrome/browser/autocomplete/model/autocomplete_service.mm
+++ b/ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/autocomplete/model/autocomplete_service.h"
+#import "ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.h"
 
 #import <algorithm>
 
@@ -11,24 +11,21 @@
 #import "components/omnibox/browser/autocomplete_provider_client.h"
 #import "components/omnibox/browser/page_classification_functions.h"
 #import "components/omnibox/browser/shortcuts_backend.h"
+#import "ios/chrome/browser/autocomplete/model/autocomplete_provider_client_impl.h"
+#import "ios/chrome/browser/autocomplete/model/shortcuts_backend_factory.h"
 #import "ios/chrome/browser/autocomplete/model/zero_suggest_prefetcher.h"
+#import "ios/chrome/browser/shared/model/browser/browser.h"
 #import "ios/chrome/browser/shared/model/profile/profile_ios.h"
 #import "ios/web/public/web_state.h"
 
-AutocompleteService::AutocompleteService(
-    base::RepeatingCallback<std::unique_ptr<AutocompleteProviderClient>()>
-        client_factory,
-    ShortcutsBackend* shortcuts_backend)
-    : client_factory_(std::move(client_factory)),
-      shortcuts_backend_(shortcuts_backend) {}
+AutocompleteBrowserAgent::AutocompleteBrowserAgent(Browser* browser)
+    : BrowserUserData(browser) {}
 
-AutocompleteService::~AutocompleteService() {}
-
-void AutocompleteService::Shutdown() {
+AutocompleteBrowserAgent::~AutocompleteBrowserAgent() {
   RemoveServices();
 }
 
-AutocompleteController* AutocompleteService::GetAutocompleteController(
+AutocompleteController* AutocompleteBrowserAgent::GetAutocompleteController(
     OmniboxPresentationContext context) {
   auto it = controllers_.find(context);
   if (it != controllers_.end()) {
@@ -44,7 +41,7 @@
   return controller_ptr;
 }
 
-OmniboxShortcutsHelper* AutocompleteService::GetOmniboxShortcutsHelper(
+OmniboxShortcutsHelper* AutocompleteBrowserAgent::GetOmniboxShortcutsHelper(
     OmniboxPresentationContext context) {
   auto it = shortcuts_helpers_.find(context);
   if (it != shortcuts_helpers_.end()) {
@@ -57,7 +54,7 @@
   return helper_ptr;
 }
 
-void AutocompleteService::RemoveServices() {
+void AutocompleteBrowserAgent::RemoveServices() {
   for (auto it = web_state_list_prefetchers_.begin();
        it != web_state_list_prefetchers_.end(); ++it) {
     [it->second disconnect];
@@ -72,7 +69,7 @@
   controllers_.clear();
 }
 
-void AutocompleteService::RegisterWebStateListForPrefetching(
+void AutocompleteBrowserAgent::RegisterWebStateListForPrefetching(
     OmniboxPresentationContext context,
     WebStateList* web_state_list,
     PageClassificationCallback classification_callback) {
@@ -81,13 +78,13 @@
                         webStateList:web_state_list
               classificationCallback:std::move(classification_callback)
                   disconnectCallback:
-                      base::BindOnce(&AutocompleteService::
+                      base::BindOnce(&AutocompleteBrowserAgent::
                                          UnregisterWebStateListForPrefetching,
                                      AsWeakPtr())];
   web_state_list_prefetchers_[web_state_list] = prefetcher;
 }
 
-void AutocompleteService::UnregisterWebStateListForPrefetching(
+void AutocompleteBrowserAgent::UnregisterWebStateListForPrefetching(
     WebStateList* web_state_list) {
   auto it = web_state_list_prefetchers_.find(web_state_list);
   if (it != web_state_list_prefetchers_.end()) {
@@ -96,7 +93,7 @@
   }
 }
 
-void AutocompleteService::RegisterWebStateForPrefetching(
+void AutocompleteBrowserAgent::RegisterWebStateForPrefetching(
     OmniboxPresentationContext context,
     web::WebState* web_state,
     PageClassificationCallback classification_callback) {
@@ -105,13 +102,13 @@
                             webState:web_state
               classificationCallback:std::move(classification_callback)
                   disconnectCallback:base::BindOnce(
-                                         &AutocompleteService::
+                                         &AutocompleteBrowserAgent::
                                              UnregisterWebStateForPrefetching,
                                          AsWeakPtr())];
   web_state_prefetchers_[web_state] = prefetcher;
 }
 
-void AutocompleteService::UnregisterWebStateForPrefetching(
+void AutocompleteBrowserAgent::UnregisterWebStateForPrefetching(
     web::WebState* web_state) {
   auto it = web_state_prefetchers_.find(web_state);
   if (it != web_state_prefetchers_.end()) {
@@ -121,12 +118,9 @@
 }
 
 std::unique_ptr<AutocompleteController>
-AutocompleteService::CreateAutocompleteController() {
+AutocompleteBrowserAgent::CreateAutocompleteController() {
   std::unique_ptr<AutocompleteProviderClient> provider_client =
-      client_factory_.Run();
-  if (!provider_client) {
-    return nullptr;
-  }
+      std::make_unique<AutocompleteProviderClientImpl>(browser_->GetProfile());
 
   int providers = AutocompleteClassifier::DefaultOmniboxProviders();
 
@@ -136,6 +130,8 @@
 }
 
 std::unique_ptr<OmniboxShortcutsHelper>
-AutocompleteService::CreateOmniboxShortcutsHelper() {
-  return std::make_unique<OmniboxShortcutsHelper>(shortcuts_backend_);
+AutocompleteBrowserAgent::CreateOmniboxShortcutsHelper() {
+  return std::make_unique<OmniboxShortcutsHelper>(
+      ios::ShortcutsBackendFactory::GetForProfile(browser_->GetProfile())
+          .get());
 }
diff --git a/ios/chrome/browser/autocomplete/model/autocomplete_service_factory.h b/ios/chrome/browser/autocomplete/model/autocomplete_service_factory.h
deleted file mode 100644
index 41acb903..0000000
--- a/ios/chrome/browser/autocomplete/model/autocomplete_service_factory.h
+++ /dev/null
@@ -1,31 +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 IOS_CHROME_BROWSER_AUTOCOMPLETE_MODEL_AUTOCOMPLETE_SERVICE_FACTORY_H_
-#define IOS_CHROME_BROWSER_AUTOCOMPLETE_MODEL_AUTOCOMPLETE_SERVICE_FACTORY_H_
-
-#import "base/no_destructor.h"
-#import "ios/chrome/browser/shared/model/profile/profile_keyed_service_factory_ios.h"
-
-class ProfileIOS;
-class AutocompleteService;
-
-/// Factory for the AutocompleteService.
-class AutocompleteServiceFactory : public ProfileKeyedServiceFactoryIOS {
- public:
-  static AutocompleteService* GetForProfile(ProfileIOS* profile);
-  static AutocompleteServiceFactory* GetInstance();
-
- private:
-  friend class base::NoDestructor<AutocompleteServiceFactory>;
-
-  AutocompleteServiceFactory();
-  ~AutocompleteServiceFactory() override;
-
-  // ProfileKeyedServiceFactoryIOS
-  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      ProfileIOS* profile) const override;
-};
-
-#endif  // IOS_CHROME_BROWSER_AUTOCOMPLETE_MODEL_AUTOCOMPLETE_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/autocomplete/model/autocomplete_service_factory.mm b/ios/chrome/browser/autocomplete/model/autocomplete_service_factory.mm
deleted file mode 100644
index a1427396..0000000
--- a/ios/chrome/browser/autocomplete/model/autocomplete_service_factory.mm
+++ /dev/null
@@ -1,82 +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.
-
-#import "ios/chrome/browser/autocomplete/model/autocomplete_service_factory.h"
-
-#import "base/functional/bind.h"
-#import "base/memory/scoped_refptr.h"
-#import "components/omnibox/browser/shortcuts_backend.h"
-#import "ios/chrome/browser/autocomplete/model/autocomplete_classifier_factory.h"
-#import "ios/chrome/browser/autocomplete/model/autocomplete_provider_client_impl.h"
-#import "ios/chrome/browser/autocomplete/model/autocomplete_scoring_model_service_factory.h"
-#import "ios/chrome/browser/autocomplete/model/autocomplete_service.h"
-#import "ios/chrome/browser/autocomplete/model/in_memory_url_index_factory.h"
-#import "ios/chrome/browser/autocomplete/model/on_device_tail_model_service_factory.h"
-#import "ios/chrome/browser/autocomplete/model/provider_state_service_factory.h"
-#import "ios/chrome/browser/autocomplete/model/remote_suggestions_service_factory.h"
-#import "ios/chrome/browser/autocomplete/model/shortcuts_backend_factory.h"
-#import "ios/chrome/browser/autocomplete/model/zero_suggest_cache_service_factory.h"
-#import "ios/chrome/browser/bookmarks/model/bookmark_model_factory.h"
-#import "ios/chrome/browser/history/model/history_service_factory.h"
-#import "ios/chrome/browser/history/model/top_sites_factory.h"
-#import "ios/chrome/browser/search_engines/model/template_url_service_factory.h"
-#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
-#import "ios/chrome/browser/signin/model/identity_manager_factory.h"
-#import "ios/chrome/browser/sync/model/sync_service_factory.h"
-
-namespace {
-
-// Factory for AutocompleteProviderClient.
-std::unique_ptr<AutocompleteProviderClient> CreateAutocompleteProviderClient(
-    base::WeakPtr<ProfileIOS> profile) {
-  CHECK(profile);
-  return std::make_unique<AutocompleteProviderClientImpl>(profile.get());
-}
-
-}  // namespace
-
-// static
-AutocompleteService* AutocompleteServiceFactory::GetForProfile(
-    ProfileIOS* profile) {
-  return GetInstance()->GetServiceForProfileAs<AutocompleteService>(
-      profile, /*create=*/true);
-}
-
-// static
-AutocompleteServiceFactory* AutocompleteServiceFactory::GetInstance() {
-  static base::NoDestructor<AutocompleteServiceFactory> instance;
-  return instance.get();
-}
-
-AutocompleteServiceFactory::AutocompleteServiceFactory()
-    : ProfileKeyedServiceFactoryIOS("AutocompleteService",
-                                    ProfileSelection::kOwnInstanceInIncognito,
-                                    TestingCreation::kCreateService) {
-  DependsOn(ios::AutocompleteClassifierFactory::GetInstance());
-  DependsOn(ios::AutocompleteScoringModelServiceFactory::GetInstance());
-  DependsOn(ios::BookmarkModelFactory::GetInstance());
-  DependsOn(ios::HistoryServiceFactory::GetInstance());
-  DependsOn(IdentityManagerFactory::GetInstance());
-  DependsOn(ios::InMemoryURLIndexFactory::GetInstance());
-  DependsOn(OnDeviceTailModelServiceFactory::GetInstance());
-  DependsOn(ios::ProviderStateServiceFactory::GetInstance());
-  DependsOn(RemoteSuggestionsServiceFactory::GetInstance());
-  DependsOn(ios::ShortcutsBackendFactory::GetInstance());
-  DependsOn(SyncServiceFactory::GetInstance());
-  DependsOn(ios::TemplateURLServiceFactory::GetInstance());
-  DependsOn(ios::TopSitesFactory::GetInstance());
-  DependsOn(ios::ZeroSuggestCacheServiceFactory::GetInstance());
-}
-
-AutocompleteServiceFactory::~AutocompleteServiceFactory() = default;
-
-std::unique_ptr<KeyedService>
-AutocompleteServiceFactory::BuildServiceInstanceFor(ProfileIOS* profile) const {
-  scoped_refptr<ShortcutsBackend> shortcuts_backend =
-      ios::ShortcutsBackendFactory::GetForProfile(profile);
-  return std::make_unique<AutocompleteService>(
-      base::BindRepeating(&CreateAutocompleteProviderClient,
-                          profile->AsWeakPtr()),
-      shortcuts_backend.get());
-}
diff --git a/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_input_accessory_coordinator.mm b/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_input_accessory_coordinator.mm
index c3bc2a5..1478dcc 100644
--- a/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_input_accessory_coordinator.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_input_accessory_coordinator.mm
@@ -578,8 +578,14 @@
       [applicationHandler openURLInNewTab:command];
       return;
     }
+  }
 
-    if (type == autofill::AutofillProfile::RecordType::kAccountNameEmail) {
+  if (base::FeatureList::IsEnabled(
+          autofill::features::kAutofillEnableSupportForNameAndEmail)) {
+    id<ApplicationCommands> applicationHandler = HandlerForProtocol(
+        self.browser->GetCommandDispatcher(), ApplicationCommands);
+    if (address.record_type() ==
+        autofill::AutofillProfile::RecordType::kAccountNameEmail) {
       OpenNewTabCommand* command = [OpenNewTabCommand
           commandWithURLFromChrome:GURL(kGoogleAccountNameEmailAddressEditURL)];
       [applicationHandler openURLInNewTab:command];
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/address_view_controller_egtest.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/address_view_controller_egtest.mm
index 663a09b..8ded457 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/address_view_controller_egtest.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/address_view_controller_egtest.mm
@@ -227,6 +227,11 @@
         autofill::features::kAutofillEnableSupportForHomeAndWork);
   }
 
+  if ([self isRunningTest:@selector(testDoNotEditNamEmailFromOverflowMenu)]) {
+    config.features_enabled.push_back(
+        autofill::features::kAutofillEnableSupportForNameAndEmail);
+  }
+
   return config;
 }
 
@@ -510,6 +515,31 @@
       assertWithMatcher:grey_notVisible()];
 }
 
+// Tests the "Edit" action of the overflow menu button does not display the
+// address's details for Name and Email profile.
+- (void)testDoNotEditNamEmailFromOverflowMenu {
+  [AutofillAppInterface clearProfilesStore];
+  [AutofillAppInterface saveExampleAccountNameEmailProfile];
+
+  // Bring up the keyboard
+  [[EarlGrey selectElementWithMatcher:WebViewMatcher()]
+      performAction:TapWebElementWithId(kFormElementName)];
+  [ChromeEarlGrey waitForKeyboardToAppear];
+
+  // Open the address manual fill view.
+  OpenAddressManualFillView();
+
+  // Tap the overflow menu button and select the "Edit" action.
+  [[EarlGrey selectElementWithMatcher:OverflowMenuButton(/*cell_index=*/0)]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:OverflowMenuEditAction()]
+      performAction:grey_tap()];
+
+  // Check that the address details page is not opened.
+  [[EarlGrey selectElementWithMatcher:AddressDetailsPage()]
+      assertWithMatcher:grey_notVisible()];
+}
+
 #pragma mark - Private
 
 // Verify that the address info has been filled.
diff --git a/ios/chrome/browser/browser_state/model/DEPS b/ios/chrome/browser/browser_state/model/DEPS
deleted file mode 100644
index 7e7414c0f..0000000
--- a/ios/chrome/browser/browser_state/model/DEPS
+++ /dev/null
@@ -1,27 +0,0 @@
-include_rules = [
-  "+components/page_content_annotations/core",
-  "+ios/chrome/browser/affiliations/model",
-  "+ios/chrome/browser/bookmarks/model",
-  "+ios/chrome/browser/content_settings/model",
-  "+ios/chrome/browser/net/model",
-  "+ios/chrome/browser/optimization_guide/model",
-  "+ios/chrome/browser/page_info/model",
-  "+ios/chrome/browser/plus_addresses/model",
-  "+ios/chrome/browser/policy/model",
-  "+ios/chrome/browser/prefs/model",
-  "+ios/chrome/browser/profile/model",
-  "+ios/chrome/browser/push_notification/model",
-  "+ios/chrome/browser/segmentation_platform/model",
-  "+ios/chrome/browser/signin/model",
-  "+ios/chrome/browser/supervised_user/model",
-  "+ios/chrome/browser/sync/model",
-  "+ios/chrome/browser/unified_consent/model",
-]
-
-specific_include_rules = {
-  # TODO(crbug.com/40820398): Remove this dependency.
-  "^browser_state_keyed_service_factories.mm": [
-    "+ios/chrome/browser",
-    "+ios/chrome/browser/voice/ui_bundled/text_to_speech_playback_controller_factory.h",
-  ],
-}
diff --git a/ios/chrome/browser/browser_state/model/OWNERS b/ios/chrome/browser/browser_state/model/OWNERS
deleted file mode 100644
index c5cd5cb..0000000
--- a/ios/chrome/browser/browser_state/model/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-sdefresne@chromium.org
diff --git a/ios/chrome/browser/browser_view/ui_bundled/browser_coordinator_unittest.mm b/ios/chrome/browser/browser_view/ui_bundled/browser_coordinator_unittest.mm
index 8e1feb2..7988d23 100644
--- a/ios/chrome/browser/browser_view/ui_bundled/browser_coordinator_unittest.mm
+++ b/ios/chrome/browser/browser_view/ui_bundled/browser_coordinator_unittest.mm
@@ -10,6 +10,7 @@
 #import "components/sync/service/sync_service_utils.h"
 #import "components/trusted_vault/trusted_vault_server_constants.h"
 #import "ios/chrome/browser/authentication/trusted_vault_reauthentication/coordinator/trusted_vault_reauthentication_coordinator.h"
+#import "ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.h"
 #import "ios/chrome/browser/bookmarks/model/bookmark_model_factory.h"
 #import "ios/chrome/browser/browser_view/model/browser_view_visibility_notifier_browser_agent.h"
 #import "ios/chrome/browser/browser_view/ui_bundled/browser_coordinator+Testing.h"
@@ -144,6 +145,7 @@
     DiscoverFeedVisibilityBrowserAgent::CreateForBrowser(browser_.get());
     ToolbarsSizeBrowserAgent::CreateForBrowser(browser_.get());
     TestFullscreenController::CreateForBrowser(browser_.get());
+    AutocompleteBrowserAgent::CreateForBrowser(browser_.get());
 
     WebUsageEnablerBrowserAgent* enabler =
         WebUsageEnablerBrowserAgent::FromBrowser(browser_.get());
diff --git a/ios/chrome/browser/browser_view/ui_bundled/browser_view_controller_unittest.mm b/ios/chrome/browser/browser_view/ui_bundled/browser_view_controller_unittest.mm
index 7156652..a41d5a4b 100644
--- a/ios/chrome/browser/browser_view/ui_bundled/browser_view_controller_unittest.mm
+++ b/ios/chrome/browser/browser_view/ui_bundled/browser_view_controller_unittest.mm
@@ -17,8 +17,7 @@
 #import "components/open_from_clipboard/fake_clipboard_recent_content.h"
 #import "components/search_engines/template_url_service.h"
 #import "components/supervised_user/core/common/features.h"
-#import "ios/chrome/browser/autocomplete/model/autocomplete_service.h"
-#import "ios/chrome/browser/autocomplete/model/autocomplete_service_factory.h"
+#import "ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.h"
 #import "ios/chrome/browser/bookmarks/model/bookmark_model_factory.h"
 #import "ios/chrome/browser/bookmarks/ui_bundled/home/bookmarks_coordinator.h"
 #import "ios/chrome/browser/browser_container/ui_bundled/browser_container_view_controller.h"
@@ -182,6 +181,7 @@
     TabUsageRecorderBrowserAgent::CreateForBrowser(browser_.get());
     StartSurfaceRecentTabBrowserAgent::CreateForBrowser(browser_.get());
     OmniboxPositionBrowserAgent::CreateForBrowser(browser_.get());
+    AutocompleteBrowserAgent::CreateForBrowser(browser_.get());
     BrowserViewVisibilityNotifierBrowserAgent::CreateForBrowser(browser_.get());
     // FullscreenController depends on ToolbarsSizeBrowserAgent, so the agent
     // must be created first. Please maintain this order.
diff --git a/ios/chrome/browser/composebox/coordinator/composebox_input_plate_mediator.mm b/ios/chrome/browser/composebox/coordinator/composebox_input_plate_mediator.mm
index 7712396..72fcea4 100644
--- a/ios/chrome/browser/composebox/coordinator/composebox_input_plate_mediator.mm
+++ b/ios/chrome/browser/composebox/coordinator/composebox_input_plate_mediator.mm
@@ -45,6 +45,7 @@
 #import "ios/chrome/browser/composebox/public/composebox_input_plate_controls.h"
 #import "ios/chrome/browser/composebox/public/features.h"
 #import "ios/chrome/browser/composebox/ui/composebox_input_item.h"
+#import "ios/chrome/browser/composebox/ui/composebox_input_item_collection.h"
 #import "ios/chrome/browser/composebox/ui/composebox_metrics_recorder.h"
 #import "ios/chrome/browser/favicon/model/favicon_loader.h"
 #import "ios/chrome/browser/intelligence/persist_tab_context/model/persist_tab_context_browser_agent.h"
@@ -139,12 +140,14 @@
 
 }  // namespace
 
-@interface ComposeboxInputPlateMediator () <SearchEngineObserving>
+@interface ComposeboxInputPlateMediator () <
+    SearchEngineObserving,
+    ComposeboxInputItemCollectionDelegate>
 @end
 
 @implementation ComposeboxInputPlateMediator {
   // The ordered list of items for display.
-  NSMutableArray<ComposeboxInputItem*>* _items;
+  ComposeboxInputItemCollection* _items;
   // The C++ session handle for this feature.
   std::unique_ptr<contextual_search::ContextualSearchSessionHandle>
       _contextualSearchSession;
@@ -208,7 +211,9 @@
                   (AimEligibilityService*)aimEligibilityService {
   self = [super init];
   if (self) {
-    _items = [NSMutableArray array];
+    _items = [[ComposeboxInputItemCollection alloc]
+        initWithAttachmentLimit:kAttachmentLimit];
+    _items.delegate = self;
     _contextualSearchSession = std::move(contextualSearchSession);
     _contextualSearchSession->NotifySessionStarted();
     CHECK(_contextualSearchSession->GetController());
@@ -269,7 +274,7 @@
 
   BOOL unableToLoadUIImage =
       ![itemProvider canLoadObjectOfClass:[UIImage class]];
-  BOOL assetAlreadyLoaded = [self assetAlreadyLoaded:assetID];
+  BOOL assetAlreadyLoaded = [_items assetAlreadyLoaded:assetID];
   if (unableToLoadUIImage || assetAlreadyLoaded) {
     return;
   }
@@ -278,8 +283,7 @@
       initWithComposeboxInputItemType:ComposeboxInputItemType::
                                           kComposeboxInputItemTypeImage
                               assetID:assetID];
-  [_items addObject:item];
-  [self updateConsumerItems];
+  [_items addItem:item];
   __block base::UnguessableToken identifier = item.identifier;
 
   __weak __typeof(self) weakSelf = self;
@@ -332,7 +336,7 @@
 - (void)processPDFFileURL:(GURL)PDFFileURL {
   DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
   NSString* assetID = base::SysUTF8ToNSString(PDFFileURL.spec());
-  if ([self assetAlreadyLoaded:assetID]) {
+  if ([_items assetAlreadyLoaded:assetID]) {
     return;
   }
 
@@ -352,8 +356,7 @@
                                           kComposeboxInputItemTypeFile
                               assetID:assetID];
   item.title = base::SysUTF8ToNSString(PDFFileURL.ExtractFileName());
-  [_items addObject:item];
-  [self updateConsumerItems];
+  [_items addItem:item];
   base::UnguessableToken identifier = item.identifier;
 
   // Read the data in the background then call `onDataReadForItem`.
@@ -369,14 +372,13 @@
 }
 
 - (BOOL)canAddMoreAttachments {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
-  return _items.count < kAttachmentLimit;
+  return _items.canAddMoreAttachments;
 }
 
 - (NSUInteger)maxNumberOfGalleryItemsAllowed {
   DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
 
-  NSUInteger availableSlots = kAttachmentLimit - _items.count;
+  NSUInteger availableSlots = _items.availableSlots;
   switch (_modeHolder.mode) {
     case ComposeboxMode::kRegularSearch:
     case ComposeboxMode::kAIM: {
@@ -386,15 +388,7 @@
     case ComposeboxMode::kImageGeneration: {
       // For ImageGeneration, allow 1 image if no images are present, otherwise
       // 0.
-      BOOL hasImage = NO;
-      for (ComposeboxInputItem* item in _items) {
-        if (item.type ==
-            ComposeboxInputItemType::kComposeboxInputItemTypeImage) {
-          hasImage = YES;
-          break;
-        }
-      }
-      return hasImage ? 0 : MIN(availableSlots, 1);
+      return _items.hasImage ? 0 : MIN(availableSlots, 1);
     }
   }
 }
@@ -403,19 +397,16 @@
 
 - (void)removeItem:(ComposeboxInputItem*)item {
   DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
-  [_items removeObject:item];
+  [_items removeItem:item];
 
   if (_contextualSearchSession) {
     _contextualSearchSession->DeleteFile(item.serverToken);
     [self reloadSuggestions];
   }
 
-  if (base::FeatureList::IsEnabled(kComposeboxAutoattachTab) &&
-      _items.count == 0) {
+  if (base::FeatureList::IsEnabled(kComposeboxAutoattachTab) && _items.empty) {
     _modeHolder.mode = ComposeboxMode::kRegularSearch;
   }
-
-  [self updateConsumerItems];
 }
 
 - (void)sendText:(NSString*)text {
@@ -463,8 +454,7 @@
       if (_contextualSearchSession) {
         _contextualSearchSession->ClearFiles();
       }
-      [_items removeAllObjects];
-      [self updateConsumerItems];
+      [_items clearItems];
       break;
     case ComposeboxMode::kAIM:
       break;
@@ -482,7 +472,7 @@
 
 - (std::set<web::WebStateID>)webStateIDsForAttachedTabs {
   std::set<web::WebStateID> webStateIDs;
-  for (ComposeboxInputItem* item in _items) {
+  for (ComposeboxInputItem* item in _items.containedItems) {
     web::WebStateID webStateID = _latestTabSelectionMapping[item.identifier];
     if (webStateID.valid()) {
       webStateIDs.insert(webStateID);
@@ -493,13 +483,7 @@
 }
 
 - (NSUInteger)nonTabAttachmentCount {
-  NSUInteger result = 0;
-  for (ComposeboxInputItem* item in _items) {
-    if (item.type != ComposeboxInputItemType::kComposeboxInputItemTypeTab) {
-      result++;
-    }
-  }
-  return result;
+  return _items.nonTabAttachmentCount;
 }
 
 - (void)attachSelectedTabsWithWebStateIDs:
@@ -562,7 +546,7 @@
 }
 
 - (void)removeDeselectedIDs:(std::set<web::WebStateID>)deselectedIDs {
-  NSArray<ComposeboxInputItem*>* items = [_items copy];
+  NSArray<ComposeboxInputItem*>* items = _items.containedItems;
   for (ComposeboxInputItem* item in items) {
     web::WebStateID webStateID = _latestTabSelectionMapping[item.identifier];
     if (webStateID.valid() && deselectedIDs.contains(webStateID)) {
@@ -579,12 +563,10 @@
       initWithComposeboxInputItemType:ComposeboxInputItemType::
                                           kComposeboxInputItemTypeTab];
   item.title = base::SysUTF16ToNSString(webState->GetTitle());
-  [_items addObject:item];
   base::UnguessableToken identifier = item.identifier;
   _latestTabSelectionMapping[identifier] = webState->GetUniqueIdentifier();
 
-  [self updateConsumerItems];
-  [self updateConsumerActionsState];
+  [_items addItem:item];
 
   if (_faviconLoader) {
     __weak __typeof(self) weakSelf = self;
@@ -715,7 +697,7 @@
                 inputData:
                     (std::unique_ptr<lens::ContextualInputData>)inputData {
   DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
-  ComposeboxInputItem* item = [self itemForIdentifier:identifier];
+  ComposeboxInputItem* item = [_items itemForIdentifier:identifier];
   if (item) {
     item.serverToken = serverToken;
   }
@@ -737,7 +719,7 @@
 - (void)onFileContextAdded:(base::UnguessableToken)serverToken
              forIdentifier:(base::UnguessableToken)identifier {
   DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
-  ComposeboxInputItem* item = [self itemForIdentifier:identifier];
+  ComposeboxInputItem* item = [_items itemForIdentifier:identifier];
   if (item) {
     item.serverToken = serverToken;
   }
@@ -767,7 +749,7 @@
 
 - (void)attachCurrentTabContent {
   DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
-  if (![self canAddMoreAttachments]) {
+  if (!_items.canAddMoreAttachments) {
     [self.delegate showAttachmentLimitError];
     return;
   }
@@ -794,7 +776,7 @@
                                       contextual_search::FileUploadErrorType>&)
                                       errorType {
   DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
-  ComposeboxInputItem* item = [self itemForServerToken:fileToken];
+  ComposeboxInputItem* item = [_items itemForServerToken:fileToken];
   if (!item) {
     return;
   }
@@ -832,11 +814,11 @@
 
 // Reloads the displayed suggestions based on the attachments/modeHolder.
 - (void)reloadSuggestions {
-  BOOL shouldRestartAutocomplete = (_items.count == 0);
+  BOOL shouldRestartAutocomplete = _items.empty;
 
   if (_items.count == 1) {
     shouldRestartAutocomplete = YES;
-    if (_items[0].type ==
+    if (_items.firstItem.type ==
         ComposeboxInputItemType::kComposeboxInputItemTypeImage) {
       shouldRestartAutocomplete =
           IsComposeboxFetchContextualSuggestionsForImageEnabled();
@@ -857,7 +839,7 @@
   ComposeboxInputItem* imageToKeep = nil;
 
   // Find one image to keep.
-  for (ComposeboxInputItem* item in _items) {
+  for (ComposeboxInputItem* item in _items.containedItems) {
     if (item.type == ComposeboxInputItemType::kComposeboxInputItemTypeImage &&
         !imageToKeep) {
       imageToKeep = item;
@@ -872,7 +854,7 @@
   }
 
   // Find items to remove from the backend.
-  for (ComposeboxInputItem* item in _items) {
+  for (ComposeboxInputItem* item in _items.containedItems) {
     if (![itemsToKeep containsObject:item]) {
       if (_contextualSearchSession) {
         _contextualSearchSession->DeleteFile(item.serverToken);
@@ -880,16 +862,14 @@
     }
   }
 
-  _items = itemsToKeep;
-
-  [self updateConsumerItems];
+  [_items replaceWithItems:itemsToKeep];
 }
 
 // Handles the loaded preview `image` for the item with the given `identifier`.
 - (void)didLoadPreviewImage:(UIImage*)previewImage
       forItemWithIdentifier:(base::UnguessableToken)identifier {
   DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
-  ComposeboxInputItem* item = [self itemForIdentifier:identifier];
+  ComposeboxInputItem* item = [_items itemForIdentifier:identifier];
   if (!item) {
     return;
   }
@@ -906,7 +886,7 @@
 - (void)didLoadFaviconIcon:(UIImage*)faviconImage
      forItemWithIdentifier:(base::UnguessableToken)identifier {
   DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
-  ComposeboxInputItem* item = [self itemForIdentifier:identifier];
+  ComposeboxInputItem* item = [_items itemForIdentifier:identifier];
   if (!item) {
     return;
   }
@@ -923,7 +903,7 @@
 - (void)didLoadFullImage:(UIImage*)image
     forItemWithIdentifier:(base::UnguessableToken)identifier {
   DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
-  ComposeboxInputItem* item = [self itemForIdentifier:identifier];
+  ComposeboxInputItem* item = [_items itemForIdentifier:identifier];
   if (!item) {
     return;
   }
@@ -949,7 +929,7 @@
 - (void)didFinishSimulatedLoadForImage:(UIImage*)image
                         itemIdentifier:(base::UnguessableToken)identifier {
   DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
-  ComposeboxInputItem* item = [self itemForIdentifier:identifier];
+  ComposeboxInputItem* item = [_items itemForIdentifier:identifier];
   if (!item) {
     return;
   }
@@ -989,7 +969,7 @@
 - (void)uploadImage:(UIImage*)image
      itemIdentifier:(base::UnguessableToken)identifier {
   DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
-  ComposeboxInputItem* item = [self itemForIdentifier:identifier];
+  ComposeboxInputItem* item = [_items itemForIdentifier:identifier];
   if (!item || !_contextualSearchSession) {
     return;
   }
@@ -1012,28 +992,6 @@
                                            std::move(callback));
 }
 
-// Returns the item with the given `identifier` or nil if not found.
-- (ComposeboxInputItem*)itemForIdentifier:(base::UnguessableToken)identifier {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
-  for (ComposeboxInputItem* item in _items) {
-    if (item.identifier == identifier) {
-      return item;
-    }
-  }
-  return nil;
-}
-
-// Returns the item with the given `serverToken` or nil if not found.
-- (ComposeboxInputItem*)itemForServerToken:(base::UnguessableToken)serverToken {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
-  for (ComposeboxInputItem* item in _items) {
-    if (item.serverToken == serverToken) {
-      return item;
-    }
-  }
-  return nil;
-}
-
 // Handles uploading the context after the snapshot is generated.
 - (void)didRetrieveColorSnapshot:(UIImage*)image
                        inputData:(std::unique_ptr<lens::ContextualInputData>)
@@ -1057,7 +1015,7 @@
                                 fromURL:(GURL)url
                                withData:(NSData*)data {
   DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
-  ComposeboxInputItem* item = [self itemForIdentifier:identifier];
+  ComposeboxInputItem* item = [_items itemForIdentifier:identifier];
   if (!item) {
     return;
   }
@@ -1095,19 +1053,6 @@
       }));
 }
 
-- (BOOL)assetAlreadyLoaded:(NSString*)assetID {
-  if (!assetID) {
-    return NO;
-  }
-  for (ComposeboxInputItem* item in _items) {
-    if ([item.assetID isEqualToString:assetID]) {
-      return YES;
-    }
-  }
-
-  return NO;
-}
-
 - (BOOL)isEligibleToAIM {
   if (!_aimEligibilityService) {
     return NO;
@@ -1196,12 +1141,12 @@
 
 - (void)handleFailedAttachment:(base::UnguessableToken)identifier {
   [self.delegate showSnackbarForItemUploadDidFail];
-  [self removeItem:[self itemForIdentifier:identifier]];
+  [self removeItem:[_items itemForIdentifier:identifier]];
 }
 
 - (void)updateButtonsVisibility {
   BOOL compactMode = [self compactModeRequired];
-  BOOL hasAttachments = _items.count > 0;
+  BOOL hasAttachments = !_items.empty;
   BOOL hasContent = hasAttachments || _hasText;
   BOOL dseGoogle = [self isDSEGoogle];
   BOOL eligibleToAIM = [self isEligibleToAIM];
@@ -1268,14 +1213,7 @@
 
 /// Updates the consumer actions enabled/disable state.
 - (void)updateConsumerActionsState {
-  BOOL hasTabOrFile = NO;
-  for (ComposeboxInputItem* item in _items) {
-    if (item.type == ComposeboxInputItemType::kComposeboxInputItemTypeTab ||
-        item.type == ComposeboxInputItemType::kComposeboxInputItemTypeFile) {
-      hasTabOrFile = YES;
-      break;
-    }
-  }
+  BOOL hasTabOrFile = _items.hasTabOrFile;
   [self.consumer disableCreateImageActions:hasTabOrFile];
 
   BOOL isImageCreation = _modeHolder.mode == ComposeboxMode::kImageGeneration;
@@ -1289,12 +1227,12 @@
 /// Updates the consumer items and maybe trigger AIM.
 - (void)updateConsumerItems {
   DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
-  [self.consumer setItems:_items];
+  [self.consumer setItems:_items.containedItems];
   [self updateOptionToAttachCurrentTab];
   [self updateConsumerActionsState];
   [self updateButtonsVisibility];
 
-  if (_items.count > 0 && [_modeHolder isRegularSearch]) {
+  if (!_items.empty && [_modeHolder isRegularSearch]) {
     // AI mode is implicitly enabled by items attachment.
     [self.metricsRecorder
         recordAiModeActivationSource:AiModeActivationSource::kImplicit];
@@ -1335,4 +1273,9 @@
   _isUpdatingCompactMode = NO;
 }
 
+- (void)composeboxInputItemCollectionDidUpdateItems:
+    (ComposeboxInputItemCollection*)composeboxInputItemCollection {
+  [self updateConsumerItems];
+}
+
 @end
diff --git a/ios/chrome/browser/composebox/coordinator/composebox_omnibox_client.mm b/ios/chrome/browser/composebox/coordinator/composebox_omnibox_client.mm
index 59a1648..44a04b3 100644
--- a/ios/chrome/browser/composebox/coordinator/composebox_omnibox_client.mm
+++ b/ios/chrome/browser/composebox/coordinator/composebox_omnibox_client.mm
@@ -19,10 +19,9 @@
 #import "components/omnibox/browser/omnibox_log.h"
 #import "components/omnibox/common/omnibox_features.h"
 #import "components/search_engines/template_url_service.h"
+#import "ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.h"
 #import "ios/chrome/browser/autocomplete/model/autocomplete_classifier_factory.h"
 #import "ios/chrome/browser/autocomplete/model/autocomplete_provider_client_impl.h"
-#import "ios/chrome/browser/autocomplete/model/autocomplete_service.h"
-#import "ios/chrome/browser/autocomplete/model/autocomplete_service_factory.h"
 #import "ios/chrome/browser/autocomplete/model/omnibox_shortcuts_helper.h"
 #import "ios/chrome/browser/bookmarks/model/bookmark_model_factory.h"
 #import "ios/chrome/browser/bookmarks/model/bookmarks_utils.h"
@@ -331,10 +330,10 @@
     const std::u16string& text,
     const AutocompleteMatch& match,
     const AutocompleteMatch& alternative_nav_match) {
-  AutocompleteService* autocomplete_service =
-      AutocompleteServiceFactory::GetForProfile(profile_);
+  AutocompleteBrowserAgent* autocomplete_browser_agent =
+      AutocompleteBrowserAgent::FromBrowser(browser_);
   OmniboxShortcutsHelper* shortcuts_helper =
-      autocomplete_service->GetOmniboxShortcutsHelper(
+      autocomplete_browser_agent->GetOmniboxShortcutsHelper(
           OmniboxPresentationContext::kComposebox);
   if (shortcuts_helper) {
     shortcuts_helper->OnAutocompleteAccept(text, match,
diff --git a/ios/chrome/browser/composebox/ui/BUILD.gn b/ios/chrome/browser/composebox/ui/BUILD.gn
index 067c039..671919d 100644
--- a/ios/chrome/browser/composebox/ui/BUILD.gn
+++ b/ios/chrome/browser/composebox/ui/BUILD.gn
@@ -11,6 +11,8 @@
     "composebox_input_item.mm",
     "composebox_input_item_cell.h",
     "composebox_input_item_cell.mm",
+    "composebox_input_item_collection.h",
+    "composebox_input_item_collection.mm",
     "composebox_input_item_view.h",
     "composebox_input_item_view.mm",
     "composebox_input_plate_consumer.h",
diff --git a/ios/chrome/browser/composebox/ui/composebox_input_item_collection.h b/ios/chrome/browser/composebox/ui/composebox_input_item_collection.h
new file mode 100644
index 0000000..082fd62
--- /dev/null
+++ b/ios/chrome/browser/composebox/ui/composebox_input_item_collection.h
@@ -0,0 +1,87 @@
+// 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_COMPOSEBOX_UI_COMPOSEBOX_INPUT_ITEM_COLLECTION_H_
+#define IOS_CHROME_BROWSER_COMPOSEBOX_UI_COMPOSEBOX_INPUT_ITEM_COLLECTION_H_
+
+#import <UIKit/UIKit.h>
+
+namespace base {
+class UnguessableToken;
+}
+
+@class ComposeboxInputItem;
+@class ComposeboxInputItemCollection;
+
+// Delegate for a `ComposeboxInputItemCollection`.
+@protocol ComposeboxInputItemCollectionDelegate <NSObject>
+
+// Informs the caller that the collection was updated.
+- (void)composeboxInputItemCollectionDidUpdateItems:
+    (ComposeboxInputItemCollection*)composeboxInputItemCollection;
+
+@end
+
+// A ordered container for `ComposeboxInputItem`, modeling the attachments
+// carousel in the inputplate.
+@interface ComposeboxInputItemCollection : NSObject
+
+// Creates a new input item collection with the given attachment limit.
+- (instancetype)initWithAttachmentLimit:(size_t)attachmentLimit;
+
+// The delegate for this instance.
+@property(nonatomic, weak) id<ComposeboxInputItemCollectionDelegate> delegate;
+
+// The contained items in this collection.
+@property(nonatomic, readonly, copy)
+    NSArray<ComposeboxInputItem*>* containedItems;
+
+// The number of objects in the array.
+@property(nonatomic, readonly) size_t count;
+
+// Whether the collection is empty.
+@property(nonatomic, readonly, getter=isEmpty) BOOL empty;
+
+// Whether the collection has at least one image added.
+@property(nonatomic, readonly) BOOL hasImage;
+
+// Whether the collection contains a tab or a file attachment.
+@property(nonatomic, readonly) BOOL hasTabOrFile;
+
+// Whether more attachment can be added.
+@property(nonatomic, readonly) BOOL canAddMoreAttachments;
+
+// The available slots in this collection.
+@property(nonatomic, readonly) size_t availableSlots;
+
+// The number of non tab attachments.
+@property(nonatomic, readonly) size_t nonTabAttachmentCount;
+
+// The first item in this collection, or `nil` if not present.
+@property(nonatomic, readonly) ComposeboxInputItem* firstItem;
+
+// Adds an items to the collection.
+- (void)addItem:(ComposeboxInputItem*)item;
+
+// Replaces the items in the collection with the given updated items.
+- (void)replaceWithItems:(NSArray<ComposeboxInputItem*>*)updatedItems;
+
+// Removes an item from the collection.
+- (void)removeItem:(ComposeboxInputItem*)item;
+
+// Removes all items from the collection.
+- (void)clearItems;
+
+// Returns the item with the given `identifier` or nil if not found.
+- (ComposeboxInputItem*)itemForIdentifier:(base::UnguessableToken)identifier;
+
+// Returns the item with the given `serverToken` or nil if not found.
+- (ComposeboxInputItem*)itemForServerToken:(base::UnguessableToken)serverToken;
+
+// Whether the given asset identified by the `assetID` was loaded.
+- (BOOL)assetAlreadyLoaded:(NSString*)assetID;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_COMPOSEBOX_UI_COMPOSEBOX_INPUT_ITEM_COLLECTION_H_
diff --git a/ios/chrome/browser/composebox/ui/composebox_input_item_collection.mm b/ios/chrome/browser/composebox/ui/composebox_input_item_collection.mm
new file mode 100644
index 0000000..80ff11e
--- /dev/null
+++ b/ios/chrome/browser/composebox/ui/composebox_input_item_collection.mm
@@ -0,0 +1,153 @@
+// 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/composebox/ui/composebox_input_item_collection.h"
+
+#import "base/check.h"
+#import "base/sequence_checker.h"
+#import "base/unguessable_token.h"
+#import "ios/chrome/browser/composebox/ui/composebox_input_item.h"
+
+@implementation ComposeboxInputItemCollection {
+  // Check that the different methods are called from the correct sequence, as
+  // this class defers work via PostTask APIs.
+  SEQUENCE_CHECKER(_sequenceChecker);
+
+  // The ordered list of items for display.
+  NSMutableArray<ComposeboxInputItem*>* _containedItems;
+
+  // The limit of attachments.
+  size_t _attachmentLimit;
+}
+
+- (instancetype)initWithAttachmentLimit:(size_t)attachmentLimit {
+  self = [super init];
+  if (self) {
+    _containedItems = [[NSMutableArray alloc] init];
+    _attachmentLimit = attachmentLimit;
+  }
+
+  return self;
+}
+
+#pragma mark - Public properties
+
+- (size_t)count {
+  return _containedItems.count;
+}
+
+- (BOOL)isEmpty {
+  return self.count == 0;
+}
+
+- (BOOL)hasImage {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
+  for (ComposeboxInputItem* item in _containedItems) {
+    if (item.type == ComposeboxInputItemType::kComposeboxInputItemTypeImage) {
+      return YES;
+    }
+  }
+
+  return NO;
+}
+
+- (BOOL)hasTabOrFile {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
+  for (ComposeboxInputItem* item in _containedItems) {
+    if (item.type == ComposeboxInputItemType::kComposeboxInputItemTypeTab ||
+        item.type == ComposeboxInputItemType::kComposeboxInputItemTypeFile) {
+      return YES;
+    }
+  }
+
+  return NO;
+}
+
+- (BOOL)canAddMoreAttachments {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
+  return self.count < _attachmentLimit;
+}
+
+- (size_t)availableSlots {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
+  return _attachmentLimit - self.count;
+}
+
+- (size_t)nonTabAttachmentCount {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
+  NSUInteger result = 0;
+  for (ComposeboxInputItem* item in _containedItems) {
+    if (item.type != ComposeboxInputItemType::kComposeboxInputItemTypeTab) {
+      result++;
+    }
+  }
+  return result;
+}
+
+- (ComposeboxInputItem*)firstItem {
+  if (self.empty) {
+    return nil;
+  }
+
+  return _containedItems[0];
+}
+
+#pragma mark - Public methods
+
+- (void)addItem:(ComposeboxInputItem*)item {
+  [_containedItems addObject:item];
+  [_delegate composeboxInputItemCollectionDidUpdateItems:self];
+}
+
+- (void)replaceWithItems:(NSArray<ComposeboxInputItem*>*)updatedItems {
+  _containedItems = [updatedItems copy];
+  [_delegate composeboxInputItemCollectionDidUpdateItems:self];
+}
+
+- (void)removeItem:(ComposeboxInputItem*)item {
+  [_containedItems removeObject:item];
+  [_delegate composeboxInputItemCollectionDidUpdateItems:self];
+}
+
+- (void)clearItems {
+  [_containedItems removeAllObjects];
+  [_delegate composeboxInputItemCollectionDidUpdateItems:self];
+}
+
+- (ComposeboxInputItem*)itemForIdentifier:(base::UnguessableToken)identifier {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
+  for (ComposeboxInputItem* item in _containedItems) {
+    if (item.identifier == identifier) {
+      return item;
+    }
+  }
+  return nil;
+}
+
+- (ComposeboxInputItem*)itemForServerToken:(base::UnguessableToken)serverToken {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
+  for (ComposeboxInputItem* item in _containedItems) {
+    if (item.serverToken == serverToken) {
+      return item;
+    }
+  }
+  return nil;
+}
+
+- (BOOL)assetAlreadyLoaded:(NSString*)assetID {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
+
+  if (!assetID) {
+    return NO;
+  }
+  for (ComposeboxInputItem* item in _containedItems) {
+    if ([item.assetID isEqualToString:assetID]) {
+      return YES;
+    }
+  }
+
+  return NO;
+}
+
+@end
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/content_suggestions_coordinator.mm b/ios/chrome/browser/content_suggestions/ui_bundled/content_suggestions_coordinator.mm
index 6b787e0..2696c34 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/content_suggestions_coordinator.mm
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/content_suggestions_coordinator.mm
@@ -362,34 +362,31 @@
   [moduleMediators addObject:_shortcutsMediator];
   self.contentSuggestionsMediator.shortcutsMediator = _shortcutsMediator;
 
-  if (IsTabResumptionEnabled()) {
-    _tabResumptionMediator = [[TabResumptionMediator alloc]
-              initWithLocalState:GetApplicationContext()->GetLocalState()
-                     prefService:prefs
-                 identityManager:identityManager
-                         browser:self.browser
-        optimizationGuideService:OptimizationGuideServiceFactory::GetForProfile(
-                                     profile)
-          impressionLimitService:
-              base::FeatureList::IsEnabled(commerce::kShopCardImpressionLimits)
-                  ? ImpressionLimitServiceFactory::GetForProfile(profile)
-                  : nil
-                 shoppingService:commerce::ShoppingServiceFactory::
-                                     GetForProfile(profile)
-                   bookmarkModel:ios::BookmarkModelFactory::GetForProfile(
-                                     profile)
-         pushNotificationService:GetApplicationContext()
-                                     ->GetPushNotificationService()
-           authenticationService:self.authService];
-    _tabResumptionMediator.NTPActionsDelegate = self.NTPActionsDelegate;
-    _tabResumptionMediator.contentSuggestionsMetricsRecorder =
-        self.contentSuggestionsMetricsRecorder;
-    _tabResumptionMediator.dispatcher = static_cast<
-        id<ApplicationCommands, PriceTrackedItemsCommands, SnackbarCommands>>(
-        self.browser->GetCommandDispatcher());
+  _tabResumptionMediator = [[TabResumptionMediator alloc]
+            initWithLocalState:GetApplicationContext()->GetLocalState()
+                   prefService:prefs
+               identityManager:identityManager
+                       browser:self.browser
+      optimizationGuideService:OptimizationGuideServiceFactory::GetForProfile(
+                                   profile)
+        impressionLimitService:
+            base::FeatureList::IsEnabled(commerce::kShopCardImpressionLimits)
+                ? ImpressionLimitServiceFactory::GetForProfile(profile)
+                : nil
+               shoppingService:commerce::ShoppingServiceFactory::GetForProfile(
+                                   profile)
+                 bookmarkModel:ios::BookmarkModelFactory::GetForProfile(profile)
+       pushNotificationService:GetApplicationContext()
+                                   ->GetPushNotificationService()
+         authenticationService:self.authService];
+  _tabResumptionMediator.NTPActionsDelegate = self.NTPActionsDelegate;
+  _tabResumptionMediator.contentSuggestionsMetricsRecorder =
+      self.contentSuggestionsMetricsRecorder;
+  _tabResumptionMediator.dispatcher = static_cast<
+      id<ApplicationCommands, PriceTrackedItemsCommands, SnackbarCommands>>(
+      self.browser->GetCommandDispatcher());
 
-    [moduleMediators addObject:_tabResumptionMediator];
-  }
+  [moduleMediators addObject:_tabResumptionMediator];
   if (IsPriceTrackingPromoCardEnabled(shoppingService, self.authService,
                                       prefs)) {
     _priceTrackingPromoMediator = [[PriceTrackingPromoMediator alloc]
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack/coordinator/magic_stack_ranking_model.mm b/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack/coordinator/magic_stack_ranking_model.mm
index d60c024..c2313c62 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack/coordinator/magic_stack_ranking_model.mm
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack/coordinator/magic_stack_ranking_model.mm
@@ -387,7 +387,6 @@
 #pragma mark - TabResumptionMediatorDelegate
 
 - (void)tabResumptionMediatorDidReceiveItem {
-  CHECK(IsTabResumptionEnabled());
   if (tab_resumption_prefs::IsTabResumptionDisabled(_prefService)) {
     return;
   }
@@ -1046,8 +1045,7 @@
 
 // Returns YES if the tab resumption module should added into the Magic Stack.
 - (BOOL)shouldShowTabResumption {
-  return IsTabResumptionEnabled() &&
-         !tab_resumption_prefs::IsTabResumptionDisabled(_prefService) &&
+  return !tab_resumption_prefs::IsTabResumptionDisabled(_prefService) &&
          _tabResumptionMediator.itemConfig;
 }
 
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/tab_resumption/coordinator/tab_resumption_mediator.mm b/ios/chrome/browser/content_suggestions/ui_bundled/tab_resumption/coordinator/tab_resumption_mediator.mm
index dd4c50f..5a9ef72 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/tab_resumption/coordinator/tab_resumption_mediator.mm
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/tab_resumption/coordinator/tab_resumption_mediator.mm
@@ -110,6 +110,21 @@
 
 namespace {
 
+// A command line flag to override the default sync threshold.
+const char kTabResumptionThresholdParameter[] = "tab-resumption-sync-threshold";
+
+const base::TimeDelta TabResumptionForXDevicesTimeThreshold() {
+  const base::CommandLine* command_line =
+      base::CommandLine::ForCurrentProcess();
+  std::string paramter =
+      command_line->GetSwitchValueASCII(kTabResumptionThresholdParameter);
+  int threshold = 0;
+  if (!base::StringToInt(kTabResumptionThresholdParameter, &threshold)) {
+    threshold = 12 * 3600;
+  }
+  return base::Seconds(threshold);
+}
+
 // Whether the item should be displayed immediately (before fetching an image).
 bool ShouldShowItemImmediately() {
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -422,7 +437,6 @@
        authenticationService:(AuthenticationService*)authenticationService {
   self = [super init];
   if (self) {
-    CHECK(IsTabResumptionEnabled());
     _profilePrefs = prefService;
     _browser = browser;
     _tabId = SessionID::InvalidValue();
@@ -947,8 +961,6 @@
   } else {
     if (item.itemType == kMostRecentTab) {
       [self fetchSnapshotForItem:item];
-    } else {
-      [self fetchSalientImageForItem:item];
     }
   }
   [self fetchFaviconForItem:item];
@@ -1008,8 +1020,8 @@
 
 // Fetches the snapshot of the tab showing `item`.
 - (void)fetchSnapshotForItem:(TabResumptionItem*)item {
-  if (!IsTabResumptionImagesThumbnailsEnabled() || !item.localWebState) {
-    return [self fetchSalientImageForItem:item];
+  if (!item.localWebState) {
+    return;
   }
 
   web::WebState* webState = item.localWebState.get();
@@ -1028,35 +1040,18 @@
                                    [weakSelf snapshotFetched:image
                                                      forItem:item];
                                  });
-    return;
   }
-  return [self fetchSalientImageForItem:item];
 }
 
 // The snapshot of the tab showing `item` was fetched.
 - (void)snapshotFetched:(UIImage*)image forItem:(TabResumptionItem*)item {
   if (!image) {
-    return [self fetchSalientImageForItem:item];
+    return;
   }
   item.contentImage = image;
   [self showItem:item];
 }
 
-// Fetches the salient image for `item`.
-- (void)fetchSalientImageForItem:(TabResumptionItem*)item {
-  if (!IsTabResumptionImagesSalientEnabled() || !_pageImageService) {
-    return;
-  }
-  __weak TabResumptionMediator* weakSelf = self;
-  page_image_service::mojom::Options options;
-  options.optimization_guide_images = true;
-  options.suggest_images = false;
-  _pageImageService->FetchImageFor(
-      page_image_service::mojom::ClientId::NtpTabResumption, item.tabURL,
-      options, base::BindOnce(^(const GURL& URL) {
-        [weakSelf salientImageURLReceived:URL forItem:item updateImage:NO];
-      }));
-}
 
 // The URL for the salient image has been received. Download the image if it
 // is valid or fallbacks to favicon.
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/tab_resumption/ui/tab_resumption_view.mm b/ios/chrome/browser/content_suggestions/ui_bundled/tab_resumption/ui/tab_resumption_view.mm
index c3a0c6e..741532f1 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/tab_resumption/ui/tab_resumption_view.mm
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/tab_resumption/ui/tab_resumption_view.mm
@@ -29,10 +29,10 @@
 
 const CGFloat kImageContainerCornerRadius = 12.0;
 
-// Image container with Salient image constants
-const CGFloat kImageSalientContainerSize = 72.0;
+// Image container with Content image constants
+const CGFloat kImageContentContainerSize = 72.0;
 
-// Image container without Salient image constants
+// Image container without Content image constants
 const CGFloat kImageEmptyContainerSize = 56.0;
 
 // Center Favicon constants.
@@ -61,7 +61,7 @@
 const CGFloat kPriceDropOverlayStartAlpha = 0.0;
 const CGFloat kPriceDropOverlayEndAlpha = 0.14;
 
-// Adds the fallback image that should be used if there is no salient nor
+// Adds the fallback image that should be used if there is no content nor
 // favicon image.
 void SetFallbackImageToImageView(UIImageView* image_view,
                                  UIView* background_view,
@@ -232,7 +232,7 @@
 }
 
 // Configures and returns the leading UIView that may contain the favicon image.
-- (UIView*)configuredFaviconViewWithSalientImage:(BOOL)hasSalientImage {
+- (UIView*)configuredFaviconViewWithContentImage:(BOOL)hasContentImage {
   UIView* faviconBackgroundView = [[UIView alloc] init];
   faviconBackgroundView.translatesAutoresizingMaskIntoConstraints = NO;
   faviconBackgroundView.backgroundColor = UIColor.whiteColor;
@@ -242,7 +242,7 @@
   CGFloat faviconCornerRadius;
   CGFloat faviconBackgoundSize;
   CGFloat faviconBackgroundCornerRadius;
-  if (hasSalientImage) {
+  if (hasContentImage) {
     faviconSize = kCornerFaviconSize;
     faviconCornerRadius = kCornerFaviconCornerRadius;
     faviconBackgoundSize = kCornerFaviconBackgroundSize;
@@ -278,7 +278,7 @@
   ]];
   AddSameCenterConstraints(faviconBackgroundView, faviconImageView);
 
-  if (hasSalientImage) {
+  if (hasContentImage) {
     UIRectCorner bottomTrail = UIRectCornerBottomRight;
     if (base::i18n::IsRTL()) {
       bottomTrail = UIRectCornerBottomLeft;
@@ -299,9 +299,9 @@
   return faviconBackgroundView;
 }
 
-// Configures and returns the leading UIView that may contain the Salient image.
-- (UIView*)configuredSalientImageViewWithSize:(CGFloat)containerSize {
-  UIImageView* salientView = [[UIImageView alloc] init];
+// Configures and returns the leading UIView that may contain the Content image.
+- (UIView*)configuredContentImageViewWithSize:(CGFloat)containerSize {
+  UIImageView* contentImageView = [[UIImageView alloc] init];
 
   // Compute the size of the image.
   CGFloat width = _item.contentImage.size.width;
@@ -314,7 +314,7 @@
     width = containerSize;
   }
 
-  // Resize the salient image.
+  // Resize the content image.
   UIGraphicsImageRendererFormat* format =
       [UIGraphicsImageRendererFormat preferredFormat];
   format.scale = 0.0;
@@ -326,11 +326,11 @@
       [renderer imageWithActions:^(UIGraphicsImageRendererContext* context) {
         [_item.contentImage drawInRect:CGRectMake(0, 0, width, height)];
       }];
-  [salientView setImage:scaledImage];
+  [contentImageView setImage:scaledImage];
 
-  salientView.translatesAutoresizingMaskIntoConstraints = NO;
+  contentImageView.translatesAutoresizingMaskIntoConstraints = NO;
 
-  salientView.contentMode = UIViewContentModeTop;
+  contentImageView.contentMode = UIViewContentModeTop;
 
   // Add a gradient overlay.
   CAGradientLayer* gradientLayer = [CAGradientLayer layer];
@@ -352,8 +352,8 @@
       static_cast<id>([UIColor colorWithWhite:0 alpha:0.2].CGColor)
     ];
   }
-  [salientView.layer insertSublayer:gradientLayer atIndex:0];
-  return salientView;
+  [contentImageView.layer insertSublayer:gradientLayer atIndex:0];
+  return contentImageView;
 }
 
 // Configures and returns the leading UIView that contains the image.
@@ -363,18 +363,16 @@
   containerView.layer.cornerRadius = kImageContainerCornerRadius;
   containerView.clipsToBounds = YES;
 
-  BOOL hasSalientImage = NO;
+  BOOL hasContentImage = NO;
   CGFloat containerSize;
   if (_item.contentImage &&
-      (IsTabResumptionImagesSalientEnabled() ||
-       IsTabResumptionImagesThumbnailsEnabled() || HasPriceDropOnTab(_item)) &&
       _item.contentImage.size.width && _item.contentImage.size.height) {
-    hasSalientImage = YES;
-    containerSize = kImageSalientContainerSize;
-    UIView* salientView =
-        [self configuredSalientImageViewWithSize:containerSize];
-    [containerView addSubview:salientView];
-    AddSameConstraints(salientView, containerView);
+    hasContentImage = YES;
+    containerSize = kImageContentContainerSize;
+    UIView* contentImageView =
+        [self configuredContentImageViewWithSize:containerSize];
+    [containerView addSubview:contentImageView];
+    AddSameConstraints(contentImageView, containerView);
   } else {
     containerView.backgroundColor = [UIColor colorNamed:kGrey100Color];
     containerSize = kImageEmptyContainerSize;
@@ -385,14 +383,14 @@
     [containerView.heightAnchor constraintEqualToConstant:containerSize],
   ]];
 
-  if (hasSalientImage && !_item.faviconImage) {
+  if (hasContentImage && !_item.faviconImage) {
     return containerView;
   }
 
   UIView* faviconView =
-      [self configuredFaviconViewWithSalientImage:hasSalientImage];
+      [self configuredFaviconViewWithContentImage:hasContentImage];
   [containerView addSubview:faviconView];
-  if (!hasSalientImage) {
+  if (!hasContentImage) {
     AddSameCenterConstraints(faviconView, containerView);
   } else {
     [NSLayoutConstraint activateConstraints:@[
diff --git a/ios/chrome/browser/data_import/public/BUILD.gn b/ios/chrome/browser/data_import/public/BUILD.gn
index c49b5b02..fcad350b 100644
--- a/ios/chrome/browser/data_import/public/BUILD.gn
+++ b/ios/chrome/browser/data_import/public/BUILD.gn
@@ -6,6 +6,8 @@
   sources = [
     "accessibility_utils.h",
     "accessibility_utils.mm",
+    "conflict_item_identifier.h",
+    "conflict_item_identifier.mm",
     "import_data_item.h",
     "import_data_item.mm",
     "import_data_item_consumer.h",
diff --git a/ios/chrome/browser/data_import/public/conflict_item_identifier.h b/ios/chrome/browser/data_import/public/conflict_item_identifier.h
new file mode 100644
index 0000000..9b41a1f918
--- /dev/null
+++ b/ios/chrome/browser/data_import/public/conflict_item_identifier.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 IOS_CHROME_BROWSER_DATA_IMPORT_PUBLIC_CONFLICT_ITEM_IDENTIFIER_H_
+#define IOS_CHROME_BROWSER_DATA_IMPORT_PUBLIC_CONFLICT_ITEM_IDENTIFIER_H_
+
+#import <Foundation/Foundation.h>
+
+enum class CredentialConflictType {
+  kPassword,
+  kPasskey,
+};
+
+// Identifier for a conflicting credential item used in
+// UITableViewDiffableDataSource of a conflict resolution screen.
+@interface ConflictItemIdentifier : NSObject
+
+@property(nonatomic, readonly) CredentialConflictType type;
+@property(nonatomic, readonly) NSUInteger index;
+
+- (instancetype)initWithType:(CredentialConflictType)type
+                       index:(NSInteger)index NS_DESIGNATED_INITIALIZER;
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_DATA_IMPORT_PUBLIC_CONFLICT_ITEM_IDENTIFIER_H_
diff --git a/ios/chrome/browser/data_import/public/conflict_item_identifier.mm b/ios/chrome/browser/data_import/public/conflict_item_identifier.mm
new file mode 100644
index 0000000..802c61fc
--- /dev/null
+++ b/ios/chrome/browser/data_import/public/conflict_item_identifier.mm
@@ -0,0 +1,42 @@
+// 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/data_import/public/conflict_item_identifier.h"
+
+#import "base/apple/foundation_util.h"
+
+@implementation ConflictItemIdentifier
+
+- (instancetype)initWithType:(CredentialConflictType)type
+                       index:(NSInteger)index {
+  self = [super init];
+  if (self) {
+    _type = type;
+    _index = index;
+  }
+  return self;
+}
+
+#pragma mark - NSObject
+
+- (BOOL)isEqual:(id)object {
+  if (self == object) {
+    return YES;
+  }
+  ConflictItemIdentifier* other =
+      base::apple::ObjCCast<ConflictItemIdentifier>(object);
+  return other && self.type == other.type && self.index == other.index;
+}
+
+- (NSUInteger)hash {
+  return (static_cast<NSUInteger>(self.type) << 31) + self.index;
+}
+
+- (NSString*)description {
+  return [NSString stringWithFormat:@"<%@: %p, type: %ld, index: %lu>",
+                                    [self class], self, (long)self.type,
+                                    (unsigned long)self.index];
+}
+
+@end
diff --git a/ios/chrome/browser/data_import/ui/data_import_credential_conflict_resolution_view_controller.mm b/ios/chrome/browser/data_import/ui/data_import_credential_conflict_resolution_view_controller.mm
index 9dc64ea3..5b2fea86 100644
--- a/ios/chrome/browser/data_import/ui/data_import_credential_conflict_resolution_view_controller.mm
+++ b/ios/chrome/browser/data_import/ui/data_import_credential_conflict_resolution_view_controller.mm
@@ -7,6 +7,7 @@
 #import "base/check_op.h"
 #import "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/data_import/public/accessibility_utils.h"
+#import "ios/chrome/browser/data_import/public/conflict_item_identifier.h"
 #import "ios/chrome/browser/data_import/public/metrics.h"
 #import "ios/chrome/browser/data_import/public/password_import_item.h"
 #import "ios/chrome/browser/data_import/ui/data_import_credential_conflict_mutator.h"
@@ -40,7 +41,8 @@
   /// at the respective index should be unmasked for display.
   NSMutableArray<NSNumber*>* _shouldUnmaskPasswordAtIndex;
   /// The data source painting each cell in the table from `_passwordConflicts`.
-  UITableViewDiffableDataSource<NSString*, NSNumber*>* _dataSource;
+  UITableViewDiffableDataSource<NSString*, ConflictItemIdentifier*>*
+      _dataSource;
   /// The "select" and "deselect" buttons.
   UIBarButtonItem* _selectButton;
   UIBarButtonItem* _deselectButton;
@@ -134,8 +136,11 @@
       DataImportCredentialConflictScreenAction::kContinue);
   NSMutableArray<NSNumber*>* passwordIdentifiers = [NSMutableArray array];
   for (NSIndexPath* indexPath in [self.tableView indexPathsForSelectedRows]) {
-    [passwordIdentifiers
-        addObject:[_dataSource itemIdentifierForIndexPath:indexPath]];
+    ConflictItemIdentifier* identifier =
+        [_dataSource itemIdentifierForIndexPath:indexPath];
+    if (identifier.type == CredentialConflictType::kPassword) {
+      [passwordIdentifiers addObject:@(identifier.index)];
+    }
   }
   [self.mutator continueToImportPasswords:passwordIdentifiers];
   [self.presentingViewController dismissViewControllerAnimated:YES
@@ -145,8 +150,12 @@
 - (void)didTapSelectionButton {
   NSUInteger totalCount = _passwordConflicts.count;
   BOOL deselect = totalCount == [self selectedItemsCount];
-  for (NSUInteger idx = 0; idx < totalCount; idx++) {
-    NSIndexPath* indexPath = [_dataSource indexPathForItemIdentifier:@(idx)];
+  NSArray<ConflictItemIdentifier*>* identifiers = [[_dataSource snapshot]
+      itemIdentifiersInSectionWithIdentifier:
+          kDataImportCredentialConflictResolutionSection];
+  for (ConflictItemIdentifier* identifier in identifiers) {
+    NSIndexPath* indexPath =
+        [_dataSource indexPathForItemIdentifier:identifier];
     if (deselect) {
       [self.tableView deselectRowAtIndexPath:indexPath animated:NO];
     } else {
@@ -180,15 +189,15 @@
 
 /// Returns the cell with the properties of the `item` displayed.
 - (UITableViewCell*)cellForIndexPath:(NSIndexPath*)indexPath
-                      itemIdentifier:(NSNumber*)identifier {
+                      itemIdentifier:(ConflictItemIdentifier*)identifier {
   /// Populate cell with information.
-  PasswordImportItem* item = _passwordConflicts[identifier.intValue];
+  PasswordImportItem* item = _passwordConflicts[identifier.index];
   UITableViewCell* cell = DequeueTableViewCell<UITableViewCell>(self.tableView);
   cell.accessibilityIdentifier =
       GetPasswordConflictResolutionTableViewCellAccessibilityIdentifier(
-          indexPath.item);
+          identifier.index);
   PasswordImportItemCellContentConfiguration* config;
-  if (_shouldUnmaskPasswordAtIndex[identifier.intValue].boolValue) {
+  if (_shouldUnmaskPasswordAtIndex[identifier.index].boolValue) {
     config = [PasswordImportItemCellContentConfiguration
         cellConfigurationForUnmaskPassword:item];
   } else {
@@ -212,8 +221,8 @@
 }
 
 /// Helper method to update the cell with `identifier`.
-- (void)updateItemWithIdentifier:(NSNumber*)identifier {
-  NSDiffableDataSourceSnapshot<NSString*, NSNumber*>* snapshot =
+- (void)updateItemWithIdentifier:(ConflictItemIdentifier*)identifier {
+  NSDiffableDataSourceSnapshot<NSString*, ConflictItemIdentifier*>* snapshot =
       [_dataSource snapshot];
   [snapshot reconfigureItemsWithIdentifiers:@[ identifier ]];
   [_dataSource applySnapshot:snapshot animatingDifferences:NO];
@@ -265,7 +274,7 @@
   __weak __typeof(self) weakSelf = self;
   UITableViewDiffableDataSourceCellProvider cellProvider = ^UITableViewCell*(
       UITableView* tableView, NSIndexPath* indexPath,
-      NSNumber* itemIdentifier) {
+      ConflictItemIdentifier* itemIdentifier) {
     CHECK_EQ(tableView, weakSelf.tableView);
     return [weakSelf cellForIndexPath:indexPath itemIdentifier:itemIdentifier];
   };
@@ -278,11 +287,17 @@
   [snapshot appendSectionsWithIdentifiers:@[
     kDataImportCredentialConflictResolutionSection
   ]];
-  NSMutableArray* indicesForPasswordConflicts = [NSMutableArray array];
+
+  NSMutableArray<ConflictItemIdentifier*>* itemIdentifiers =
+      [NSMutableArray array];
   for (NSUInteger i = 0; i < _passwordConflicts.count; i++) {
-    [indicesForPasswordConflicts addObject:@(i)];
+    [itemIdentifiers
+        addObject:[[ConflictItemIdentifier alloc]
+                      initWithType:CredentialConflictType::kPassword
+                             index:i]];
   }
-  [snapshot appendItemsWithIdentifiers:indicesForPasswordConflicts
+
+  [snapshot appendItemsWithIdentifiers:itemIdentifiers
              intoSectionWithIdentifier:
                  kDataImportCredentialConflictResolutionSection];
   [_dataSource applySnapshot:snapshot animatingDifferences:NO];
@@ -298,12 +313,13 @@
 }
 
 /// Helper method to set up the accessory view.
-- (UIView*)accessoryViewForItemIdentifier:(NSNumber*)identifier {
-  if (![[self reauthenticationModule] canAttemptReauth]) {
+- (UIView*)accessoryViewForItemIdentifier:(ConflictItemIdentifier*)identifier {
+  if (identifier.type == CredentialConflictType::kPasskey ||
+      ![[self reauthenticationModule] canAttemptReauth]) {
     return nil;
   }
   BOOL forUnmaskAction =
-      !(_shouldUnmaskPasswordAtIndex[identifier.intValue].boolValue);
+      !(_shouldUnmaskPasswordAtIndex[identifier.index].boolValue);
   UIButtonConfiguration* configuration =
       [UIButtonConfiguration plainButtonConfiguration];
   NSString* symbol_name =
@@ -333,11 +349,15 @@
 /// Reveal password if `shouldUnmask` is YES and user is authenticated to view
 /// passwords; mask password if otherwise.
 - (void)maybeUpdatePasswordMasking:(BOOL)shouldUnmask
-             forItemWithIdentifier:(NSNumber*)identifier
+             forItemWithIdentifier:(ConflictItemIdentifier*)identifier
                      authenticated:(BOOL)authenticated {
+  if (identifier.type == CredentialConflictType::kPasskey) {
+    return;
+  }
+
   if (!shouldUnmask || authenticated ||
       ![[self reauthenticationModule] canAttemptReauth]) {
-    _shouldUnmaskPasswordAtIndex[identifier.intValue] = @(shouldUnmask);
+    _shouldUnmaskPasswordAtIndex[identifier.index] = @(shouldUnmask);
     [self updateItemWithIdentifier:identifier];
     return;
   }
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index 6f1f8b5..b1354b7 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -456,18 +456,6 @@
     {"Display promo during FRE", kIOSDockingPromoDisplayedDuringFRE,
      std::size(kIOSDockingPromoDisplayedDuringFRE), nullptr}};
 
-const FeatureEntry::FeatureParam kTabResumptionImagesOnlyThumbnail[] = {
-    {kTabResumptionImagesTypes, kTabResumptionImagesTypesThumbnails}};
-const FeatureEntry::FeatureParam kTabResumptionImagesOnlySalient[] = {
-    {kTabResumptionImagesTypes, kTabResumptionImagesTypesSalient}};
-
-const FeatureEntry::FeatureVariation kTabResumptionImagesVariations[] = {
-    {"Only thumbnails", kTabResumptionImagesOnlyThumbnail,
-     std::size(kTabResumptionImagesOnlyThumbnail), nullptr},
-    {"Only salient", kTabResumptionImagesOnlySalient,
-     std::size(kTabResumptionImagesOnlySalient), nullptr},
-};
-
 // Uses int values from Lens filters ablation mode enum.
 const FeatureEntry::FeatureParam kLensFiltersAblationModeDisabled[] = {
     {kLensFiltersAblationMode, "0"}};
@@ -1872,9 +1860,6 @@
      flag_descriptions::kSpotlightNeverRetainIndexName,
      flag_descriptions::kSpotlightNeverRetainIndexDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kSpotlightNeverRetainIndex)},
-    {"tab-resumption", flag_descriptions::kTabResumptionName,
-     flag_descriptions::kTabResumptionDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(kTabResumption)},
     {"bottom-omnibox-evolution", flag_descriptions::kBottomOmniboxEvolutionName,
      flag_descriptions::kBottomOmniboxEvolutionDescription, flags_ui::kOsIos,
      FEATURE_WITH_PARAMS_VALUE_TYPE(kBottomOmniboxEvolution,
@@ -2139,11 +2124,6 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(kIOSSoftLock,
                                     kIOSSoftLockVariations,
                                     "IOSSoftLock")},
-    {"tab-resumption-images", flag_descriptions::kTabResumptionImagesName,
-     flag_descriptions::kTabResumptionImagesDescription, flags_ui::kOsIos,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(kTabResumptionImages,
-                                    kTabResumptionImagesVariations,
-                                    "TabResumption1_5")},
     {"segmentation-platform-tips-ephemeral-card",
      flag_descriptions::kSegmentationPlatformTipsEphemeralCardName,
      flag_descriptions::kSegmentationPlatformTipsEphemeralCardDescription,
diff --git a/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator.mm b/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator.mm
index 3574c809..44f0588 100644
--- a/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator.mm
+++ b/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator.mm
@@ -17,9 +17,8 @@
 #import "components/profile_metrics/browser_profile_type.h"
 #import "components/search_engines/util.h"
 #import "components/strings/grit/components_strings.h"
+#import "ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.h"
 #import "ios/chrome/browser/autocomplete/model/autocomplete_scheme_classifier_impl.h"
-#import "ios/chrome/browser/autocomplete/model/autocomplete_service.h"
-#import "ios/chrome/browser/autocomplete/model/autocomplete_service_factory.h"
 #import "ios/chrome/browser/badges/ui_bundled/badge_button_factory.h"
 #import "ios/chrome/browser/badges/ui_bundled/badge_delegate.h"
 #import "ios/chrome/browser/badges/ui_bundled/badge_mediator.h"
@@ -420,11 +419,11 @@
     omniboxPositionBrowserAgent->SetOmniboxStateProvider(self);
   }
 
-  AutocompleteService* autocompleteService =
-      AutocompleteServiceFactory::GetForProfile(self.profile);
-  if (autocompleteService) {
+  AutocompleteBrowserAgent* autocompleteBrowserAgent =
+      AutocompleteBrowserAgent::FromBrowser(self.browser);
+  if (autocompleteBrowserAgent) {
     __weak __typeof__(self) weakSelf = self;
-    autocompleteService->RegisterWebStateListForPrefetching(
+    autocompleteBrowserAgent->RegisterWebStateListForPrefetching(
         IsComposeboxIOSEnabled() ? OmniboxPresentationContext::kComposebox
                                  : OmniboxPresentationContext::kLocationBar,
         self.webStateList,
@@ -467,12 +466,12 @@
   // TODO(crbug.com/462700929): Cleanup the service's objects like when it was
   // owned by the omnibox. Remove this workaround once the service can be safely
   // cleaned up during shutdown.
-  AutocompleteService* autocompleteService =
-      AutocompleteServiceFactory::GetForProfile(self.profile);
-  if (autocompleteService) {
-    autocompleteService->UnregisterWebStateListForPrefetching(
+  AutocompleteBrowserAgent* autocompleteBrowserAgent =
+      AutocompleteBrowserAgent::FromBrowser(self.browser);
+  if (autocompleteBrowserAgent) {
+    autocompleteBrowserAgent->UnregisterWebStateListForPrefetching(
         self.webStateList);
-    autocompleteService->RemoveServices();
+    autocompleteBrowserAgent->RemoveServices();
   }
   [self.badgeMediator disconnect];
   self.badgeMediator = nil;
diff --git a/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator_unittest.mm b/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator_unittest.mm
index 518a09aa..5315f159 100644
--- a/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator_unittest.mm
+++ b/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator_unittest.mm
@@ -11,6 +11,7 @@
 #import "components/omnibox/browser/test_location_bar_model.h"
 #import "components/variations/scoped_variations_ids_provider.h"
 #import "components/variations/variations_ids_provider.h"
+#import "ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.h"
 #import "ios/chrome/browser/autocomplete/model/autocomplete_classifier_factory.h"
 #import "ios/chrome/browser/favicon/model/favicon_service_factory.h"
 #import "ios/chrome/browser/favicon/model/ios_chrome_favicon_loader_factory.h"
@@ -111,6 +112,7 @@
     // must be created first. Please maintain this order.
     ToolbarsSizeBrowserAgent::CreateForBrowser(browser_.get());
     FullscreenController::CreateForBrowser(browser_.get());
+    AutocompleteBrowserAgent::CreateForBrowser(browser_.get());
 
     auto web_state = std::make_unique<web::FakeWebState>();
     web_state->SetBrowserState(profile_.get());
diff --git a/ios/chrome/browser/main/model/BUILD.gn b/ios/chrome/browser/main/model/BUILD.gn
index 8765d36..a6a7b97d 100644
--- a/ios/chrome/browser/main/model/BUILD.gn
+++ b/ios/chrome/browser/main/model/BUILD.gn
@@ -21,6 +21,7 @@
     "//components/breadcrumbs/core:status",
     "//components/data_sharing/public:features",
     "//ios/chrome/browser/app_launcher/model",
+    "//ios/chrome/browser/autocomplete/model",
     "//ios/chrome/browser/browser_view/model",
     "//ios/chrome/browser/bubble/model",
     "//ios/chrome/browser/collaboration/model",
diff --git a/ios/chrome/browser/main/model/DEPS b/ios/chrome/browser/main/model/DEPS
index 3089df4..3c246a0 100644
--- a/ios/chrome/browser/main/model/DEPS
+++ b/ios/chrome/browser/main/model/DEPS
@@ -14,6 +14,7 @@
     # go/keep-sorted start
     "+components/data_sharing/public/features.h",
     "+ios/chrome/browser/app_launcher/model/app_launcher_browser_agent.h",
+    "+ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.h",
     "+ios/chrome/browser/browser_view/model/browser_view_visibility_notifier_browser_agent.h",
     "+ios/chrome/browser/bubble/model",
     "+ios/chrome/browser/collaboration/model/collaboration_service_factory.h",
diff --git a/ios/chrome/browser/main/model/browser_agent_util.mm b/ios/chrome/browser/main/model/browser_agent_util.mm
index 18ee1e74..76e667b 100644
--- a/ios/chrome/browser/main/model/browser_agent_util.mm
+++ b/ios/chrome/browser/main/model/browser_agent_util.mm
@@ -9,6 +9,7 @@
 #import "components/breadcrumbs/core/breadcrumbs_status.h"
 #import "components/data_sharing/public/features.h"
 #import "ios/chrome/browser/app_launcher/model/app_launcher_browser_agent.h"
+#import "ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.h"
 #import "ios/chrome/browser/browser_view/model/browser_view_visibility_notifier_browser_agent.h"
 #import "ios/chrome/browser/bubble/model/tab_based_iph_browser_agent.h"
 #import "ios/chrome/browser/collaboration/model/collaboration_service_factory.h"
@@ -120,6 +121,7 @@
   UrlLoadingNotifierBrowserAgent::CreateForBrowser(browser);
   AppLauncherBrowserAgent::CreateForBrowser(browser);
   OmniboxPositionBrowserAgent::CreateForBrowser(browser);
+  AutocompleteBrowserAgent::CreateForBrowser(browser);
   ToolbarsSizeBrowserAgent::CreateForBrowser(browser);
 
   // Only create the FullscreenBrowserAgent and ReaderModeBrowserAgent for
diff --git a/ios/chrome/browser/omnibox/coordinator/omnibox_coordinator.mm b/ios/chrome/browser/omnibox/coordinator/omnibox_coordinator.mm
index fcfbafb..44071011 100644
--- a/ios/chrome/browser/omnibox/coordinator/omnibox_coordinator.mm
+++ b/ios/chrome/browser/omnibox/coordinator/omnibox_coordinator.mm
@@ -16,8 +16,7 @@
 #import "components/open_from_clipboard/clipboard_recent_content.h"
 #import "components/search_engines/template_url_service.h"
 #import "components/strings/grit/components_strings.h"
-#import "ios/chrome/browser/autocomplete/model/autocomplete_service.h"
-#import "ios/chrome/browser/autocomplete/model/autocomplete_service_factory.h"
+#import "ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.h"
 #import "ios/chrome/browser/favicon/model/ios_chrome_favicon_loader_factory.h"
 #import "ios/chrome/browser/feature_engagement/model/tracker_factory.h"
 #import "ios/chrome/browser/location_bar/ui_bundled/location_bar_constants.h"
@@ -179,10 +178,10 @@
   _omniboxTextModel = std::make_unique<OmniboxTextModel>(_client.get());
   id<OmniboxTextInput> textInput = viewController.textInput;
 
-  AutocompleteService* autocompleteService =
-      AutocompleteServiceFactory::GetForProfile(profile);
+  AutocompleteBrowserAgent* autocompleteBrowserAgent =
+      AutocompleteBrowserAgent::FromBrowser(browser);
   AutocompleteController* autocompleteController =
-      autocompleteService->GetAutocompleteController(_presentationContext);
+      autocompleteBrowserAgent->GetAutocompleteController(_presentationContext);
 
   _omniboxAutocompleteController = [[OmniboxAutocompleteController alloc]
        initWithOmniboxClient:_client.get()
diff --git a/ios/chrome/browser/omnibox/eg_tests/inttest/omnibox_inttest_coordinator.mm b/ios/chrome/browser/omnibox/eg_tests/inttest/omnibox_inttest_coordinator.mm
index 9346e55..c37660d4 100644
--- a/ios/chrome/browser/omnibox/eg_tests/inttest/omnibox_inttest_coordinator.mm
+++ b/ios/chrome/browser/omnibox/eg_tests/inttest/omnibox_inttest_coordinator.mm
@@ -29,7 +29,7 @@
   OmniboxInttestViewController* _viewController;
   raw_ptr<FakeOmniboxClient> _fakeOmniboxClient;
   raw_ptr<FakeSuggestionsBuilder> _fakeSuggestionsBuilder;
-  // TODO(crbug.com/462066136): Move to a TestAutocompleteService.
+  // TODO(crbug.com/462066136): Move to a TestAutocompleteBrowserAgent.
   std::unique_ptr<OmniboxInttestAutocompleteController> _autocompleteController;
 }
 
diff --git a/ios/chrome/browser/omnibox/model/chrome_omnibox_client_ios.mm b/ios/chrome/browser/omnibox/model/chrome_omnibox_client_ios.mm
index ca35b71f..54b8b3bd 100644
--- a/ios/chrome/browser/omnibox/model/chrome_omnibox_client_ios.mm
+++ b/ios/chrome/browser/omnibox/model/chrome_omnibox_client_ios.mm
@@ -19,10 +19,9 @@
 #import "components/omnibox/browser/omnibox_log.h"
 #import "components/omnibox/common/omnibox_features.h"
 #import "components/search_engines/template_url_service.h"
+#import "ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.h"
 #import "ios/chrome/browser/autocomplete/model/autocomplete_classifier_factory.h"
 #import "ios/chrome/browser/autocomplete/model/autocomplete_provider_client_impl.h"
-#import "ios/chrome/browser/autocomplete/model/autocomplete_service.h"
-#import "ios/chrome/browser/autocomplete/model/autocomplete_service_factory.h"
 #import "ios/chrome/browser/autocomplete/model/omnibox_shortcuts_helper.h"
 #import "ios/chrome/browser/bookmarks/model/bookmark_model_factory.h"
 #import "ios/chrome/browser/bookmarks/model/bookmarks_utils.h"
@@ -279,10 +278,10 @@
     const std::u16string& text,
     const AutocompleteMatch& match,
     const AutocompleteMatch& alternative_nav_match) {
-  AutocompleteService* autocomplete_service =
-      AutocompleteServiceFactory::GetForProfile(profile_);
+  AutocompleteBrowserAgent* autocomplete_browser_agent =
+      AutocompleteBrowserAgent::FromBrowser(browser_);
   OmniboxShortcutsHelper* shortcuts_helper =
-      autocomplete_service->GetOmniboxShortcutsHelper(
+      autocomplete_browser_agent->GetOmniboxShortcutsHelper(
           OmniboxPresentationContext::kLocationBar);
   if (shortcuts_helper) {
     shortcuts_helper->OnAutocompleteAccept(text, match,
diff --git a/ios/chrome/browser/omnibox/ui/omnibox_drs_view_controller.mm b/ios/chrome/browser/omnibox/ui/omnibox_drs_view_controller.mm
index 8d3f3ab6..a98f88e 100644
--- a/ios/chrome/browser/omnibox/ui/omnibox_drs_view_controller.mm
+++ b/ios/chrome/browser/omnibox/ui/omnibox_drs_view_controller.mm
@@ -237,7 +237,7 @@
 }
 
 - (void)popupDidCloseForPresenter:(OmniboxPopupPresenter*)presenter {
-  [self.proxiedPresenterDelegate popupDidOpenForPresenter:presenter];
+  [self.proxiedPresenterDelegate popupDidCloseForPresenter:presenter];
   [self close];
 }
 
diff --git a/ios/chrome/browser/profile/model/keyed_service_factories.mm b/ios/chrome/browser/profile/model/keyed_service_factories.mm
index 2043831..a3a6e202 100644
--- a/ios/chrome/browser/profile/model/keyed_service_factories.mm
+++ b/ios/chrome/browser/profile/model/keyed_service_factories.mm
@@ -11,7 +11,6 @@
 #import "ios/chrome/browser/autocomplete/model/autocomplete_classifier_factory.h"
 #import "ios/chrome/browser/autocomplete/model/autocomplete_provider_client_impl.h"
 #import "ios/chrome/browser/autocomplete/model/autocomplete_scoring_model_service_factory.h"
-#import "ios/chrome/browser/autocomplete/model/autocomplete_service_factory.h"
 #import "ios/chrome/browser/autocomplete/model/in_memory_url_index_factory.h"
 #import "ios/chrome/browser/autocomplete/model/on_device_tail_model_service_factory.h"
 #import "ios/chrome/browser/autocomplete/model/provider_state_service_factory.h"
@@ -268,7 +267,6 @@
   AcceptLanguagesServiceFactory::GetInstance();
   AppStoreBundleServiceFactory::GetInstance();
   AuthenticationServiceFactory::GetInstance();
-  AutocompleteServiceFactory::GetInstance();
   BackgroundDownloadServiceFactory::GetInstance();
   BookmarkModelMetricsServiceFactory::GetInstance();
   BreadcrumbManagerKeyedServiceFactory::GetInstance();
diff --git a/ios/chrome/browser/qr_scanner/ui_bundled/BUILD.gn b/ios/chrome/browser/qr_scanner/ui_bundled/BUILD.gn
index 0fc463d..9854426c 100644
--- a/ios/chrome/browser/qr_scanner/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/qr_scanner/ui_bundled/BUILD.gn
@@ -55,6 +55,7 @@
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/scanner/ui_bundled:camera_state",
     "//ios/chrome/browser/settings/ui_bundled:eg_test_support+eg2",
+    "//ios/chrome/browser/shared/public/features",
     "//ios/chrome/test/earl_grey:eg_test_support+eg2",
     "//ios/testing/earl_grey:eg_test_support+eg2",
     "//net",
diff --git a/ios/chrome/browser/qr_scanner/ui_bundled/qr_scanner_view_controller_egtest.mm b/ios/chrome/browser/qr_scanner/ui_bundled/qr_scanner_view_controller_egtest.mm
index 7a5bead..8d9e7daa 100644
--- a/ios/chrome/browser/qr_scanner/ui_bundled/qr_scanner_view_controller_egtest.mm
+++ b/ios/chrome/browser/qr_scanner/ui_bundled/qr_scanner_view_controller_egtest.mm
@@ -12,6 +12,7 @@
 #import "ios/chrome/browser/qr_scanner/ui_bundled/qr_scanner_app_interface.h"
 #import "ios/chrome/browser/scanner/ui_bundled/camera_state.h"
 #import "ios/chrome/browser/settings/ui_bundled/settings_app_interface.h"
+#import "ios/chrome/browser/shared/public/features/features.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
@@ -214,6 +215,12 @@
   std::unique_ptr<EarlGreyScopedBlockSwizzler> _camera_controller_swizzler;
 }
 
+- (AppLaunchConfiguration)appConfigurationForTestCase {
+  AppLaunchConfiguration config = [super appConfigurationForTestCase];
+  config.features_disabled.push_back(kComposeboxIOS);
+  return config;
+}
+
 - (void)setUp {
   [super setUp];
 
diff --git a/ios/chrome/browser/settings/ui_bundled/google_services/manage_sync_settings_table_view_controller.mm b/ios/chrome/browser/settings/ui_bundled/google_services/manage_sync_settings_table_view_controller.mm
index d78f1eb5..1a9f45a 100644
--- a/ios/chrome/browser/settings/ui_bundled/google_services/manage_sync_settings_table_view_controller.mm
+++ b/ios/chrome/browser/settings/ui_bundled/google_services/manage_sync_settings_table_view_controller.mm
@@ -102,10 +102,8 @@
                   withRowAnimation:UITableViewRowAnimationMiddle];
   } else {
     [UIView performWithoutAnimation:^{
-      [self.tableView beginUpdates];
       [self.tableView insertSections:sections
                     withRowAnimation:UITableViewRowAnimationNone];
-      [self.tableView endUpdates];
     }];
   }
 }
@@ -121,10 +119,8 @@
   } else {
     // To avoid animation glitches related to crbug.com/1469539.
     [UIView performWithoutAnimation:^{
-      [self.tableView beginUpdates];
       [self.tableView deleteSections:sections
                     withRowAnimation:UITableViewRowAnimationNone];
-      [self.tableView endUpdates];
     }];
   }
 }
@@ -149,10 +145,8 @@
   }
   // To avoid animation glitches related to crbug.com/1469539.
   [UIView performWithoutAnimation:^{
-    [self.tableView beginUpdates];
     [self.tableView reloadRowsAtIndexPaths:@[ indexPath ]
                           withRowAnimation:UITableViewRowAnimationNone];
-    [self.tableView endUpdates];
   }];
 }
 
diff --git a/ios/chrome/browser/shared/coordinator/scene/BUILD.gn b/ios/chrome/browser/shared/coordinator/scene/BUILD.gn
index aef439a..46a3f72 100644
--- a/ios/chrome/browser/shared/coordinator/scene/BUILD.gn
+++ b/ios/chrome/browser/shared/coordinator/scene/BUILD.gn
@@ -47,6 +47,15 @@
   ]
 }
 
+source_set("scene_state_header_for_otr_profile_deletion") {
+  visibility = [
+    ":scene",
+    "//ios/chrome/app/profile:otr_profile_destroyer_profile_agent",
+  ]
+  sources = [ "scene_controller+OTRProfileDeletion.h" ]
+  deps = [ ":scene_state_header" ]
+}
+
 source_set("scene_testing") {
   sources = [ "scene_controller_testing.h" ]
   frameworks = [ "UIKit.framework" ]
@@ -60,6 +69,7 @@
   ]
 
   deps = [
+    ":scene_state_header_for_otr_profile_deletion",
     ":scene_util",
     "//base",
     "//components/autofill/core/browser",
@@ -205,7 +215,6 @@
     "//ios/chrome/browser/tab_switcher/ui_bundled:utils",
     "//ios/chrome/browser/tab_switcher/ui_bundled/tab_grid",
     "//ios/chrome/browser/url_loading/model",
-    "//ios/chrome/browser/web_state_list/model:session_metrics",
     "//ios/chrome/browser/web_state_list/model/web_usage_enabler",
     "//ios/chrome/browser/whats_new/coordinator/promo",
     "//ios/chrome/browser/widget_kit/model:features",
diff --git a/ios/chrome/browser/shared/coordinator/scene/scene_controller+OTRProfileDeletion.h b/ios/chrome/browser/shared/coordinator/scene/scene_controller+OTRProfileDeletion.h
new file mode 100644
index 0000000..ecfd66c
--- /dev/null
+++ b/ios/chrome/browser/shared/coordinator/scene/scene_controller+OTRProfileDeletion.h
@@ -0,0 +1,20 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_SHARED_COORDINATOR_SCENE_SCENE_CONTROLLER_OTRPROFILEDELETION_H_
+#define IOS_CHROME_BROWSER_SHARED_COORDINATOR_SCENE_SCENE_CONTROLLER_OTRPROFILEDELETION_H_
+
+#import "ios/chrome/browser/shared/coordinator/scene/scene_controller.h"
+
+@interface SceneController (OTRProfileDeletion)
+
+// Must be called before destroying the incognito Profile.
+- (void)willDestroyIncognitoProfile;
+
+// Must be called after recreating the incognito Profile.
+- (void)incognitoProfileCreated;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_SHARED_COORDINATOR_SCENE_SCENE_CONTROLLER_OTRPROFILEDELETION_H_
diff --git a/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm b/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm
index 6812f08..c810732 100644
--- a/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm
+++ b/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm
@@ -74,7 +74,6 @@
 #import "ios/chrome/browser/browsing_data/model/browsing_data_remover.h"
 #import "ios/chrome/browser/browsing_data/model/browsing_data_remover_factory.h"
 #import "ios/chrome/browser/crash_report/model/breadcrumbs/breadcrumb_manager_browser_agent.h"
-#import "ios/chrome/browser/crash_report/model/crash_keys_helper.h"
 #import "ios/chrome/browser/crash_report/model/crash_loop_detection_util.h"
 #import "ios/chrome/browser/crash_report/model/crash_report_helper.h"
 #import "ios/chrome/browser/credential_provider_promo/ui_bundled/credential_provider_promo_scene_agent.h"
@@ -140,6 +139,7 @@
 #import "ios/chrome/browser/share_extension/model/share_extension_scene_agent.h"
 #import "ios/chrome/browser/shared/coordinator/default_browser_promo/non_modal_default_browser_promo_scheduler_scene_agent.h"
 #import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_scene_agent.h"
+#import "ios/chrome/browser/shared/coordinator/scene/scene_controller+OTRProfileDeletion.h"
 #import "ios/chrome/browser/shared/coordinator/scene/scene_ui_provider.h"
 #import "ios/chrome/browser/shared/coordinator/scene/url_context.h"
 #import "ios/chrome/browser/shared/model/application_context/application_context.h"
@@ -203,7 +203,6 @@
 #import "ios/chrome/browser/url_loading/model/scene_url_loading_service.h"
 #import "ios/chrome/browser/url_loading/model/url_loading_browser_agent.h"
 #import "ios/chrome/browser/url_loading/model/url_loading_params.h"
-#import "ios/chrome/browser/web_state_list/model/session_metrics.h"
 #import "ios/chrome/browser/web_state_list/model/web_usage_enabler/web_usage_enabler_browser_agent.h"
 #import "ios/chrome/browser/whats_new/coordinator/promo/whats_new_scene_agent.h"
 #import "ios/chrome/browser/widget_kit/model/features.h"
@@ -222,8 +221,6 @@
 #import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/navigation/navigation_util.h"
 #import "ios/web/public/session/proto/storage.pb.h"
-#import "ios/web/public/thread/web_task_traits.h"
-#import "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_state.h"
 #import "net/base/apple/url_conversions.h"
 #import "net/base/url_util.h"
@@ -4390,27 +4387,6 @@
 
 // Called when the last incognito tab was closed.
 - (void)lastIncognitoTabClosed {
-  // If no other window has incognito tab, then destroy and rebuild the
-  // Profile. Otherwise, just do the state transition animation.
-  if ([self shouldDestroyAndRebuildIncognitoProfile]) {
-    // Incognito profile cannot be deleted before all the requests are
-    // deleted. Queue empty task on IO thread and destroy the Profile
-    // when the task has executed, again verifying that no incognito tabs are
-    // present. When an incognito tab is moved between browsers, there is
-    // a point where the tab isn't attached to any web state list. However, when
-    // this queued cleanup step executes, the moved tab will be attached, so
-    // the cleanup shouldn't proceed.
-
-    auto cleanup = ^{
-      if ([self shouldDestroyAndRebuildIncognitoProfile]) {
-        [self destroyAndRebuildIncognitoProfile];
-      }
-    };
-
-    web::GetIOThreadTaskRunner({})->PostTaskAndReply(
-        FROM_HERE, base::DoNothing(), base::BindRepeating(cleanup));
-  }
-
   // a) The first condition can happen when the last incognito tab is closed
   // from the tab switcher.
   // b) The second condition can happen if some other code (like JS) triggers
@@ -4440,22 +4416,6 @@
   [self showTabSwitcher];
 }
 
-// Clears incognito data that is specific to iOS and won't be cleared by
-// deleting the profile.
-- (void)clearIOSSpecificIncognitoData {
-  DCHECK(self.profile->HasOffTheRecordProfile());
-  ProfileIOS* otrProfile = self.profile->GetOffTheRecordProfile();
-
-  __weak SceneController* weakSelf = self;
-  BrowsingDataRemover* browsingDataRemover =
-      BrowsingDataRemoverFactory::GetForProfile(otrProfile);
-  browsingDataRemover->Remove(browsing_data::TimePeriod::ALL_TIME,
-                              BrowsingDataRemoveMask::REMOVE_ALL,
-                              base::BindOnce(^{
-                                [weakSelf activateBVCAndMakeCurrentBVCPrimary];
-                              }));
-}
-
 - (void)activateBVCAndMakeCurrentBVCPrimary {
   // If there are pending removal operations, the activation will be deferred
   // until the callback is received.
@@ -4547,79 +4507,6 @@
 
 #pragma mark - Handling of destroying the incognito profile
 
-// The incognito Profile should be closed when the last incognito tab is
-// closed (i.e. if there are other incognito tabs open in another Scene, the
-// Profile must not be destroyed).
-- (BOOL)shouldDestroyAndRebuildIncognitoProfile {
-  ProfileIOS* profile = self.profile;
-  if (!profile->HasOffTheRecordProfile()) {
-    return NO;
-  }
-
-  ProfileIOS* otrProfile = profile->GetOffTheRecordProfile();
-  DCHECK(otrProfile);
-
-  BrowserList* browserList = BrowserListFactory::GetForProfile(otrProfile);
-  for (Browser* browser :
-       browserList->BrowsersOfType(BrowserList::BrowserType::kIncognito)) {
-    WebStateList* webStateList = browser->GetWebStateList();
-    if (!webStateList->empty()) {
-      return NO;
-    }
-  }
-
-  return YES;
-}
-
-// Destroys and rebuilds the incognito Profile. This will inform all the
-// other SceneController to destroy state tied to the Profile and to
-// recreate it.
-- (void)destroyAndRebuildIncognitoProfile {
-  // This seems the best place to mark the start of destroying the incognito
-  // profile.
-  crash_keys::SetDestroyingAndRebuildingIncognitoBrowserState(
-      /*in_progress=*/true);
-
-  [self clearIOSSpecificIncognitoData];
-
-  ProfileIOS* profile = self.profile;
-  DCHECK(profile->HasOffTheRecordProfile());
-  ProfileIOS* otrProfile = profile->GetOffTheRecordProfile();
-
-  NSMutableArray<SceneController*>* sceneControllers =
-      [[NSMutableArray alloc] init];
-  for (SceneState* sceneState in self.sceneState.profileState.connectedScenes) {
-    SceneController* sceneController = sceneState.controller;
-    // In some circumstances, the scene state may still exist while the
-    // corresponding scene controller has been deallocated.
-    // (see crbug.com/1142782).
-    if (sceneController) {
-      [sceneControllers addObject:sceneController];
-    }
-  }
-
-  for (SceneController* sceneController in sceneControllers) {
-    [sceneController willDestroyIncognitoProfile];
-  }
-
-  // Record off-the-record metrics before detroying the Profile.
-  SessionMetrics::FromProfile(otrProfile)
-      ->RecordAndClearSessionMetrics(MetricsToRecordFlags::kNoMetrics);
-
-  // Destroy and recreate the off-the-record Profile.
-  profile->DestroyOffTheRecordProfile();
-  profile->GetOffTheRecordProfile();
-
-  for (SceneController* sceneController in sceneControllers) {
-    [sceneController incognitoProfileCreated];
-  }
-
-  // This seems the best place to deem the destroying and rebuilding the
-  // incognito profile to be completed.
-  crash_keys::SetDestroyingAndRebuildingIncognitoBrowserState(
-      /*in_progress=*/false);
-}
-
 - (void)willDestroyIncognitoProfile {
   // Clear the Incognito Browser and notify the TabGrid that its otrBrowser
   // will be destroyed.
diff --git a/ios/chrome/browser/shared/model/profile/BUILD.gn b/ios/chrome/browser/shared/model/profile/BUILD.gn
index 76fce0a..d2162ec0 100644
--- a/ios/chrome/browser/shared/model/profile/BUILD.gn
+++ b/ios/chrome/browser/shared/model/profile/BUILD.gn
@@ -76,6 +76,8 @@
   sources = [
     "incognito_session_tracker.h",
     "incognito_session_tracker.mm",
+    "profile_incognito_session_tracker.h",
+    "profile_incognito_session_tracker.mm",
   ]
   deps = [
     ":profile",
diff --git a/ios/chrome/browser/shared/model/profile/incognito_session_tracker.h b/ios/chrome/browser/shared/model/profile/incognito_session_tracker.h
index f2f8370f..f2d4e1b 100644
--- a/ios/chrome/browser/shared/model/profile/incognito_session_tracker.h
+++ b/ios/chrome/browser/shared/model/profile/incognito_session_tracker.h
@@ -12,6 +12,7 @@
 #import "ios/chrome/browser/shared/model/profile/profile_manager_observer_ios.h"
 
 class ProfileIOS;
+class ProfileIncognitoSessionTracker;
 class ProfileManagerIOS;
 
 // Tracks whether there are any open off-the-record tabs open by any Profile in
@@ -52,10 +53,6 @@
                                            ProfileIOS* profile) override;
 
  private:
-  // Forward-declaration of the observer used to track the state of
-  // an individual Profile.
-  class Observer;
-
   // Invoked when the state of invoked when the presence of off-the-record
   // tabs for a specific Profile has changed.
   void OnIncognitoSessionStateChanged(bool has_incognito_tabs);
@@ -64,9 +61,10 @@
   base::ScopedObservation<ProfileManagerIOS, ProfileManagerObserverIOS>
       scoped_manager_observation_{this};
 
-  // Map from Profile to the observer used to track whether it has any open
-  // off-the-record tabs.
-  base::flat_map<ProfileIOS*, std::unique_ptr<Observer>> observers_;
+  // Map from profile to the ProfileIncognitoSessionTracker used to track
+  // whether this profile has any open off-the-record tabs.
+  base::flat_map<ProfileIOS*, std::unique_ptr<ProfileIncognitoSessionTracker>>
+      trackers_;
 
   // List of registered callbacks.
   SessionStateChangedCallbackList callbacks_;
diff --git a/ios/chrome/browser/shared/model/profile/incognito_session_tracker.mm b/ios/chrome/browser/shared/model/profile/incognito_session_tracker.mm
index 7ee6cf3f..3f71705 100644
--- a/ios/chrome/browser/shared/model/profile/incognito_session_tracker.mm
+++ b/ios/chrome/browser/shared/model/profile/incognito_session_tracker.mm
@@ -6,167 +6,10 @@
 
 #import <algorithm>
 
-#import "base/scoped_multi_source_observation.h"
 #import "base/scoped_observation.h"
-#import "ios/chrome/browser/shared/model/browser/browser.h"
-#import "ios/chrome/browser/shared/model/browser/browser_list.h"
 #import "ios/chrome/browser/shared/model/browser/browser_list_factory.h"
-#import "ios/chrome/browser/shared/model/browser/browser_list_observer.h"
+#import "ios/chrome/browser/shared/model/profile/profile_incognito_session_tracker.h"
 #import "ios/chrome/browser/shared/model/profile/profile_manager_ios.h"
-#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
-#import "ios/chrome/browser/shared/model/web_state_list/web_state_list_observer.h"
-
-// Observer used to track the state of an individual Profile
-// and inform the IncognitoSessionTracker when the state of the incognito
-// session for that Profile changes.
-class IncognitoSessionTracker::Observer final : public BrowserListObserver,
-                                                public WebStateListObserver {
- public:
-  // Callback invoked when the presence of off-the-record tabs has changed.
-  using Callback = base::RepeatingCallback<void(bool)>;
-
-  Observer(BrowserList* list, Callback callback);
-  ~Observer() final;
-
-  // Returns whether any of the BrowserList's Browser has incognito tabs open.
-  bool has_incognito_tabs() const { return has_incognito_tabs_; }
-
-  // BrowserListObserver:
-  void OnBrowserAdded(const BrowserList* list, Browser* browser) final;
-  void OnBrowserRemoved(const BrowserList* list, Browser* browser) final;
-  void OnBrowserListShutdown(BrowserList* list) final;
-
-  // WebStateListObserver:
-  void WebStateListDidChange(WebStateList* web_state_list,
-                             const WebStateListChange& change,
-                             const WebStateListStatus& status) final;
-  void BatchOperationEnded(WebStateList* web_state_list) final;
-
- private:
-  // Invoked when a potentially significant change is detected in any of
-  // the observed WebStateList.
-  void OnWebStateListChanged();
-
-  // Closure invoked when the presence of off-the-record tabs has changed.
-  Callback callback_;
-
-  // Manages the observation of the BrowserList.
-  base::ScopedObservation<BrowserList, BrowserListObserver>
-      browser_list_observation_{this};
-
-  // Manages the observation of all off-the-record WebStateLists.
-  base::ScopedMultiSourceObservation<WebStateList, WebStateListObserver>
-      web_state_list_observations_{this};
-
-  // Whether any of the WebStateList has an off-the-record tab open.
-  bool has_incognito_tabs_ = false;
-};
-
-IncognitoSessionTracker::Observer::Observer(BrowserList* browser_list,
-                                            Callback callback)
-    : callback_(std::move(callback)) {
-  DCHECK(!callback_.is_null());
-  browser_list_observation_.Observe(browser_list);
-
-  // Observe all pre-existing off-the-record Browsers.
-  const auto kIncognitoBrowserType = BrowserList::BrowserType::kIncognito;
-  for (Browser* browser : browser_list->BrowsersOfType(kIncognitoBrowserType)) {
-    web_state_list_observations_.AddObservation(browser->GetWebStateList());
-  }
-
-  // Check whether any of the Browsers has any open off-the-record tabs.
-  OnWebStateListChanged();
-}
-
-IncognitoSessionTracker::Observer::~Observer() = default;
-
-void IncognitoSessionTracker::Observer::OnBrowserAdded(
-    const BrowserList* browser_list,
-    Browser* browser) {
-  // Ignore non-incognito Browsers.
-  if (browser->type() != Browser::Type::kIncognito) {
-    return;
-  }
-
-  WebStateList* const web_state_list = browser->GetWebStateList();
-  web_state_list_observations_.AddObservation(web_state_list);
-
-  // If the WebStateList was not empty, then it may be necessary to
-  // notify the callback.
-  if (!web_state_list->empty()) {
-    OnWebStateListChanged();
-  }
-}
-
-void IncognitoSessionTracker::Observer::OnBrowserRemoved(
-    const BrowserList* browser_list,
-    Browser* browser) {
-  // Ignore non-incognito Browsers.
-  if (browser->type() != Browser::Type::kIncognito) {
-    return;
-  }
-
-  WebStateList* const web_state_list = browser->GetWebStateList();
-  web_state_list_observations_.RemoveObservation(web_state_list);
-
-  // If the WebStateList was not empty, then it may be necessary to
-  // notify the callback.
-  if (!web_state_list->empty()) {
-    OnWebStateListChanged();
-  }
-}
-
-void IncognitoSessionTracker::Observer::WebStateListDidChange(
-    WebStateList* web_state_list,
-    const WebStateListChange& change,
-    const WebStateListStatus& status) {
-  // Ignore changes during batch operations.
-  if (web_state_list->IsBatchInProgress()) {
-    return;
-  }
-
-  switch (change.type()) {
-    // None of those events can change the number of off-the-record tabs,
-    // ignore them.
-    case WebStateListChange::Type::kStatusOnly:
-    case WebStateListChange::Type::kMove:
-    case WebStateListChange::Type::kReplace:
-    case WebStateListChange::Type::kGroupCreate:
-    case WebStateListChange::Type::kGroupVisualDataUpdate:
-    case WebStateListChange::Type::kGroupMove:
-    case WebStateListChange::Type::kGroupDelete:
-      return;
-
-    // Those events either increment or decrement the number of open
-    // off-the-record tabs, so update the state.
-    case WebStateListChange::Type::kDetach:
-    case WebStateListChange::Type::kInsert:
-      OnWebStateListChanged();
-      return;
-  }
-}
-
-void IncognitoSessionTracker::Observer::OnWebStateListChanged() {
-  const bool has_incognito_tabs = std::ranges::any_of(
-      web_state_list_observations_.sources(),
-      [](WebStateList* web_state_list) { return !web_state_list->empty(); });
-
-  if (has_incognito_tabs_ != has_incognito_tabs) {
-    has_incognito_tabs_ = has_incognito_tabs;
-    callback_.Run(has_incognito_tabs_);
-  }
-}
-
-void IncognitoSessionTracker::Observer::BatchOperationEnded(
-    WebStateList* web_state_list) {
-  // Anything can change during a batch operation. Update the state.
-  OnWebStateListChanged();
-}
-
-void IncognitoSessionTracker::Observer::OnBrowserListShutdown(
-    BrowserList* browser_list) {
-  browser_list_observation_.Reset();
-}
 
 IncognitoSessionTracker::IncognitoSessionTracker(ProfileManagerIOS* manager) {
   // ProfileManagerIOS invoke OnProfileLoaded(...) for all Profiles already
@@ -214,8 +57,8 @@
   // Observer. The use of `base::Unretained(this)` is safe as the
   // `IncognitoSessionTracker` owns the `Observer` and the closure cannot
   // outlive `this`.
-  auto [_, inserted] = observers_.insert(std::make_pair(
-      profile, std::make_unique<Observer>(
+  auto [_, inserted] = trackers_.insert(std::make_pair(
+      profile, std::make_unique<ProfileIncognitoSessionTracker>(
                    BrowserListFactory::GetForProfile(profile),
                    base::BindRepeating(
                        &IncognitoSessionTracker::OnIncognitoSessionStateChanged,
@@ -227,9 +70,9 @@
 void IncognitoSessionTracker::OnProfileUnloaded(ProfileManagerIOS* manager,
                                                 ProfileIOS* profile) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  auto iterator = observers_.find(profile);
-  DCHECK(iterator != observers_.end());
-  observers_.erase(iterator);
+  auto iterator = trackers_.find(profile);
+  DCHECK(iterator != trackers_.end());
+  trackers_.erase(iterator);
 
   // The removed profile does not have any tabs, thus no incognito tabs.
   OnIncognitoSessionStateChanged(false);
@@ -249,8 +92,10 @@
   const bool has_incognito_session_tabs =
       has_incognito_tabs ||
       std::ranges::any_of(
-          observers_, &Observer::has_incognito_tabs,
-          [](auto& pair) -> const Observer& { return *pair.second; });
+          trackers_, &ProfileIncognitoSessionTracker::has_incognito_tabs,
+          [](auto& pair) -> const ProfileIncognitoSessionTracker& {
+            return *pair.second;
+          });
 
   if (has_incognito_session_tabs_ != has_incognito_session_tabs) {
     has_incognito_session_tabs_ = has_incognito_session_tabs;
diff --git a/ios/chrome/browser/shared/model/profile/profile_incognito_session_tracker.h b/ios/chrome/browser/shared/model/profile/profile_incognito_session_tracker.h
new file mode 100644
index 0000000..30578894
--- /dev/null
+++ b/ios/chrome/browser/shared/model/profile/profile_incognito_session_tracker.h
@@ -0,0 +1,60 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_SHARED_MODEL_PROFILE_PROFILE_INCOGNITO_SESSION_TRACKER_H_
+#define IOS_CHROME_BROWSER_SHARED_MODEL_PROFILE_PROFILE_INCOGNITO_SESSION_TRACKER_H_
+
+#include "base/functional/callback.h"
+#include "base/scoped_multi_source_observation.h"
+#include "base/scoped_observation.h"
+#include "ios/chrome/browser/shared/model/browser/browser_list_observer.h"
+#include "ios/chrome/browser/shared/model/web_state_list/web_state_list_observer.h"
+
+// Tracks whether a given profile has any open off-the-record tabs open,
+// invoking a callback when the state changes. Can also be queried to
+// check whether any off-the-record tabs are open at any time.
+class ProfileIncognitoSessionTracker final : public BrowserListObserver,
+                                             public WebStateListObserver {
+ public:
+  // Callback invoked when the presence of off-the-record tabs has changed.
+  using Callback = base::RepeatingCallback<void(bool)>;
+
+  ProfileIncognitoSessionTracker(BrowserList* list, Callback callback);
+  ~ProfileIncognitoSessionTracker() final;
+
+  // Returns whether any of the BrowserList's Browser has incognito tabs open.
+  bool has_incognito_tabs() const { return has_incognito_tabs_; }
+
+  // BrowserListObserver:
+  void OnBrowserAdded(const BrowserList* list, Browser* browser) final;
+  void OnBrowserRemoved(const BrowserList* list, Browser* browser) final;
+  void OnBrowserListShutdown(BrowserList* list) final;
+
+  // WebStateListObserver:
+  void WebStateListDidChange(WebStateList* web_state_list,
+                             const WebStateListChange& change,
+                             const WebStateListStatus& status) final;
+  void BatchOperationEnded(WebStateList* web_state_list) final;
+
+ private:
+  // Invoked when a potentially significant change is detected in any of
+  // the observed WebStateList.
+  void OnWebStateListChanged();
+
+  // Closure invoked when the presence of off-the-record tabs has changed.
+  Callback callback_;
+
+  // Manages the observation of the BrowserList.
+  base::ScopedObservation<BrowserList, BrowserListObserver>
+      browser_list_observation_{this};
+
+  // Manages the observation of all off-the-record WebStateLists.
+  base::ScopedMultiSourceObservation<WebStateList, WebStateListObserver>
+      web_state_list_observations_{this};
+
+  // Whether any of the WebStateList has an off-the-record tab open.
+  bool has_incognito_tabs_ = false;
+};
+
+#endif  // IOS_CHROME_BROWSER_SHARED_MODEL_PROFILE_PROFILE_INCOGNITO_SESSION_TRACKER_H_
diff --git a/ios/chrome/browser/shared/model/profile/profile_incognito_session_tracker.mm b/ios/chrome/browser/shared/model/profile/profile_incognito_session_tracker.mm
new file mode 100644
index 0000000..3841bd47
--- /dev/null
+++ b/ios/chrome/browser/shared/model/profile/profile_incognito_session_tracker.mm
@@ -0,0 +1,117 @@
+// 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/shared/model/profile/profile_incognito_session_tracker.h"
+
+#import "base/scoped_observation.h"
+#import "ios/chrome/browser/shared/model/browser/browser.h"
+#import "ios/chrome/browser/shared/model/browser/browser_list.h"
+#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
+
+ProfileIncognitoSessionTracker::ProfileIncognitoSessionTracker(
+    BrowserList* browser_list,
+    Callback callback)
+    : callback_(std::move(callback)) {
+  DCHECK(!callback_.is_null());
+  browser_list_observation_.Observe(browser_list);
+
+  // Observe all pre-existing off-the-record Browsers.
+  const auto kIncognitoBrowserType = BrowserList::BrowserType::kIncognito;
+  for (Browser* browser : browser_list->BrowsersOfType(kIncognitoBrowserType)) {
+    web_state_list_observations_.AddObservation(browser->GetWebStateList());
+  }
+
+  // Check whether any of the Browsers has any open off-the-record tabs.
+  OnWebStateListChanged();
+}
+
+ProfileIncognitoSessionTracker::~ProfileIncognitoSessionTracker() = default;
+
+void ProfileIncognitoSessionTracker::OnBrowserAdded(
+    const BrowserList* browser_list,
+    Browser* browser) {
+  // Ignore non-incognito Browsers.
+  if (browser->type() != Browser::Type::kIncognito) {
+    return;
+  }
+
+  WebStateList* const web_state_list = browser->GetWebStateList();
+  web_state_list_observations_.AddObservation(web_state_list);
+
+  // If the WebStateList was not empty, then it may be necessary to
+  // notify the callback.
+  if (!web_state_list->empty()) {
+    OnWebStateListChanged();
+  }
+}
+
+void ProfileIncognitoSessionTracker::OnBrowserRemoved(
+    const BrowserList* browser_list,
+    Browser* browser) {
+  // Ignore non-incognito Browsers.
+  if (browser->type() != Browser::Type::kIncognito) {
+    return;
+  }
+
+  WebStateList* const web_state_list = browser->GetWebStateList();
+  web_state_list_observations_.RemoveObservation(web_state_list);
+
+  // If the WebStateList was not empty, then it may be necessary to
+  // notify the callback.
+  if (!web_state_list->empty()) {
+    OnWebStateListChanged();
+  }
+}
+
+void ProfileIncognitoSessionTracker::WebStateListDidChange(
+    WebStateList* web_state_list,
+    const WebStateListChange& change,
+    const WebStateListStatus& status) {
+  // Ignore changes during batch operations.
+  if (web_state_list->IsBatchInProgress()) {
+    return;
+  }
+
+  switch (change.type()) {
+    // None of those events can change the number of off-the-record tabs,
+    // ignore them.
+    case WebStateListChange::Type::kStatusOnly:
+    case WebStateListChange::Type::kMove:
+    case WebStateListChange::Type::kReplace:
+    case WebStateListChange::Type::kGroupCreate:
+    case WebStateListChange::Type::kGroupVisualDataUpdate:
+    case WebStateListChange::Type::kGroupMove:
+    case WebStateListChange::Type::kGroupDelete:
+      return;
+
+    // Those events either increment or decrement the number of open
+    // off-the-record tabs, so update the state.
+    case WebStateListChange::Type::kDetach:
+    case WebStateListChange::Type::kInsert:
+      OnWebStateListChanged();
+      return;
+  }
+}
+
+void ProfileIncognitoSessionTracker::OnWebStateListChanged() {
+  const bool has_incognito_tabs = std::ranges::any_of(
+      web_state_list_observations_.sources(),
+      [](WebStateList* web_state_list) { return !web_state_list->empty(); });
+
+  if (has_incognito_tabs_ != has_incognito_tabs) {
+    has_incognito_tabs_ = has_incognito_tabs;
+    callback_.Run(has_incognito_tabs_);
+  }
+}
+
+void ProfileIncognitoSessionTracker::BatchOperationEnded(
+    WebStateList* web_state_list) {
+  // Anything can change during a batch operation. Update the state.
+  OnWebStateListChanged();
+}
+
+void ProfileIncognitoSessionTracker::OnBrowserListShutdown(
+    BrowserList* browser_list) {
+  browser_list_observation_.Reset();
+}
diff --git a/ios/chrome/browser/shared/public/features/features.h b/ios/chrome/browser/shared/public/features/features.h
index ee8f21792..26d0406 100644
--- a/ios/chrome/browser/shared/public/features/features.h
+++ b/ios/chrome/browser/shared/public/features/features.h
@@ -648,47 +648,11 @@
 // enabled.
 bool IsIOSKeyboardAccessoryTwoBubbleEnabled();
 
-// Feature that enables tab resumption.
-BASE_DECLARE_FEATURE(kTabResumption);
-
-// Whether the tab resumption feature is enabled.
-bool IsTabResumptionEnabled();
-
-// Feature that enables images for Tab Resumption.
-BASE_DECLARE_FEATURE(kTabResumptionImages);
-
-// A parameter to choose what type of images are enabled in
-// `kTabResumptionImages` experiment (default to all).
-extern const char kTabResumptionImagesTypes[];
-
-// A parameter value for `kTabResumptionImagesTypes` to only enable salient
-// images images for tab resumption.
-extern const char kTabResumptionImagesTypesSalient[];
-
-// A parameter value for `kTabResumptionImagesTypes` to only enable thumbnails
-// images images for tab resumption.
-extern const char kTabResumptionImagesTypesThumbnails[];
-
 // A parameter to indicate whether the native UI is enabled for the discover
 // feed.
 // TODO(crbug.com/40246814): Remove this.
 extern const char kDiscoverFeedIsNativeUIEnabled[];
 
-// Feature parameters for the tab resumption feature. The threshold for tabs
-// fetched from sync in seconds. Default to 12 hours.
-extern const char kTabResumptionThresholdParameterName[];
-
-// Whether the tab resumption with salient images for distant tabs (or fallback
-// for local tabs) is enabled.
-bool IsTabResumptionImagesSalientEnabled();
-
-// Whether the tab resumption with salient images for local tabs is enabled.
-bool IsTabResumptionImagesThumbnailsEnabled();
-
-// Convenience method for determining the tab resumption time threshold for
-// X-Devices tabs only.
-const base::TimeDelta TabResumptionForXDevicesTimeThreshold();
-
 // Kill switch for disabling the navigations when the application is in
 // foreground inactive state after opening an external app.
 BASE_DECLARE_FEATURE(kInactiveNavigationAfterAppLaunchKillSwitch);
diff --git a/ios/chrome/browser/shared/public/features/features.mm b/ios/chrome/browser/shared/public/features/features.mm
index 649b6a4..77d2414 100644
--- a/ios/chrome/browser/shared/public/features/features.mm
+++ b/ios/chrome/browser/shared/public/features/features.mm
@@ -651,53 +651,6 @@
   return base::FeatureList::IsEnabled(kIOSKeyboardAccessoryTwoBubble);
 }
 
-BASE_FEATURE(kTabResumption, base::FEATURE_ENABLED_BY_DEFAULT);
-
-// A parameter to indicate whether the native UI is enabled for the discover
-// feed.
-const char kDiscoverFeedIsNativeUIEnabled[] = "DiscoverFeedIsNativeUIEnabled";
-
-const char kTabResumptionThresholdParameterName[] =
-    "tab-resumption-sync-threshold";
-
-bool IsTabResumptionEnabled() {
-  return base::FeatureList::IsEnabled(kTabResumption);
-}
-
-const base::TimeDelta TabResumptionForXDevicesTimeThreshold() {
-  // Default to 12 hours.
-  int threshold = base::GetFieldTrialParamByFeatureAsInt(
-      kTabResumption, kTabResumptionThresholdParameterName,
-      /*default_value*/ 12 * 3600);
-  return base::Seconds(threshold);
-}
-
-BASE_FEATURE(kTabResumptionImages, base::FEATURE_ENABLED_BY_DEFAULT);
-
-const char kTabResumptionImagesTypes[] = "tr-images-type";
-const char kTabResumptionImagesTypesSalient[] = "salient";
-const char kTabResumptionImagesTypesThumbnails[] = "thumbnails";
-
-bool IsTabResumptionImagesSalientEnabled() {
-  if (!base::FeatureList::IsEnabled(kTabResumptionImages)) {
-    return false;
-  }
-  std::string image_type = base::GetFieldTrialParamByFeatureAsString(
-      kTabResumptionImages, kTabResumptionImagesTypes, "");
-
-  return image_type == kTabResumptionImagesTypesSalient;
-}
-
-bool IsTabResumptionImagesThumbnailsEnabled() {
-  if (!base::FeatureList::IsEnabled(kTabResumptionImages)) {
-    return false;
-  }
-  std::string image_type = base::GetFieldTrialParamByFeatureAsString(
-      kTabResumptionImages, kTabResumptionImagesTypes, "");
-
-  return image_type == kTabResumptionImagesTypesThumbnails || image_type == "";
-}
-
 BASE_FEATURE(kInactiveNavigationAfterAppLaunchKillSwitch,
              "kInactiveNavigationAfterAppLaunchKillSwitch",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/ios/chrome/browser/signin/model/ios_chrome_signin_client.mm b/ios/chrome/browser/signin/model/ios_chrome_signin_client.mm
index 001cfe29..a1df6e3 100644
--- a/ios/chrome/browser/signin/model/ios_chrome_signin_client.mm
+++ b/ios/chrome/browser/signin/model/ios_chrome_signin_client.mm
@@ -32,6 +32,10 @@
         signin::oauth_consumer_name::kEnterprisePlusAddressName,
         {plus_addresses::features::kEnterprisePlusAddressOAuthScope.Get()});
   }
+
+  signin::OAuthConsumer GetOAuthConsumerForGlicUserStatus() const override {
+    NOTREACHED();
+  }
 };
 
 }  // namespace
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/grid_cell.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/grid_cell.mm
index bab706f8..040ccbce 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/grid_cell.mm
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/grid_cell.mm
@@ -109,6 +109,9 @@
 // UI elements for highlighted state.
 // Container for the cell's contents to enable shrinking transform.
 @property(nonatomic, strong) UIView* containerView;
+// Horizontal constraints for `containerView`.
+@property(nonatomic, strong) NSLayoutConstraint* containerLeadingConstraint;
+@property(nonatomic, strong) NSLayoutConstraint* containerTrailingConstraint;
 // Background view to show while cell is highlighted.
 @property(nonatomic, strong) UIView* groupingBackgroundView;
 // Dimming view over the cell contents while cell is highlighted.
@@ -216,6 +219,12 @@
     self.layer.shadowOpacity = 0.5f;
     self.layer.masksToBounds = NO;
     CGFloat margin = IsTabGridEmptyThumbnailUIEnabled() ? kSnapshotInset : 0;
+    self.containerLeadingConstraint = [snapshotView.leadingAnchor
+        constraintEqualToAnchor:contentContainer.leadingAnchor
+                       constant:margin];
+    self.containerTrailingConstraint = [snapshotView.trailingAnchor
+        constraintEqualToAnchor:contentContainer.trailingAnchor
+                       constant:-margin];
     NSArray* constraints = @[
       [topBar.topAnchor constraintEqualToAnchor:contentContainer.topAnchor],
       [topBar.leadingAnchor
@@ -223,12 +232,8 @@
       [topBar.trailingAnchor
           constraintEqualToAnchor:contentContainer.trailingAnchor],
       [snapshotView.topAnchor constraintEqualToAnchor:topBar.bottomAnchor],
-      [snapshotView.leadingAnchor
-          constraintEqualToAnchor:contentContainer.leadingAnchor
-                         constant:margin],
-      [snapshotView.trailingAnchor
-          constraintEqualToAnchor:contentContainer.trailingAnchor
-                         constant:-margin],
+      self.containerLeadingConstraint,
+      self.containerTrailingConstraint,
       [snapshotView.bottomAnchor
           constraintEqualToAnchor:contentContainer.bottomAnchor
                          constant:-margin],
@@ -948,20 +953,19 @@
 }
 
 - (void)positionTabViews {
+  if (!IsNewTabGridTransitionsEnabled()) {
+    self.containerLeadingConstraint.constant = 0;
+    self.containerTrailingConstraint.constant = 0;
+    self.containerView.layer.cornerRadius = 0;
+    self.snapshotView.layer.cornerRadius = 0;
+  }
   [self scaleTabViews];
   self.topBarHeightConstraint.constant = self.topTabView.frame.size.height;
   [self setNeedsUpdateConstraints];
   [self layoutIfNeeded];
   PositionView(self.topTabView, CGPointMake(0, 0));
   // Position the main view so it's top-aligned with the main cell view.
-  CGPoint mainTabViewOrigin = self.mainCellView.frame.origin;
-  if (IsTabGridEmptyThumbnailUIEnabled()) {
-    // With the snapshot inset horizontally to create containerized feel, need
-    // to shift the view to a zero x position so the animation of it aligns with
-    // the frame of the BVC WKWebView.
-    mainTabViewOrigin.x = 0;
-  }
-  PositionView(self.mainTabView, mainTabViewOrigin);
+  PositionView(self.mainTabView, self.mainCellView.frame.origin);
   if (!self.bottomTabView) {
     return;
   }
@@ -973,6 +977,14 @@
 }
 
 - (void)positionCellViews {
+  if (!IsNewTabGridTransitionsEnabled()) {
+    self.containerView.layer.cornerRadius = kGridCellCornerRadius;
+    self.containerLeadingConstraint.constant =
+        IsTabGridEmptyThumbnailUIEnabled() ? kSnapshotInset : 0;
+    self.containerTrailingConstraint.constant =
+        IsTabGridEmptyThumbnailUIEnabled() ? -kSnapshotInset : 0;
+    self.snapshotView.layer.cornerRadius = kGridCellCornerRadius;
+  }
   [self scaleTabViews];
   self.topBarHeightConstraint.constant = [self topBarHeight];
   [self setNeedsUpdateConstraints];
diff --git a/ios/chrome/browser/tabs/model/tabs_dependency_installer.mm b/ios/chrome/browser/tabs/model/tabs_dependency_installer.mm
index 9319a72..523c14e 100644
--- a/ios/chrome/browser/tabs/model/tabs_dependency_installer.mm
+++ b/ios/chrome/browser/tabs/model/tabs_dependency_installer.mm
@@ -40,7 +40,7 @@
                                          public web::WebStateObserver {
  public:
   TabsDependencyInstallationHelper(
-      WebStateList& web_state_list,
+      Browser& browser,
       TabsDependencyInstaller& dependency_installer,
       TabsDependencyInstaller::Policy policy);
   ~TabsDependencyInstallationHelper() override;
@@ -65,6 +65,8 @@
   void OnWebStateAdded(web::WebState* web_state);
   void OnWebStateRemoved(web::WebState* web_state);
 
+  // Original browser that is being observed.
+  const raw_ref<Browser> browser_;
   // The WebStateList being observed for addition, replacement, and detachment
   // of WebStates
   const raw_ref<WebStateList> web_state_list_;
@@ -83,10 +85,11 @@
 };
 
 TabsDependencyInstallationHelper::TabsDependencyInstallationHelper(
-    WebStateList& web_state_list,
+    Browser& browser,
     TabsDependencyInstaller& dependency_installer,
     TabsDependencyInstaller::Policy policy)
-    : web_state_list_(web_state_list),
+    : browser_(browser),
+      web_state_list_(CHECK_DEREF(browser.GetWebStateList())),
       dependency_installer_(dependency_installer),
       wait_for_realization_to_install_dependencies_(
           WaitForRealizationToInstallDependencies(policy)) {
@@ -94,12 +97,24 @@
   for (int i = 0; i < web_state_list_->count(); i++) {
     OnWebStateAdded(web_state_list_->GetWebStateAt(i));
   }
+  // Start tracking TabsDependencyInstaller.
+  TabsDependencyInstallerManager* manager =
+      TabsDependencyInstallerManager::FromBrowser(&*browser_);
+  if (manager) {
+    manager->AddInstaller(&*dependency_installer_);
+  }
 }
 
 TabsDependencyInstallationHelper::~TabsDependencyInstallationHelper() {
   for (int i = 0; i < web_state_list_->count(); i++) {
     OnWebStateRemoved(web_state_list_->GetWebStateAt(i));
   }
+  // Stop tracking TabsDependencyInstaller.
+  TabsDependencyInstallerManager* manager =
+      TabsDependencyInstallerManager::FromBrowser(&*browser_);
+  if (manager) {
+    manager->RemoveInstaller(&*dependency_installer_);
+  }
 }
 
 #pragma mark - WebStateListObserver
@@ -238,12 +253,7 @@
 
 void TabsDependencyInstaller::StartObserving(Browser* browser, Policy policy) {
   installation_helper_ = std::make_unique<TabsDependencyInstallationHelper>(
-      CHECK_DEREF(browser->GetWebStateList()), *this, policy);
-  TabsDependencyInstallerManager* manager =
-      TabsDependencyInstallerManager::FromBrowser(browser);
-  if (manager) {
-    manager->AddInstaller(this);
-  }
+      CHECK_DEREF(browser), *this, policy);
 }
 
 void TabsDependencyInstaller::StopObserving() {
diff --git a/ios/chrome/browser/tabs/model/tabs_dependency_installer_unittest.mm b/ios/chrome/browser/tabs/model/tabs_dependency_installer_unittest.mm
index b6969f9..1bcf2603 100644
--- a/ios/chrome/browser/tabs/model/tabs_dependency_installer_unittest.mm
+++ b/ios/chrome/browser/tabs/model/tabs_dependency_installer_unittest.mm
@@ -15,6 +15,7 @@
 #import "ios/chrome/browser/shared/model/web_state_list/test/fake_web_state_list_delegate.h"
 #import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/shared/model/web_state_list/web_state_opener.h"
+#import "ios/chrome/browser/tabs/model/tabs_dependency_installer_manager.h"
 #import "ios/web/common/features.h"
 #import "ios/web/public/test/fakes/fake_web_state.h"
 #import "ios/web/public/test/web_task_environment.h"
@@ -394,3 +395,31 @@
       WebStateList::InsertionParams::Automatic().Activate());
   EXPECT_FALSE(installer_.WasInstalled(web_state_2_id));
 }
+
+// Verifies that stopping the observation for an installer will uninstall it
+// from the TabsDependencyInstallerManager.
+TEST_P(TabsDependencyInstallerTest, UninstallForManagerAfterDisconnect) {
+  TabsDependencyInstallerManager::CreateForBrowser(browser_.get());
+  TabsDependencyInstallerManager* manager =
+      TabsDependencyInstallerManager::FromBrowser(browser_.get());
+  ASSERT_TRUE(manager);
+  installer_.StartObserving(
+      browser_.get(), std::get<TabsDependencyInstaller::Policy>(GetParam()));
+
+  auto web_state = std::make_unique<web::FakeWebState>();
+  const web::WebStateID web_state_id = web_state->GetUniqueIdentifier();
+
+  manager->InstallDependencies(web_state.get());
+  EXPECT_TRUE(installer_.WasInstalled(web_state_id));
+  EXPECT_EQ(1u, installer_.InstallCount(web_state_id));
+  EXPECT_FALSE(installer_.WasUninstalled(web_state_id));
+
+  installer_.StopObserving();
+
+  manager->UninstallDependencies(web_state.get());
+
+  // The uninstall should not be performed since the test installer stops
+  // observing before the manager starts uninstalling dependencies.
+  EXPECT_FALSE(installer_.WasUninstalled(web_state_id));
+  EXPECT_EQ(0u, installer_.UninstallCount(web_state_id));
+}
diff --git a/ios/chrome/browser/toolbar/ui_bundled/BUILD.gn b/ios/chrome/browser/toolbar/ui_bundled/BUILD.gn
index b3454bb..3376256 100644
--- a/ios/chrome/browser/toolbar/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/toolbar/ui_bundled/BUILD.gn
@@ -208,6 +208,7 @@
     "//components/search_engines",
     "//components/sync_preferences:test_support",
     "//ios/chrome/app/strings",
+    "//ios/chrome/browser/autocomplete/model",
     "//ios/chrome/browser/bookmarks/model",
     "//ios/chrome/browser/collaboration/model/messaging",
     "//ios/chrome/browser/fullscreen/ui_bundled",
diff --git a/ios/chrome/browser/toolbar/ui_bundled/toolbar_coordinator_unittest.mm b/ios/chrome/browser/toolbar/ui_bundled/toolbar_coordinator_unittest.mm
index f423b44..fa10518 100644
--- a/ios/chrome/browser/toolbar/ui_bundled/toolbar_coordinator_unittest.mm
+++ b/ios/chrome/browser/toolbar/ui_bundled/toolbar_coordinator_unittest.mm
@@ -7,6 +7,7 @@
 #import "base/scoped_observation.h"
 #import "base/test/scoped_feature_list.h"
 #import "components/omnibox/browser/omnibox_pref_names.h"
+#import "ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.h"
 #import "ios/chrome/browser/fullscreen/ui_bundled/fullscreen_controller.h"
 #import "ios/chrome/browser/infobars/model/infobar_manager_impl.h"
 #import "ios/chrome/browser/omnibox/model/omnibox_position/omnibox_position_browser_agent.h"
@@ -166,6 +167,7 @@
                      forProtocol:@protocol(BrowserCoordinatorCommands)];
 
     OmniboxPositionBrowserAgent::CreateForBrowser(browser_.get());
+    AutocompleteBrowserAgent::CreateForBrowser(browser_.get());
     // FullscreenController depends on ToolbarsSizeBrowserAgent, so the agent
     // must be created first. Please maintain this order.
     ToolbarsSizeBrowserAgent::CreateForBrowser(browser_.get());
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn
index 7d486c3..caf510e 100644
--- a/ios/chrome/test/earl_grey/BUILD.gn
+++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -125,6 +125,7 @@
     "//ios/chrome/browser/ai_prototyping/test:eg_app_support+eg2",
     "//ios/chrome/browser/authentication/test:eg_app_support+eg2",
     "//ios/chrome/browser/authentication/ui_bundled/cells",
+    "//ios/chrome/browser/autocomplete/model",
     "//ios/chrome/browser/autofill/model",
     "//ios/chrome/browser/autofill/model/automation:eg_app_support+eg2",
     "//ios/chrome/browser/autofill/ui_bundled:eg_app_support+eg2",
diff --git a/ios/chrome/test/earl_grey/chrome_coordinator_app_interface.mm b/ios/chrome/test/earl_grey/chrome_coordinator_app_interface.mm
index c65b46b..dbb7fcb 100644
--- a/ios/chrome/test/earl_grey/chrome_coordinator_app_interface.mm
+++ b/ios/chrome/test/earl_grey/chrome_coordinator_app_interface.mm
@@ -9,6 +9,7 @@
 
 #import "components/language/ios/browser/ios_language_detection_tab_helper.h"
 #import "components/prefs/pref_service.h"
+#import "ios/chrome/browser/autocomplete/model/autocomplete_browser_agent.h"
 #import "ios/chrome/browser/history/ui_bundled/history_coordinator.h"
 #import "ios/chrome/browser/history/ui_bundled/stub_history_coordinator_delegate.h"
 #import "ios/chrome/browser/main/model/browser_impl.h"
@@ -269,6 +270,7 @@
 }
 
 + (void)startOmniboxCoordinator {
+  AutocompleteBrowserAgent::CreateForBrowser(self.helper.browser);
   OmniboxInttestCoordinator* coordinator = [[OmniboxInttestCoordinator alloc]
       initWithBaseViewController:[self rootViewController]
                          browser:self.helper.browser];
diff --git a/ios/chrome/test/swift_interop/chromium/BUILD.gn b/ios/chrome/test/swift_interop/chromium/BUILD.gn
index 4222a6a..43d1635 100644
--- a/ios/chrome/test/swift_interop/chromium/BUILD.gn
+++ b/ios/chrome/test/swift_interop/chromium/BUILD.gn
@@ -15,7 +15,10 @@
 swift_source_set("tests") {
   testonly = true
 
-  sources = [ "sys_info_xctest.swift" ]
+  sources = [
+    "sys_info_xctest.swift",
+    "time_xctest.swift",
+  ]
   cxx_modulemaps = [ "chromium.modulemap" ]
 
   deps = [
diff --git a/ios/chrome/test/swift_interop/chromium/chromium_umbrella.h b/ios/chrome/test/swift_interop/chromium/chromium_umbrella.h
index 331f86a..e0b35d22 100644
--- a/ios/chrome/test/swift_interop/chromium/chromium_umbrella.h
+++ b/ios/chrome/test/swift_interop/chromium/chromium_umbrella.h
@@ -8,5 +8,6 @@
 // TODO(crbug.com/458741717): Remove this file once on swift 6.3
 
 #include "base/system/sys_info.h"
+#include "base/time/time.h"
 
 #endif  // IOS_CHROME_TEST_SWIFT_INTEROP_CHROMIUM_CHROMIUM_UMBRELLA_H_
diff --git a/ios/chrome/test/swift_interop/chromium/time_xctest.swift b/ios/chrome/test/swift_interop/chromium/time_xctest.swift
new file mode 100644
index 0000000..ed1086d2
--- /dev/null
+++ b/ios/chrome/test/swift_interop/chromium/time_xctest.swift
@@ -0,0 +1,46 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import Base
+import XCTest
+
+class TimeTest: XCTestCase {
+
+  func testSeconds() {
+    let ts = timespec(tv_sec: 2, tv_nsec: 0)
+    let timeDelta: base.TimeDelta = base.TimeDelta.FromTimeSpec(ts)
+    XCTAssertEqual(2, timeDelta.InSeconds())
+    XCTAssertEqual(2000, timeDelta.InMilliseconds())
+    XCTAssertEqual(2_000_000, timeDelta.InMicroseconds())
+    XCTAssertEqual(2_000_000_000, timeDelta.InNanoseconds())
+  }
+
+  func testMilliseconds() {
+    let ts = timespec(tv_sec: 0, tv_nsec: 2_000_000)
+    let timeDelta: base.TimeDelta = base.TimeDelta.FromTimeSpec(ts)
+    XCTAssertEqual(0, timeDelta.InSeconds())
+    XCTAssertEqual(2, timeDelta.InMilliseconds())
+    XCTAssertEqual(2000, timeDelta.InMicroseconds())
+    XCTAssertEqual(2_000_000, timeDelta.InNanoseconds())
+  }
+
+  func testMicroseconds() {
+    let ts = timespec(tv_sec: 0, tv_nsec: 2000)
+    let timeDelta: base.TimeDelta = base.TimeDelta.FromTimeSpec(ts)
+    XCTAssertEqual(0, timeDelta.InSeconds())
+    XCTAssertEqual(0, timeDelta.InMilliseconds())
+    XCTAssertEqual(2, timeDelta.InMicroseconds())
+    XCTAssertEqual(2000, timeDelta.InNanoseconds())
+  }
+
+  func testMix() {
+    let ts = timespec(tv_sec: 1, tv_nsec: 20000)
+    let timeDelta: base.TimeDelta = base.TimeDelta.FromTimeSpec(ts)
+    XCTAssertEqual(1, timeDelta.InSeconds())
+    XCTAssertEqual(1000, timeDelta.InMilliseconds())
+    XCTAssertEqual(1_000_020, timeDelta.InMicroseconds())
+    XCTAssertEqual(1_000_020_000, timeDelta.InNanoseconds())
+  }
+
+}
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
index 48abb67a..98aeb13 100644
--- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-b2f9bc0f700ca4fcc8892cd119f9eb25e8766927
\ No newline at end of file
+93a19d9329b4425543a8e59735a71bc6c5a77339
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
index 85026a40..7fb009e 100644
--- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@
-0febdba76d0c8986dd17371719ac530bb48144b4
\ No newline at end of file
+e72591a63815aa6ae1c4c6f0ab2ae4a305239ba7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index f78609e5..dd956f6 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-e46d97316b74284c8fabd4a83b8e10a93d4d4f3b
\ No newline at end of file
+08470f4ff73659655fe89d7b48c05cf393b27caf
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
index 0f1e4d74..b66cb80 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@
-fdd0d611101674153869341e3d79ebe36d18ad6b
\ No newline at end of file
+3e761f1c50aff18030d4c1978ab01963b87ec3e7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index 1fdca8b..f17cda3 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-2ccce183f6fb3ea225c734a75c01008cc0765e59
\ No newline at end of file
+ab18a7e94b4b505fae478a14e70a9417336fefb1
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
index 9bf4ad2f..79ec2be7 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@
-9fa4a102d9d2b2d39a0252713a5901e83a323316
\ No newline at end of file
+fbbe740b46b2def86f3f35ca5e95a4f9b0f848c8
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
index cbe9e9c..cdf4be0 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-f8b6d17e3cbb122bff8d91224801b4953a1e8773
\ No newline at end of file
+ce1ab4b341ce396f1982ffc5f035aac216be4c38
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
index dd7bc737..681c9f7 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-65f25cdfa83f3b279e6c973df881f379e260ce87
\ No newline at end of file
+bb162b47454e0274073ca48bb2e872d239b80883
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
index dcc16e73..4c80cf8d 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-8c3a50e9993e3be7e3c95609f8cbd415d29227c6
\ No newline at end of file
+cc056db1b179249d2ed5d42b7fd3efec3d8889d0
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 68be8cd..dba9e65 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-e12b14376200fda2ce9f7e35939dd8814d76f728
\ No newline at end of file
+c0ff1d8e3ac4214885e0b9ac03e9772ce48ccd1e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index ec20037..a638998 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-8983a7ad04a5ea91c8023d50b060d7dd9c99cf0d
\ No newline at end of file
+de347bb0ac76a556d46db78958836701117656f5
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
index 62ea783..35d97031 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-e5adf55eced29d8fed96f105386926306f88597a
\ No newline at end of file
+f4c54f8d21bafb518eb31baac81e98892ba36f68
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index cf35f6e4cb5..09f6893 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-9079c7b49442a8f9ab1d1f0de660fea8f2a78ab1
\ No newline at end of file
+7a3c3db94146242dd62304c65f11d5ce07a70e4f
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 4a66417..31e0cbe6 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-ccdbe9589714598a88741289d70a7e58bed532fb
\ No newline at end of file
+3bf28f8413af49edcfd00915f8c72f659f820bfe
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index 6450fb7..7cc0b83 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-0c2081741b872f472d272bb8b7b034476e17b7e1
\ No newline at end of file
+56e19826fdc3ca3fe49d918cc5d5be0322bdf01c
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
index f038efa..ad8afb22 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-5e6b24f84a23886dc806f880436c868bfad47abf
\ No newline at end of file
+1789fc6fabf4ad5c9c45da3fa65bc89c8add2d5f
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index ab6f8f8..0c08fa70 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-09ada82ddb4cc8436912bc559d58c2ae3b52d6b5
\ No newline at end of file
+9a9089f006a187ef2b21de7b185a8645feea43a5
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
index c0ad0e4..8199731 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-34253678799ff284043163f979a0bec32ac61d95
\ No newline at end of file
+0d0edb37266c538fcff59a92bfbe690f82dcd3ba
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index ce8cb61..147784d 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-2a596002ad6fd05e67a80f74d8676253a1279d31
\ No newline at end of file
+065c92d6ea4aaec1ee6bacae28a8fcd1e271c044
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index c4833d75..ab415eb 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-0b9a8fe4cf0db3c6307797a9167ba2f51d54c47c
\ No newline at end of file
+18012ef8a793895915b6aa8686dae10da74ed2de
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index cd3d547..38d0afa 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-f43a212086ba89a47ffba0804a5a097c12656983
\ No newline at end of file
+c11ef2c35d676f0e6df02d2379707de32c11f68b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
index d95bef9..b78cf9607 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-b82529e3ad7637e1d3c70070703e32c1641f9f79
\ No newline at end of file
+b3d3ff1e142397071695e54089a55561205d4607
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index 1bad51e3..0dc9eae0 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-cc24068b9d2e92222673c58e35aaf6bbd1708173
\ No newline at end of file
+354caf7c470bdad8bec94b9e3d9660f8bfeab0ed
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 021d7aa5..248a045 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-c1c73e1da65d7748eca146d43b6deb4e0936bb93
\ No newline at end of file
+54c986849ca91864aefb1a44d9134578bfa61c84
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index ddc57af..62e1ce9 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-7b103e297e510349221b3a3a7128d5847c0676ab
\ No newline at end of file
+d5bb4f6835c9cae95acfc663aa7739ca55777f58
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
index 9f74487..64891c4f 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-b5ee2cc798834117f356ad23c5db407ec3cb8d27
\ No newline at end of file
+0617a5207cddad4b43abb24157321647dc43b466
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index bb6a4d5..8fa3285e 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-19eb10fd6fac34d5a719ac9b051cdced20e35fce
\ No newline at end of file
+fdc9d40cbcab0a9d855ffab3b122cf8731e46e5a
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
index b2ebc8c0..db229b86 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-84714f07ca8ad952ccb9af88501be2f877cc8c52
\ No newline at end of file
+4f015280a1ce93b5e5d9d16c6e6e9a01eb2fab61
\ No newline at end of file
diff --git a/ios/web_view/internal/signin/ios_web_view_signin_client.mm b/ios/web_view/internal/signin/ios_web_view_signin_client.mm
index 5055c50..e4e6d2f 100644
--- a/ios/web_view/internal/signin/ios_web_view_signin_client.mm
+++ b/ios/web_view/internal/signin/ios_web_view_signin_client.mm
@@ -25,6 +25,10 @@
         signin::oauth_consumer_name::kEnterprisePlusAddressName,
         {plus_addresses::features::kEnterprisePlusAddressOAuthScope.Get()});
   }
+
+  signin::OAuthConsumer GetOAuthConsumerForGlicUserStatus() const override {
+    NOTREACHED();
+  }
 };
 
 }  // namespace
diff --git a/ios_internal b/ios_internal
index b751aae..fd52a14 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit b751aaeca79d1952ef7631a2e83fbb5b00c133b8
+Subproject commit fd52a146a6011abcc1c9c18a07f113fa192a9161
diff --git a/media/mojo/mojom/media_types.mojom b/media/mojo/mojom/media_types.mojom
index 282db1a6..1133754 100644
--- a/media/mojo/mojom/media_types.mojom
+++ b/media/mojo/mojom/media_types.mojom
@@ -508,9 +508,7 @@
 struct SharedImageVideoFrameData {
   gpu.mojom.ExportedSharedImage shared_image;
   gpu.mojom.SyncToken sync_token;
-  // TODO(crbug.com/40263579): Remove this bool once all VideoFrame
-  // clients use MappableSI.
-  bool is_mappable_si_enabled;
+  bool is_mappable;
   // |ycbcr_data| is present on Android when the
   // video is hardware decoded and the display compositor uses Vulkan.
   [EnableIf=is_android]
diff --git a/media/mojo/mojom/video_frame_mojom_traits.cc b/media/mojo/mojom/video_frame_mojom_traits.cc
index 6b07388..8b42ffd 100644
--- a/media/mojo/mojom/video_frame_mojom_traits.cc
+++ b/media/mojo/mojom/video_frame_mojom_traits.cc
@@ -115,7 +115,6 @@
             std::move(region), std::move(strides), std::move(offsets)));
   }
 
-  bool is_mappable_si_enabled = input->HasMappableSharedImage();
   if (input->HasMappableSharedImage()) {
     auto gpu_memory_buffer_handle = input->GetGpuMemoryBufferHandle();
 
@@ -123,7 +122,6 @@
     std::optional<gpu::ExportedSharedImage> shared_image;
     gpu::SyncToken sync_token;
     CHECK(input->HasSharedImage());
-    CHECK(is_mappable_si_enabled);
     shared_image = input->shared_image()->Export(
         /*with_buffer_handle=*/true);
     sync_token = input->acquire_sync_token();
@@ -131,30 +129,27 @@
     return media::mojom::VideoFrameData::NewSharedImageData(
         media::mojom::SharedImageVideoFrameData::New(
             std::move(shared_image.value()), std::move(sync_token),
-            /*is_mappable_si_enabled=*/true, std::move(input->ycbcr_info())));
+            /*is_mappable=*/true, std::move(input->ycbcr_info())));
 #else
     return media::mojom::VideoFrameData::NewSharedImageData(
         media::mojom::SharedImageVideoFrameData::New(
             std::move(shared_image.value()), std::move(sync_token),
-            /*is_mappable_si_enabled=*/true));
+            /*is_mappable=*/true));
 #endif
   }
 
   if (input->HasSharedImage()) {
-    // Mappable SI should only be used with `HasMappableSharedImage()`
-    // VideoFrames.
-    CHECK(!is_mappable_si_enabled);
     gpu::ExportedSharedImage shared_image = input->shared_image()->Export();
 #if BUILDFLAG(IS_ANDROID)
     return media::mojom::VideoFrameData::NewSharedImageData(
         media::mojom::SharedImageVideoFrameData::New(
             std::move(shared_image), input->acquire_sync_token(),
-            /*is_mappable_si_enabled=*/false, std::move(input->ycbcr_info())));
+            /*is_mappable=*/false, std::move(input->ycbcr_info())));
 #else
     return media::mojom::VideoFrameData::NewSharedImageData(
         media::mojom::SharedImageVideoFrameData::New(
             std::move(shared_image), input->acquire_sync_token(),
-            /*is_mappable_si_enabled=*/false));
+            /*is_mappable=*/false));
 #endif
   }
 
@@ -355,9 +350,9 @@
       return false;
     }
 
-    bool is_mappable_si_enabled = shared_image_data.is_mappable_si_enabled();
-    if (is_mappable_si_enabled) {
-      // VideoFrame should have buffer usage if Mappable SharedImage is enabled.
+    bool is_mappable = shared_image_data.is_mappable();
+    if (is_mappable) {
+      // VideoFrame should have buffer usage if its SI is mappable.
       // NOTE: This isn't exactly correct for software SharedImages can be
       // mappable but do not have buffer usage. But since, such software
       // SharedImages are not used with VideoFrames this should work.
diff --git a/media/renderers/video_frame_yuv_converter.cc b/media/renderers/video_frame_yuv_converter.cc
index daa8578..de1e3a4f 100644
--- a/media/renderers/video_frame_yuv_converter.cc
+++ b/media/renderers/video_frame_yuv_converter.cc
@@ -101,7 +101,6 @@
 
   // This SharedImage will be written to (and later read from) via the raster
   // interface.
-  CHECK(raster_context_provider->ContextCapabilities().gpu_rasterization);
   gpu::SharedImageUsageSet src_usage = gpu::SHARED_IMAGE_USAGE_RASTER_READ |
                                        gpu::SHARED_IMAGE_USAGE_RASTER_WRITE;
 
diff --git a/net/socket/client_socket_pool.h b/net/socket/client_socket_pool.h
index 87150ef6..04e9fd18 100644
--- a/net/socket/client_socket_pool.h
+++ b/net/socket/client_socket_pool.h
@@ -411,8 +411,16 @@
 
   SocketPoolState State() const { return state_; }
 
+  // This should be called exactly once before each attempted socket allocation
+  // via `RequestSocket` or `RequestSockets`. Be sure not to over-invoke to
+  // prevent early capping of the socket pool.
   void UpdateStateBeforeAllocation();
 
+  // This should be called once after each successful socket released (and not
+  // reused) via `RequestSocket`, `RequestSockets`, `CancelRequest`,
+  // `ReleaseSocket`, `OnConnectJobComplete`, `CloseIdleSockets`, or
+  // `CloseIdleSocketsInGroup`. Be sure not to over-invoke to prevent early
+  // uncapping of the socket pool.
   void UpdateStateAfterRelease();
 
   // This is used to reset the pool to the initial uncapped state when the
diff --git a/net/socket/transport_client_socket_pool.cc b/net/socket/transport_client_socket_pool.cc
index 6bb762ce..142935b 100644
--- a/net/socket/transport_client_socket_pool.cc
+++ b/net/socket/transport_client_socket_pool.cc
@@ -936,12 +936,6 @@
   }
 }
 
-bool TransportClientSocketPool::CloseOneIdleSocket() {
-  if (idle_socket_count_ == 0)
-    return false;
-  return CloseOneIdleSocketExceptInGroup(nullptr);
-}
-
 bool TransportClientSocketPool::CloseOneIdleConnectionInHigherLayeredPool() {
   // This pool doesn't have any idle sockets. It's possible that a pool at a
   // higher layer is holding one of this sockets active, but it's actually idle.
@@ -987,6 +981,7 @@
           reason_for_closing_socket);
       idle_socket_it = group->mutable_idle_sockets()->erase(idle_socket_it);
       DecrementIdleCount();
+      UpdateStateAfterRelease();
     } else {
       DCHECK(!reason_for_closing_socket);
       ++idle_socket_it;
@@ -1108,7 +1103,9 @@
 
     if (State() == SocketPoolState::kCapped) {
       if (idle_socket_count_ > 0) {
-        CloseOneIdleSocket();
+        if (CloseOneIdleSocketExceptInGroup(nullptr)) {
+          UpdateStateAfterRelease();
+        }
       } else {
         // We can't activate more sockets since we're already at our global
         // limit.
@@ -1367,6 +1364,7 @@
                               bound_request->request->socket_tag());
       bound_request->request->net_log().EndEventWithNetErrorCode(
           NetLogEventType::SOCKET_POOL, bound_request->pending_error);
+      UpdateStateAfterRelease();
       OnAvailableSocketSlot(group->group_id(), group);
       CheckForStalledSocketGroups();
       return;
@@ -1376,6 +1374,7 @@
     // the group, and kick off another request. The socket will be discarded.
     if (bound_request->generation != group->generation()) {
       group->InsertUnboundRequest(std::move(bound_request->request));
+      UpdateStateAfterRelease();
       OnAvailableSocketSlot(group->group_id(), group);
       CheckForStalledSocketGroups();
       return;
@@ -1392,6 +1391,9 @@
       if (result == OK)
         AddIdleSocket(job->PassSocket(), group);
       RemoveConnectJob(job, group);
+      if (result != OK) {
+        UpdateStateAfterRelease();
+      }
       OnAvailableSocketSlot(group->group_id(), group);
       CheckForStalledSocketGroups();
       return;
@@ -1419,6 +1421,7 @@
     RemoveConnectJob(job, group);
   // If no socket was handed out, there's a new socket slot available.
   if (!request->handle()->socket()) {
+    UpdateStateAfterRelease();
     OnAvailableSocketSlot(group->group_id(), group);
     CheckForStalledSocketGroups();
   }
diff --git a/net/socket/transport_client_socket_pool.h b/net/socket/transport_client_socket_pool.h
index c4e2a4b..24ee65c 100644
--- a/net/socket/transport_client_socket_pool.h
+++ b/net/socket/transport_client_socket_pool.h
@@ -654,13 +654,6 @@
   // |reason| must be non-empty when |force| is true.
   void CleanupIdleSockets(bool force, const char* net_log_reason_utf8);
 
-  // Closes one idle socket.  Picks the first one encountered.
-  // TODO(willchan): Consider a better algorithm for doing this.  Perhaps we
-  // should keep an ordered list of idle sockets, and close them in order.
-  // Requires maintaining more state.  It's not clear if it's worth it since
-  // I'm not sure if we hit this situation often.
-  bool CloseOneIdleSocket();
-
   // Checks higher layered pools to see if they can close an idle connection.
   bool CloseOneIdleConnectionInHigherLayeredPool();
 
diff --git a/net/socket/websocket_transport_client_socket_pool.cc b/net/socket/websocket_transport_client_socket_pool.cc
index 24f75db6..7555d96 100644
--- a/net/socket/websocket_transport_client_socket_pool.cc
+++ b/net/socket/websocket_transport_client_socket_pool.cc
@@ -169,12 +169,12 @@
     ReleaseSocket(handle->group_id(), std::move(socket),
                   handle->group_generation());
   if (DeleteJob(handle)) {
+    UpdateStateAfterRelease();
     CHECK(!base::Contains(pending_callbacks_,
                           reinterpret_cast<ClientSocketHandleID>(handle)));
   } else {
     pending_callbacks_.erase(reinterpret_cast<ClientSocketHandleID>(handle));
   }
-  UpdateStateAfterRelease();
 
   ActivateStalledRequest();
 }
@@ -355,8 +355,10 @@
 
   connect_job_delegate = nullptr;
 
-  if (!handed_out_socket)
+  if (!handed_out_socket) {
+    UpdateStateAfterRelease();
     ActivateStalledRequest();
+  }
 
   InvokeUserCallbackLater(handle, std::move(callback), result);
 }
diff --git a/remoting/host/installer/linux/BUILD.gn b/remoting/host/installer/linux/BUILD.gn
index c51c41b..00f15da 100644
--- a/remoting/host/installer/linux/BUILD.gn
+++ b/remoting/host/installer/linux/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/config/zip.gni")
+import("//build/timestamp.gni")
 import("//remoting/build/config/remoting_build.gni")
 import("//remoting/host/installer/credits.gni")
 import("//remoting/remoting_locales.gni")
@@ -106,6 +107,8 @@
     rebase_path("//", root_build_dir),
     "-o",
     ".",
+    "-b",
+    build_timestamp,
   ]
   inputs += [ "//remoting/host/installer/linux/chrome-remote-desktop@.service" ]
 
diff --git a/remoting/host/installer/linux/build-deb.sh b/remoting/host/installer/linux/build-deb.sh
index 5113785..8b5771b 100755
--- a/remoting/host/installer/linux/build-deb.sh
+++ b/remoting/host/installer/linux/build-deb.sh
@@ -49,9 +49,10 @@
   echo "-s     path to the top of the src tree."
   echo "-o     output directory path."
   echo "-O     option (no options currently defined)"
+  echo "-b     build timestamp (Epoch seconds)"
 }
 
-while getopts ":s:o:O:ph" OPTNAME
+while getopts ":s:o:O:phb:" OPTNAME
 do
   case $OPTNAME in
     s )
@@ -66,6 +67,9 @@
     O )
       OPTION="$OPTARG"
       ;;
+    b )
+      BUILD_TIMESTAMP="$OPTARG"
+      ;;
     h )
       usage
       exit 0
@@ -131,7 +135,13 @@
   --force-distribution \
   --distribution unstable \
   "New Debian package $revision_text"
-
+# Manually overwrite the trailer line to force the timestamp for reproducible
+# builds. Without this, debchange uses the current system time (localtime).
+# NOTE: When debchange --date is properly supported in the build environment,
+# this sed command should be removed and --date "$DATE_RFC5322" added to the
+# debchange command above.
+DATE_RFC5322="$(date --rfc-email -d "@$BUILD_TIMESTAMP")"
+sed -i "s/^ -- $DEBEMAIL .*/ -- $DEBEMAIL  $DATE_RFC5322/" debian/changelog
 
 CRON_SCRIPT_DIR="${OUTPUT_PATH}/remoting/installer/cron"
 mkdir -p ${CRON_SCRIPT_DIR}
@@ -147,7 +157,8 @@
 # but it seems that we don't currently, so this is the most expediant fix.
 SAVE_LDLP=$LD_LIBRARY_PATH
 unset LD_LIBRARY_PATH
-BUILD_DIR=$OUTPUT_PATH SRC_DIR=${SCRIPTDIR}/../../../.. \
+SOURCE_DATE_EPOCH="$BUILD_TIMESTAMP" \
+  BUILD_DIR=$OUTPUT_PATH SRC_DIR=${SCRIPTDIR}/../../../.. \
   dpkg-buildpackage -b -us -uc
 LD_LIBRARY_PATH=$SAVE_LDLP
 
diff --git a/third_party/angle b/third_party/angle
index 0c0d10c..1724ab3 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit 0c0d10c4914aa427d1fe969508ca327fbeece913
+Subproject commit 1724ab3641c825d2ed6fc76e20c3d20301e73696
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 7539c7d0..126fa052 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -368,6 +368,9 @@
 BASE_FEATURE(kClearSiteDataPrefetchPrerenderCache,
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+// Fix for CSS font comparison logic.
+BASE_FEATURE(kCSSFontComparisonFix, base::FEATURE_ENABLED_BY_DEFAULT);
+
 // Enable legacy `dpr` client hint.
 BASE_FEATURE(kClientHintsDPR_DEPRECATED, base::FEATURE_ENABLED_BY_DEFAULT);
 
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 4bb1387..bb01a62 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -228,6 +228,9 @@
 // "prerenderCache" to clear the Prefetch and Prerender caches respectively.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kClearSiteDataPrefetchPrerenderCache);
 
+// Fix for CSS font comparison logic.
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kCSSFontComparisonFix);
+
 // We do intend to deprecate these when possible, do not remove the feature
 // until they can be disabled by default.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kClientHintsDeviceMemory_DEPRECATED);
diff --git a/third_party/blink/renderer/core/css/container_query_evaluator.cc b/third_party/blink/renderer/core/css/container_query_evaluator.cc
index 11baf86..605ab38 100644
--- a/third_party/blink/renderer/core/css/container_query_evaluator.cc
+++ b/third_party/blink/renderer/core/css/container_query_evaluator.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/blink/renderer/core/css/container_query_evaluator.h"
 
+#include "base/feature_list.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom-blink.h"
 #include "third_party/blink/renderer/core/css/container_query.h"
 #include "third_party/blink/renderer/core/css/container_state.h"
@@ -975,7 +977,9 @@
   // the container values and invalidate style for any changed queries.
   bool invalidate_for_font =
       (unit_flags_ & MediaQueryExpValue::kFontRelative) &&
-      !base::ValuesEquivalent(old_style.GetFont(), new_style.GetFont());
+      (base::FeatureList::IsEnabled(blink::features::kCSSFontComparisonFix)
+           ? !base::ValuesEquivalent(old_style.GetFont(), new_style.GetFont())
+           : old_style.GetFont() != new_style.GetFont());
 
   // Writing direction changes may affect how logical queries match for size and
   // scroll-state() queries even when the physical size or scroll-state do not
diff --git a/third_party/blink/renderer/core/css/style_element.cc b/third_party/blink/renderer/core/css/style_element.cc
index be717d4..995ca52 100644
--- a/third_party/blink/renderer/core/css/style_element.cc
+++ b/third_party/blink/renderer/core/css/style_element.cc
@@ -49,6 +49,7 @@
 #include "third_party/blink/renderer/platform/json/json_values.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
 
 namespace blink {
 
@@ -290,7 +291,8 @@
     // string size in memory (at the expense of decoding on the CPU).
     url_string = StrCat({"data:text/css,", EncodeWithURLEscapeSequences(text)});
   } else {
-    auto* blob = Blob::Create(text.Span8(), "text/css");
+    StringUtf8Adaptor utf8(text, Utf8ConversionMode::kLenient);
+    auto* blob = Blob::Create(base::as_byte_span(utf8), "text/css");
     CHECK(blob);
     url_string = DOMURL::CreatePublicURL(context, blob);
   }
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc
index f1cb26eb..a4c6667 100644
--- a/third_party/blink/renderer/core/css/style_engine.cc
+++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -33,8 +33,10 @@
 
 #include "base/auto_reset.h"
 #include "base/containers/adapters.h"
+#include "base/feature_list.h"
 #include "base/hash/hash.h"
 #include "base/rand_util.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/timing/resource_timing.mojom-blink.h"
 #include "third_party/blink/renderer/core/css/cascade_layer_map.h"
 #include "third_party/blink/renderer/core/css/cascade_layered.h"
@@ -3268,8 +3270,10 @@
   bool root_font_glyphs_changed =
       !old_root_style ||
       (UsesGlyphRelativeUnits() &&
-       !base::ValuesEquivalent<Font>(old_root_style->GetFont(),
-                                     new_root_style->GetFont()));
+       (base::FeatureList::IsEnabled(blink::features::kCSSFontComparisonFix)
+            ? !base::ValuesEquivalent<Font>(old_root_style->GetFont(),
+                                            new_root_style->GetFont())
+            : old_root_style->GetFont() != new_root_style->GetFont()));
   bool root_line_height_changed =
       !old_root_style ||
       (UsesLineHeightUnits() &&
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.cc b/third_party/blink/renderer/core/html/media/html_video_element.cc
index d18b245..ae0c2e05 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_video_element.cc
@@ -63,7 +63,7 @@
 #include "third_party/blink/renderer/core/loader/document_loader.h"
 #include "third_party/blink/renderer/core/loader/resource/video_timing.h"
 #include "third_party/blink/renderer/core/paint/timing/paint_timing_detector.h"
-#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_snapshot_provider.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/extensions_3d_util.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
@@ -351,7 +351,7 @@
 }
 
 void HTMLVideoElement::ResetCache(TimerBase*) {
-  resource_provider_.reset();
+  snapshot_provider_.reset();
 }
 
 bool HTMLVideoElement::IsPersistent() const {
@@ -575,12 +575,12 @@
   gfx::ColorSpace dest_color_space =
       reinterpret_as_srgb ? gfx::ColorSpace::CreateSRGB()
                           : media_video_frame->CompatRGBColorSpace();
-  if (!resource_provider_ ||
-      (resource_provider_->IsAccelerated() &&
-       resource_provider_->IsGpuContextLost()) ||
+  if (!snapshot_provider_ ||
+      (snapshot_provider_->IsAccelerated() &&
+       snapshot_provider_->IsGpuContextLost()) ||
       allow_accelerated_images != allow_accelerated_images_ ||
-      dest_size != resource_provider_->Size() ||
-      dest_color_space != resource_provider_->GetColorSpace()) {
+      dest_size != snapshot_provider_->Size() ||
+      dest_color_space != snapshot_provider_->GetColorSpace()) {
     viz::RasterContextProvider* raster_context_provider = nullptr;
     if (allow_accelerated_images) {
       if (auto wrapper = SharedGpuContext::ContextProviderWrapper()) {
@@ -588,22 +588,23 @@
             wrapper->ContextProvider().RasterContextProvider();
       }
     }
-    resource_provider_.reset();
+    snapshot_provider_.reset();
     // Providing a null |raster_context_provider| creates a software provider.
     // TODO(https://crbug.com/1341235): The choice of color type and alpha type
     // is inappropriate in many circumstances.
-    resource_provider_ = CreateResourceProviderForVideoFrame(
+    snapshot_provider_ = CreateSnapshotProviderForVideoFrame(
         dest_size, GetN32FormatForCanvas(), kPremul_SkAlphaType,
         dest_color_space, raster_context_provider);
-    if (!resource_provider_)
+    if (!snapshot_provider_) {
       return nullptr;
+    }
     allow_accelerated_images_ = allow_accelerated_images;
   }
   cache_deleting_timer_.StartOneShot(kTemporaryResourceDeletionDelay,
                                      FROM_HERE);
 
   auto image = CreateImageFromVideoFrame(
-      std::move(media_video_frame), resource_provider_.get(), video_renderer,
+      std::move(media_video_frame), snapshot_provider_.get(), video_renderer,
       /*prefer_tagged_orientation=*/true, reinterpret_as_srgb);
   if (image)
     image->SetOriginClean(!WouldTaintOrigin());
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.h b/third_party/blink/renderer/core/html/media/html_video_element.h
index 29995d358..6a3ab8d 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.h
+++ b/third_party/blink/renderer/core/html/media/html_video_element.h
@@ -32,7 +32,7 @@
 #include "third_party/blink/renderer/core/html/html_image_loader.h"
 #include "third_party/blink/renderer/core/html/media/html_media_element.h"
 #include "third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h"
-#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_snapshot_provider.h"
 #include "third_party/blink/renderer/platform/timer.h"
 
 namespace blink {
@@ -98,7 +98,7 @@
 
   // Helper for GetSourceImageForCanvas() and other external callers who want a
   // StaticBitmapImage of the current VideoFrame. If `allow_accelerated_images`
-  // is set to false a software backed CanvasResourceProvider will be used to
+  // is set to false a software backed CanvasSnapshotProvider will be used to
   // produce the StaticBitmapImage. If `size` is specified, the image will be
   // scaled to it, otherwise the image will be in its natural size. If
   // `reinterpret_as_srgb` is true, then reinterpret the video as thought it
@@ -279,7 +279,7 @@
 
   // Used to fulfill blink::Image requests (CreateImage(),
   // GetSourceImageForCanvas(), etc). Created on demand.
-  std::unique_ptr<CanvasResourceProvider> resource_provider_;
+  std::unique_ptr<CanvasSnapshotProvider> snapshot_provider_;
   bool allow_accelerated_images_ = true;
   HeapTaskRunnerTimer<HTMLVideoElement> cache_deleting_timer_;
 
diff --git a/third_party/blink/renderer/core/inspector/inspect_tools.cc b/third_party/blink/renderer/core/inspector/inspect_tools.cc
index 769a8f0..a36f7fb 100644
--- a/third_party/blink/renderer/core/inspector/inspect_tools.cc
+++ b/third_party/blink/renderer/core/inspector/inspect_tools.cc
@@ -802,16 +802,19 @@
     auto task_runner =
         overlay_->GetFrame()->GetTaskRunner(TaskType::kInternalInspector);
     if (message_string == "resume") {
-      task_runner->PostTask(FROM_HERE,
-                            BindOnce(&v8_inspector::V8InspectorSession::resume,
-                                     Unretained(v8_session_),
-                                     /* setTerminateOnResume */ false));
+      task_runner->PostTask(
+          FROM_HERE,
+          blink::BindOnce(&PausedInDebuggerTool::ExecuteOnV8Session,
+                          WrapPersistent(weak_factory_.GetWeakCell()),
+                          Action::kResume));
       return;
     }
     if (message_string == "stepOver") {
       task_runner->PostTask(
-          FROM_HERE, BindOnce(&v8_inspector::V8InspectorSession::stepOver,
-                              Unretained(v8_session_)));
+          FROM_HERE,
+          blink::BindOnce(&PausedInDebuggerTool::ExecuteOnV8Session,
+                          WrapPersistent(weak_factory_.GetWeakCell()),
+                          Action::kStepOver));
       return;
     }
   }
@@ -819,6 +822,30 @@
                                     kInvalidOverlayCommand);
 }
 
+void PausedInDebuggerTool::ExecuteOnV8Session(Action action) {
+  if (!v8_session_) {
+    return;
+  }
+
+  switch (action) {
+    case Action::kResume:
+      v8_session_->resume(/* setTerminateOnResume */ false);
+      break;
+    case Action::kStepOver:
+      v8_session_->stepOver();
+      break;
+  }
+}
+
+void PausedInDebuggerTool::OnAgentDisable() {
+  v8_session_ = nullptr;
+}
+
+void PausedInDebuggerTool::Trace(Visitor* visitor) const {
+  InspectTool::Trace(visitor);
+  visitor->Trace(weak_factory_);
+}
+
 // WcoTool --------------------------------------------------------
 
 WindowControlsOverlayTool::WindowControlsOverlayTool(
diff --git a/third_party/blink/renderer/core/inspector/inspect_tools.h b/third_party/blink/renderer/core/inspector/inspect_tools.h
index c8ccf076..5336a4b 100644
--- a/third_party/blink/renderer/core/inspector/inspect_tools.h
+++ b/third_party/blink/renderer/core/inspector/inspect_tools.h
@@ -5,12 +5,14 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECT_TOOLS_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECT_TOOLS_H_
 
+#include <v8-inspector.h>
+
 #include <vector>
 
-#include <v8-inspector.h>
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/core/inspector/inspector_overlay_agent.h"
 #include "third_party/blink/renderer/core/inspector/node_content_visibility_state.h"
+#include "third_party/blink/renderer/platform/heap/weak_cell.h"
 
 namespace blink {
 
@@ -237,14 +239,21 @@
         message_(message) {}
   PausedInDebuggerTool(const PausedInDebuggerTool&) = delete;
   PausedInDebuggerTool& operator=(const PausedInDebuggerTool&) = delete;
+  void Trace(Visitor* visitor) const override;
 
  private:
+  enum class Action { kResume, kStepOver };
+
   void Draw(float scale) override;
   void Dispatch(const ScriptValue& message,
                 ExceptionState& exception_state) override;
   String GetOverlayName() override;
+  void OnAgentDisable() override;
+  void ExecuteOnV8Session(Action action);
+
   v8_inspector::V8InspectorSession* v8_session_;
   String message_;
+  WeakCellFactory<PausedInDebuggerTool> weak_factory_{this};
 };
 
 // -----------------------------------------------------------------------------
diff --git a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
index ef665e1..74aa9d51b 100644
--- a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
@@ -529,6 +529,9 @@
 
   persistent_tool_ = nullptr;
   hinge_ = nullptr;
+  if (inspect_tool_) {
+    inspect_tool_->OnAgentDisable();
+  }
   PickTheRightTool();
   SetNeedsUnbufferedInput(false);
   document_to_ax_context_.clear();
diff --git a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
index 0256d9a..70b6279 100644
--- a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
@@ -119,6 +119,7 @@
   virtual void Trace(Visitor* visitor) const;
   virtual bool HideOnHideHighlight();
   virtual bool HideOnMouseMove();
+  virtual void OnAgentDisable() {}
 
  protected:
   Member<InspectorOverlayAgent> overlay_;
diff --git a/third_party/blink/renderer/core/layout/inline/inline_box_state.cc b/third_party/blink/renderer/core/layout/inline/inline_box_state.cc
index e49850e..a45005e 100644
--- a/third_party/blink/renderer/core/layout/inline/inline_box_state.cc
+++ b/third_party/blink/renderer/core/layout/inline/inline_box_state.cc
@@ -5,6 +5,8 @@
 #include "third_party/blink/renderer/core/layout/inline/inline_box_state.h"
 
 #include "base/containers/adapters.h"
+#include "base/feature_list.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/renderer/core/layout/box_fragment_builder.h"
 #include "third_party/blink/renderer/core/layout/geometry/logical_offset.h"
 #include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
@@ -274,7 +276,9 @@
     return false;
   DCHECK(style);
   if (style == &text_style ||
-      base::ValuesEquivalent(style->GetFont(), text_style.GetFont()) ||
+      (base::FeatureList::IsEnabled(blink::features::kCSSFontComparisonFix)
+           ? base::ValuesEquivalent(style->GetFont(), text_style.GetFont())
+           : style->GetFont() == text_style.GetFont()) ||
       style->GetFont()->PrimaryFont() == text_style.GetFont()->PrimaryFont()) {
     return true;
   }
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
index aee7f0a..576cf2f 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
@@ -24,6 +24,8 @@
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
 
 #include "base/auto_reset.h"
+#include "base/feature_list.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/renderer/core/editing/position_with_affinity.h"
 #include "third_party/blink/renderer/core/frame/frame_owner.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -269,7 +271,9 @@
   // any other font-relative unit), any changes to the font may change said
   // dimensions.
   if (IntrinsicSizeIsFontMetricsDependent() &&
-      !base::ValuesEquivalent(old_style.GetFont(), style.GetFont())) {
+      (base::FeatureList::IsEnabled(blink::features::kCSSFontComparisonFix)
+           ? !base::ValuesEquivalent(old_style.GetFont(), style.GetFont())
+           : old_style.GetFont() != style.GetFont())) {
     return true;
   }
   return false;
diff --git a/third_party/blink/renderer/core/paint/outline_painter.cc b/third_party/blink/renderer/core/paint/outline_painter.cc
index 3fa78f5..cf12b5a 100644
--- a/third_party/blink/renderer/core/paint/outline_painter.cc
+++ b/third_party/blink/renderer/core/paint/outline_painter.cc
@@ -800,13 +800,15 @@
   return FloatRoundedRect::Radii(DefaultFocusRingCornerRadius(style));
 }
 
-void PaintSingleFocusRing(GraphicsContext& context,
-                          const Vector<gfx::Rect>& rects,
-                          float width,
-                          int offset,
-                          const FloatRoundedRect::Radii& corner_radii,
-                          const Color& color,
-                          const AutoDarkMode& auto_dark_mode) {
+void PaintSingleFocusRing(
+    GraphicsContext& context,
+    const Vector<gfx::Rect>& rects,
+    float width,
+    int offset,
+    const FloatRoundedRect::Radii& corner_radii,
+    const ContouredRect::CornerCurvature& corner_curvature,
+    const Color& color,
+    const AutoDarkMode& auto_dark_mode) {
   DCHECK(!rects.empty());
   SkPath path;
   if (!ComputeRightAnglePath(path, rects, offset, 0))
@@ -814,9 +816,22 @@
 
   SkRect rect;
   if (path.isRect(&rect)) {
-    context.DrawFocusRingRect(
-        SkRRect(FloatRoundedRect(gfx::SkRectToRectF(rect), corner_radii)),
-        color, width, auto_dark_mode);
+    if (corner_curvature.IsRound()) {
+      context.DrawFocusRingRect(
+          SkRRect(FloatRoundedRect(gfx::SkRectToRectF(rect), corner_radii)),
+          color, width, auto_dark_mode);
+    } else {
+      ContouredRect border_rect(
+          FloatRoundedRect(gfx::SkRectToRectF(rect), corner_radii),
+          corner_curvature);
+      ContouredRect contour(border_rect);
+      const auto outset = AdjustedOutlineOffset(rects[0], offset);
+      contour.OutsetWithCornerCorrection(gfx::OutsetsF::TLBR(
+          outset.top(), outset.left(), outset.bottom(), outset.right()));
+      contour.SetOriginRect(border_rect.AsRoundedRect());
+      context.DrawFocusRingPath(contour.GetPath().GetSkPath(), color, width, 0,
+                                auto_dark_mode);
+    }
     return;
   }
 
@@ -849,17 +864,30 @@
   const float inner_ring_width = FocusRingInnerStrokeWidth(style);
   const int offset = FocusRingOffset(style, info);
 
+  const ContouredRect::CornerCurvature corner_curvature(
+      corner_radii.TopLeft().IsEmpty() ? ContouredRect::CornerCurvature::kRound
+                                       : style.CornerTopLeftShape().Exponent(),
+      corner_radii.TopRight().IsEmpty()
+          ? ContouredRect::CornerCurvature::kRound
+          : style.CornerTopRightShape().Exponent(),
+      corner_radii.BottomRight().IsEmpty()
+          ? ContouredRect::CornerCurvature::kRound
+          : style.CornerBottomRightShape().Exponent(),
+      corner_radii.BottomLeft().IsEmpty()
+          ? ContouredRect::CornerCurvature::kRound
+          : style.CornerBottomLeftShape().Exponent());
+
   Color outer_color =
       style.DarkColorScheme() ? Color(0x10, 0x10, 0x10) : Color::kWhite;
   PaintSingleFocusRing(context, rects, outer_ring_width,
                        offset + std::ceil(inner_ring_width), corner_radii,
-                       outer_color, AutoDarkMode::Disabled());
+                       corner_curvature, outer_color, AutoDarkMode::Disabled());
   // Draw the inner ring using |outer_ring_width| (which should be wider than
   // the additional offset of the outer ring) over the outer ring to ensure no
   // gaps or AA artifacts.
   DCHECK_GE(outer_ring_width, std::ceil(inner_ring_width));
   PaintSingleFocusRing(context, rects, outer_ring_width, offset, corner_radii,
-                       inner_color, AutoDarkMode::Disabled());
+                       corner_curvature, inner_color, AutoDarkMode::Disabled());
 }
 
 }  // anonymous namespace
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
index 64f5c6a..253c463 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
@@ -649,7 +649,9 @@
 void CanvasRenderingContext2D::StyleDidChange(const ComputedStyle* old_style,
                                               const ComputedStyle& new_style) {
   if (old_style &&
-      base::ValuesEquivalent(old_style->GetFont(), new_style.GetFont())) {
+      (base::FeatureList::IsEnabled(blink::features::kCSSFontComparisonFix)
+           ? base::ValuesEquivalent(old_style->GetFont(), new_style.GetFont())
+           : old_style->GetFont() == new_style.GetFont())) {
     return;
   }
   PruneLocalFontCache(0);
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_features.cc b/third_party/blink/renderer/modules/peerconnection/peer_connection_features.cc
index a3622a0e..146a3fff 100644
--- a/third_party/blink/renderer/modules/peerconnection/peer_connection_features.cc
+++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_features.cc
@@ -34,7 +34,7 @@
 
 // This feature unumutes a track when a packet arrives instead of after
 // setRemoteDescription.
-BASE_FEATURE(kWebRtcUnmuteTracksWhenPacketArrives,
-             base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kWebRtcUnmuteTracksWhenPacketArrives2,
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_features.h b/third_party/blink/renderer/modules/peerconnection/peer_connection_features.h
index 677d4f80..2f104a3 100644
--- a/third_party/blink/renderer/modules/peerconnection/peer_connection_features.h
+++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_features.h
@@ -12,6 +12,6 @@
 MODULES_EXPORT BASE_DECLARE_FEATURE(kWebRtcEncryptedRtpHeaderExtensions);
 MODULES_EXPORT BASE_DECLARE_FEATURE(
     kWebRtcRtpScriptTransformerFrameRestrictions);
-MODULES_EXPORT BASE_DECLARE_FEATURE(kWebRtcUnmuteTracksWhenPacketArrives);
+MODULES_EXPORT BASE_DECLARE_FEATURE(kWebRtcUnmuteTracksWhenPacketArrives2);
 }  // namespace blink
 #endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_PEER_CONNECTION_FEATURES_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
index 91b8815..ae9dc1f 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
@@ -2550,7 +2550,7 @@
   }
 
   // TODO(https://crbug.com/40821064): Remove killswitch after rollout.
-  if (!base::FeatureList::IsEnabled(kWebRtcUnmuteTracksWhenPacketArrives)) {
+  if (!base::FeatureList::IsEnabled(kWebRtcUnmuteTracksWhenPacketArrives2)) {
     for (auto& transceiver : track_events) {
       transceiver->receiver()->track()->Component()->Source()->SetReadyState(
           MediaStreamSource::kReadyStateLive);
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.cc
index edbcc59..5691cc09 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.cc
@@ -9,6 +9,7 @@
 #include "base/functional/bind.h"
 #include "base/notreached.h"
 #include "base/task/single_thread_task_runner.h"
+#include "third_party/blink/renderer/modules/mediastream/video_track_adapter.h"  // For kMediaStreamTrackEmptyVideoFrameMonitor.
 #include "third_party/blink/renderer/modules/peerconnection/peer_connection_features.h"
 #include "third_party/blink/renderer/platform/peerconnection/rtc_encoded_audio_stream_transformer.h"
 #include "third_party/blink/renderer/platform/peerconnection/rtc_encoded_video_stream_transformer.h"
@@ -20,6 +21,14 @@
 
 namespace blink {
 
+// The kWebRtcUnmuteTracksWhenPacketArrives2 feature is also gated on
+// kMediaStreamTrackEmptyVideoFrameMonitor.
+bool ShouldUnmuteTrackWhenPacketsArrive() {
+  return base::FeatureList::IsEnabled(
+             kMediaStreamTrackEmptyVideoFrameMonitor) &&
+         base::FeatureList::IsEnabled(kWebRtcUnmuteTracksWhenPacketArrives2);
+}
+
 RtpReceiverState::RtpReceiverState(
     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> signaling_task_runner,
@@ -165,7 +174,7 @@
     }
     DCHECK(!encoded_audio_transformer_ || !encoded_video_transformer_);
     // TODO(https://crbug.com/40821064): Remove killswitch after rollout.
-    if (base::FeatureList::IsEnabled(kWebRtcUnmuteTracksWhenPacketArrives)) {
+    if (ShouldUnmuteTrackWhenPacketsArrive()) {
       CHECK(webrtc_receiver_);
       webrtc_receiver_->SetObserver(this);
     }
@@ -248,8 +257,7 @@
   ~RTCRtpReceiverInternal() override {
     DCHECK(main_task_runner_->BelongsToCurrentThread());
     // TODO(https://crbug.com/40821064): Remove killswitch after rollout.
-    if (webrtc_receiver_ &&
-        base::FeatureList::IsEnabled(kWebRtcUnmuteTracksWhenPacketArrives)) {
+    if (webrtc_receiver_ && ShouldUnmuteTrackWhenPacketsArrive()) {
       webrtc_receiver_->SetObserver(nullptr);
     }
   }
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.cc b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
index 59f768418..465c0750 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_frame.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
@@ -54,6 +54,7 @@
 #include "third_party/blink/renderer/modules/webcodecs/video_frame_init_util.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame_rect_util.h"
 #include "third_party/blink/renderer/platform/geometry/geometry_hash_traits.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
 #include "third_party/blink/renderer/platform/graphics/canvas_snapshot_provider.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
 #include "third_party/blink/renderer/platform/graphics/image.h"
@@ -364,7 +365,7 @@
     if (info_to_provider_.size() >= kMaxSize)
       info_to_provider_.clear();
 
-    auto provider = CreateResourceProviderForVideoFrame(
+    auto provider = CreateSnapshotProviderForVideoFrame(
         size, viz::SkColorTypeToSinglePlaneSharedImageFormat(info.colorType()),
         info.alphaType(), SkColorSpaceToGfxColorSpace(info.refColorSpace()),
         GetRasterContextProvider().get());
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index ace4bb4..c6487cad 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -8809,7 +8809,7 @@
       raster_context_provider =
           wrapper->ContextProvider().RasterContextProvider();
     }
-    temp = CreateResourceProviderForVideoFrame(
+    temp = CreateSnapshotProviderForVideoFrame(
         size, format, alpha_type, color_space, raster_context_provider);
   } else {
     temp = CanvasResourceProvider::CreateExternalBitmapProvider(
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
index 31393f32..bbbcfd2 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
@@ -235,7 +235,7 @@
   // rate.
   virtual bool IsSingleBuffered() const = 0;
 
-  bool IsGpuContextLost() const;
+  bool IsGpuContextLost() const override;
 
   virtual bool WritePixels(const SkImageInfo& orig_info,
                            const void* pixels,
diff --git a/third_party/blink/renderer/platform/graphics/canvas_snapshot_provider.h b/third_party/blink/renderer/platform/graphics/canvas_snapshot_provider.h
index 2146641..06610ef 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_snapshot_provider.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_snapshot_provider.h
@@ -6,6 +6,7 @@
 
 #include "base/functional/function_ref.h"
 #include "third_party/blink/renderer/platform/graphics/image_orientation.h"
+#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace blink {
@@ -26,6 +27,7 @@
   virtual gfx::ColorSpace GetColorSpace() const = 0;
   virtual SkAlphaType GetAlphaType() const = 0;
   virtual bool IsValid() const = 0;
+  virtual bool IsGpuContextLost() const = 0;
   virtual bool IsExternalBitmapProvider() const { return false; }
 };
 
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_image_util.cc b/third_party/blink/renderer/platform/graphics/video_frame_image_util.cc
index bb6d5fe..6cb1c30 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_image_util.cc
+++ b/third_party/blink/renderer/platform/graphics/video_frame_image_util.cc
@@ -130,10 +130,6 @@
   const auto transform =
       frame->metadata().transformation.value_or(media::kNoTransformation);
 
-  // This method should only be called with context providers supporting OOP-R.
-  CHECK(!raster_context_provider ||
-        raster_context_provider->ContextCapabilities().gpu_rasterization);
-
   // If the provider isn't accelerated, avoid GPU round trips to upload frame
   // data from GpuMemoryBuffer backed frames which aren't mappable.
   if (frame->HasMappableSharedImage() && !frame->IsMappable() &&
@@ -211,7 +207,7 @@
       wrapper->ContextProvider().RasterContextProvider());
 }
 
-std::unique_ptr<CanvasResourceProvider> CreateResourceProviderForVideoFrame(
+std::unique_ptr<CanvasSnapshotProvider> CreateSnapshotProviderForVideoFrame(
     gfx::Size size,
     viz::SharedImageFormat format,
     SkAlphaType alpha_type,
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_image_util.h b/third_party/blink/renderer/platform/graphics/video_frame_image_util.h
index 469ec40d..2675349 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_image_util.h
+++ b/third_party/blink/renderer/platform/graphics/video_frame_image_util.h
@@ -34,7 +34,6 @@
 }  // namespace cc
 
 namespace blink {
-class CanvasResourceProvider;
 class CanvasSnapshotProvider;
 class StaticBitmapImage;
 
@@ -93,12 +92,12 @@
 PLATFORM_EXPORT scoped_refptr<viz::RasterContextProvider>
 GetRasterContextProvider();
 
-// Creates a CanvasResourceProvider which is appropriate for drawing VideoFrame
+// Creates a CanvasSnapshotProvider which is appropriate for drawing VideoFrame
 // objects into. Some callers to CreateImageFromVideoFrame() may choose to cache
-// their resource providers. If |raster_context_provider| is null a software
-// resource provider will be returned.
-PLATFORM_EXPORT std::unique_ptr<CanvasResourceProvider>
-CreateResourceProviderForVideoFrame(
+// their snapshot providers. If |raster_context_provider| is null a software
+// snapshot provider will be returned.
+PLATFORM_EXPORT std::unique_ptr<CanvasSnapshotProvider>
+CreateSnapshotProviderForVideoFrame(
     gfx::Size size,
     viz::SharedImageFormat format,
     SkAlphaType alpha_type,
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_image_util_test.cc b/third_party/blink/renderer/platform/graphics/video_frame_image_util_test.cc
index af0b762..2717aafe 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_image_util_test.cc
+++ b/third_party/blink/renderer/platform/graphics/video_frame_image_util_test.cc
@@ -105,7 +105,7 @@
 
   scoped_refptr<StaticBitmapImage> DoCreateImageFromVideoFrame(
       scoped_refptr<media::VideoFrame> frame,
-      CanvasResourceProvider* resource_provider = nullptr,
+      CanvasSnapshotProvider* snapshot_provider = nullptr,
       media::PaintCanvasVideoRenderer* video_renderer = nullptr,
       bool prefer_tagged_orientation = true) {
     const auto transform =
@@ -119,22 +119,22 @@
       dest_rect.Transpose();
     }
 
-    std::unique_ptr<CanvasResourceProvider> local_resource_provider;
+    std::unique_ptr<CanvasSnapshotProvider> local_snapshot_provider;
 
-    if (!resource_provider) {
+    if (!snapshot_provider) {
       auto frame_color_space = frame->CompatRGBColorSpace();
-      local_resource_provider = CreateResourceProviderForVideoFrame(
+      local_snapshot_provider = CreateSnapshotProviderForVideoFrame(
           dest_rect.size(), GetN32FormatForCanvas(), kPremul_SkAlphaType,
           frame_color_space, raster_context_provider());
-      if (!local_resource_provider) {
+      if (!local_snapshot_provider) {
         DLOG(ERROR) << "Failed to create CanvasResourceProvider.";
         return nullptr;
       }
 
-      resource_provider = local_resource_provider.get();
-      CHECK(resource_provider);
+      snapshot_provider = local_snapshot_provider.get();
+      CHECK(snapshot_provider);
     }
-    return CreateImageFromVideoFrame(std::move(frame), resource_provider,
+    return CreateImageFromVideoFrame(std::move(frame), snapshot_provider,
                                      video_renderer, prefer_tagged_orientation);
   }
 
@@ -287,7 +287,7 @@
       raster_context_provider(), kTestSize, gfx::Rect(kTestSize),
       base::DoNothing());
 
-  auto provider = CreateResourceProviderForVideoFrame(
+  auto provider = CreateSnapshotProviderForVideoFrame(
       kTestSize, kTestFormat, kTestAlphaType, kTestColorSpace,
       raster_context_provider());
   ASSERT_TRUE(provider);
@@ -298,12 +298,10 @@
 
   image = DoCreateImageFromVideoFrame(texture_frame, provider.get());
   EXPECT_TRUE(image->IsTextureBacked());
-
-  ASSERT_FALSE(provider->Recorder().HasRecordedDrawOps());
 }
 
-TEST_P(VideoFrameImageUtilTest, CreateResourceProviderForVideoFrame) {
-  auto provider = CreateResourceProviderForVideoFrame(
+TEST_P(VideoFrameImageUtilTest, CreateSnapshotProviderForVideoFrame) {
+  auto provider = CreateSnapshotProviderForVideoFrame(
       kTestSize, kTestFormat, kTestAlphaType, kTestColorSpace,
       raster_context_provider());
   ASSERT_TRUE(provider);
diff --git a/third_party/blink/renderer/platform/media/web_media_player_impl.cc b/third_party/blink/renderer/platform/media/web_media_player_impl.cc
index fcb5d9d0..c96b4f3 100644
--- a/third_party/blink/renderer/platform/media/web_media_player_impl.cc
+++ b/third_party/blink/renderer/platform/media/web_media_player_impl.cc
@@ -1515,10 +1515,6 @@
   paint_params.transformation =
       pipeline_metadata_.video_decoder_config.video_transformation();
 
-  // This class should only be used with raster context providers that
-  // support OOP-R.
-  CHECK(!raster_context_provider_ ||
-        raster_context_provider_->ContextCapabilities().gpu_rasterization);
   video_renderer_.Paint(video_frame, canvas, flags, paint_params,
                         raster_context_provider_.get());
 }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index aa489c0..b113c2eb 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -4427,7 +4427,7 @@
       // Spec: https://wicg.github.io/sanitizer-api/
       // Tracking bug: crbug.com/356601280
       name: "SanitizerAPI",
-      status: "test",
+      status: "experimental",
     },
     {
       // https://wicg.github.io/webcomponents/proposals/Scoped-Custom-Element-Registries
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index f0d3355c..35ca1c47 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -5248,8 +5248,6 @@
 
 # ====== Tests from enabling .any.js/.worker.js tests end here ========
 
-crbug.com/40551880 http/tests/devtools/sources/debugger/live-edit-no-reveal.js [ Crash Failure Pass Timeout ]
-
 # ====== Begin of display: contents tests ======
 
 crbug.com/181374 external/wpt/css/css-display/display-contents-dynamic-table-001-inline.html [ Failure ]
@@ -5953,6 +5951,10 @@
 crbug.com/41448929 http/tests/devtools/elements/styles-3/styles-add-new-rule.js [ Failure Pass Timeout ]
 crbug.com/41448929 http/tests/devtools/elements/styles-3/styles-change-node-while-editing.js [ Failure Pass ]
 
+# For DevTools roll.
+crbug.com/407751198 http/tests/devtools/console/console-dirxml.js [ Failure Pass ]
+crbug.com/407751198 http/tests/devtools/console/console-xml-document.js [ Failure Pass ]
+
 # Tests using testRunner.useUnfortunateSynchronousResizeMode occasionally timeout,
 # but the test coverage is still good.
 
@@ -6298,7 +6300,6 @@
 crbug.com/40728742 http/tests/devtools/sources/debugger-ui/continue-to-location-markers-in-top-level-function.js [ Failure Pass Timeout ]
 
 # Sheriff 2020-11-16
-crbug.com/40732030 http/tests/devtools/sources/debugger-ui/debugger-inline-values-frames.js [ Failure Pass Timeout ]
 crbug.com/40732030 http/tests/devtools/sources/debugger-ui/reveal-execution-line.js [ Failure Pass Timeout ]
 crbug.com/1150475 fast/dom/open-and-close-by-DOM.html [ Failure Pass ]
 
@@ -6313,9 +6314,6 @@
 #Sheriff 2020-11-26
 crbug.com/931646 crbug.com/424347610 [ Mac ] virtual/viewport-and-meta-enabled/http/tests/preload/meta-viewport-link-headers-imagesrcset.php [ Failure Pass Timeout ]
 
-# DevTools roll
-crbug.com/40155405 http/tests/devtools/report-API-errors.js [ Crash Failure Pass Timeout ]
-
 # Sheriff 2020-12-11
 # Flaking on Linux
 crbug.com/40736669 http/tests/devtools/extensions/extensions-resources.js [ Failure Pass ]
@@ -6423,9 +6421,6 @@
 # Started failing after rolling new version of check-layout-th.js
 css3/flexbox/perpendicular-writing-modes-inside-flex-item.html [ Failure ]
 
-# Sheriff 2021-11-15
-crbug.com/40205355 http/tests/devtools/sources/debugger-ui/debugger-inline-values.js [ Failure Pass Timeout ]
-
 # The wpt_flags=h2 variants of these tests fail on content shell but pass on
 # headless shell. Use test expectations so that the results for headless shell
 # will be unexpected pass.
@@ -7034,11 +7029,6 @@
 
 crbug.com/366415131 external/wpt/html/semantics/forms/the-select-element/customizable-select/picker-and-slotted.html [ Failure ]
 
-# Temporarily disabled to unblock DevTools roll.
-crbug.com/407751574 http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test.js [ Failure Pass Timeout ]
-crbug.com/407751574 http/tests/devtools/sources/debugger-ui/async-call-stack-async-function.js [ Failure Pass Timeout ]
-crbug.com/407751574 http/tests/devtools/sources/debugger-ui/call-stack-show-more.js [ Failure Pass Timeout ]
-
 crbug.com/357649033 virtual/customizable-select-in-page-disabled/external/wpt/html/semantics/forms/the-select-element/customizable-select-in-page/customizable-select-in-page-appearance.tentative.html [ Failure ]
 crbug.com/357649033 virtual/customizable-select-in-page-disabled/external/wpt/html/semantics/forms/the-select-element/customizable-select-in-page/customizable-select-in-page-keyboard-behavior.tentative.html [ Failure ]
 crbug.com/357649033 virtual/customizable-select-in-page-disabled/external/wpt/html/semantics/forms/the-select-element/customizable-select-in-page/customizable-select-in-page-mouse-behavior.tentative.html [ Failure ]
@@ -8732,6 +8722,7 @@
 crbug.com/356930166 [ Mac15 ] external/wpt/webrtc/RTCPeerConnection-perfect-negotiation.https.html [ Skip Timeout ]
 crbug.com/356930166 [ Mac15 ] external/wpt/webrtc/RTCPeerConnection-restartIce.https.html [ Timeout ]
 crbug.com/356930166 [ Mac15 ] external/wpt/webrtc/RTCPeerConnection-videoDetectorTest.html [ Skip Timeout ]
+crbug.com/356930166 [ Mac15 ] external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html [ Skip Timeout ]
 crbug.com/356930166 [ Mac15 ] external/wpt/webrtc/RTCRtpReceiver-getStats.https.html [ Skip Timeout ]
 crbug.com/356930166 [ Mac15 ] external/wpt/webrtc/RTCRtpSender-getStats.https.html [ Skip Timeout ]
 crbug.com/356930166 [ Mac15 ] external/wpt/webrtc/RTCRtpSender-replaceTrack.https.html [ Skip Timeout ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index b92076d..b4850131 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -2806,23 +2806,6 @@
     ]
   },
   {
-    "prefix": "sanitizer-api",
-    "platforms": [
-      "Linux"
-    ],
-    "bases": [
-      "external/wpt/sanitizer-api/"
-    ],
-    "args": [
-      "--enable-features=SanitizerAPI"
-    ],
-    "expires": "Jan 18, 2026",
-    "owners": [
-      "vogelheim@google.com"
-    ],
-    "exclusive_tests": "ALL"
-  },
-  {
     "prefix": "scalefactor150",
     "platforms": [
       "Linux",
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt
deleted file mode 100644
index 5a5ade0..0000000
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-getStats.https-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] getStats() on track associated with RTCRtpReceiver should return stats report containing inbound-rtp stats
-  assert_true: expected true got false
-[FAIL] getStats() audio contains inbound-rtp stats
-  assert_true: expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt
index c15bf990..20f0e487 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpReceiver-getStats.https-expected.txt
@@ -1,13 +1,5 @@
 This is a testharness.js-based test.
-[FAIL] receiver.getStats() via addTransceiver should return stats report containing inbound-rtp stats
-  assert_true: expected true got false
-[FAIL] receiver.getStats() via addTrack should return stats report containing inbound-rtp stats
-  assert_true: expected true got false
 [FAIL] receiver.getStats() should work on a stopped transceiver but not have inbound-rtp objects
-  assert_true: expected true got false
-[FAIL] receiver.getStats() should work with a closed PeerConnection but not have inbound-rtp objects
-  assert_true: expected true got false
-[FAIL] receiver.getStats() should return stats report containing ICE candidate stats
-  assert_true: expected true got false
+  assert_false: expected false got true
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpTransceiver.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpTransceiver.https-expected.txt
index 3d45ac0..3661b1e2 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpTransceiver.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpTransceiver.https-expected.txt
@@ -1,9 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] checkRemoveTrackNegotiation
   assert_equals: pc2.setRemoteDescription(offer) should've added 2 tracks to receive stream expected 2 but got 0
-[FAIL] track with audio is muted after SRD
-  assert_true: track is muted after SRD expected true got false
-[FAIL] track with video is muted after SRD
-  assert_true: track is muted after SRD expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpTransceiver.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpTransceiver.https.html
index f364753..7fc9c936 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpTransceiver.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpTransceiver.https.html
@@ -2267,7 +2267,43 @@
     await exchangeOfferAnswer(pc1, pc2);
     await waitUntilTrackEventWithTimeout(pc2.getReceivers()[0].track, 'unmute', t);
     assert_false(pc2.getReceivers()[0].track.muted, `track is unmuted`);
-  }, `track with ${kind} gets unmuted when setting the transceiver direction to 'sendrecv ' after 'inactive'`);
+  }, `track with ${kind} gets unmuted when setting the transceiver direction to 'sendrecv' after 'inactive'`);
+
+  promise_test(async t => {
+    const pc1 = new RTCPeerConnection();
+    const pc2 = new RTCPeerConnection();
+    t.add_cleanup(() => pc1.close());
+    t.add_cleanup(() => pc2.close());
+
+    let stream;
+    if (kind === 'audio') {
+      stream = await navigator.mediaDevices.getUserMedia({[kind]: true});
+    } else {
+      stream = await getNoiseStream({[kind]: true});
+    }
+    t.add_cleanup(() => stream.getTracks().forEach(t => t.stop()));
+
+    pc1.addTrack(stream.getTracks()[0], stream);
+    pc2.ontrack = t.step_func(async e => {
+      assert_true(e.track.muted, `track is muted in ontrack`);
+    });
+
+    await exchangeIceCandidates(pc1, pc2);
+    await exchangeOfferAnswer(pc1, pc2);
+    await waitUntilTrackEventWithTimeout(pc2.getReceivers()[0].track, 'unmute', t);
+    assert_false(pc2.getReceivers()[0].track.muted, `track is unmuted`);
+    pc1.getSenders()[0].replaceTrack(null);
+
+    pc1.getTransceivers()[0].direction = 'inactive';
+    await exchangeOfferAnswer(pc1, pc2);
+    await waitUntilTrackEventWithTimeout(pc2.getReceivers()[0].track, 'mute', t);
+    assert_true(pc2.getReceivers()[0].track.muted, `track is muted`);
+
+    pc1.getTransceivers()[0].direction = 'sendrecv';
+    await exchangeOfferAnswer(pc1, pc2);
+    await waitUntilTrackEventWithTimeout(pc2.getReceivers()[0].track, 'unmute', t);
+    assert_true(pc2.getReceivers()[0].track.muted, `track remains muted`);
+  }, `track with ${kind} stays muted when setting the transceiver direction to 'sendrecv' after 'inactive' but no packets flow`);
 });
 
 </script>
diff --git a/third_party/blink/web_tests/fast/borders/cornerShapeOutlineAuto-expected.png b/third_party/blink/web_tests/fast/borders/cornerShapeOutlineAuto-expected.png
new file mode 100644
index 0000000..1c45638
--- /dev/null
+++ b/third_party/blink/web_tests/fast/borders/cornerShapeOutlineAuto-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/borders/cornerShapeOutlineAuto-offset-expected.png b/third_party/blink/web_tests/fast/borders/cornerShapeOutlineAuto-offset-expected.png
new file mode 100644
index 0000000..df72209
--- /dev/null
+++ b/third_party/blink/web_tests/fast/borders/cornerShapeOutlineAuto-offset-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/borders/cornerShapeOutlineAuto-offset.html b/third_party/blink/web_tests/fast/borders/cornerShapeOutlineAuto-offset.html
new file mode 100644
index 0000000..f25b27f
--- /dev/null
+++ b/third_party/blink/web_tests/fast/borders/cornerShapeOutlineAuto-offset.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style type="text/css">
+      div {
+        width: 200px;
+        height: 200px;
+        outline: 15px auto purple;
+        outline-offset: 5px;
+        margin: 30px;
+        border-radius: 140px;
+        corner-shape: bevel notch squircle scoop;
+        background-color: green;
+      }
+    </style>
+  </head>
+  <body>
+    <div>&nbsp;</div>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/fast/borders/cornerShapeOutlineAuto.html b/third_party/blink/web_tests/fast/borders/cornerShapeOutlineAuto.html
new file mode 100644
index 0000000..c86f519
--- /dev/null
+++ b/third_party/blink/web_tests/fast/borders/cornerShapeOutlineAuto.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style type="text/css">
+      div {
+        width: 200px;
+        height: 200px;
+        outline: 15px auto purple;
+        margin: 20px;
+        border-radius: 140px;
+        corner-shape: scoop bevel notch squircle;
+        background-color: green;
+      }
+    </style>
+  </head>
+  <body>
+    <div>&nbsp;</div>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test.js
index 816f482..ebadb37 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test.js
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test.js
@@ -29,9 +29,9 @@
 
   await SourcesTestRunner.startDebuggerTestPromise(/* quiet */ true);
   await SourcesTestRunner.runTestFunctionAndWaitUntilPausedPromise();
-  await TestRunner.addSnifferPromise(SourcesModule.CallStackSidebarPane.CallStackSidebarPane.prototype, 'updatedForTest');
 
   const callStackPane = SourcesModule.CallStackSidebarPane.CallStackSidebarPane.instance();
+  await callStackPane.updateComplete;
   const callStackElement = callStackPane.contentElement;
   TestRunner.addResult(`Call stack pane content: ${TestRunner.clearSpecificInfoFromStackFrames(callStackElement.deepTextContent())}`);
   TestRunner.addResult('Running the axe-core linter on the call stack sidebar pane.');
diff --git a/third_party/blink/web_tests/http/tests/devtools/components/widget-events-expected.txt b/third_party/blink/web_tests/http/tests/devtools/components/widget-events-expected.txt
deleted file mode 100644
index b33e832..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/components/widget-events-expected.txt
+++ /dev/null
@@ -1,212 +0,0 @@
-This tests that events are properly propagated through Widget hierarchy.
-
-
-Running: testShowWidget
-Widget()
-Widget.show()
-  Widget.wasShown()
-  Widget.onResize()
-Widget.detach()
-  Widget.willHide()
-
-Running: testAttachToOrphanNode
-Widget()
-Widget.show()
-Error: Attempt to attach widget to orphan node
-
-Running: testImmediateParent
-Parent()
-Child()
-Child.show()
-OK
-
-Running: testDistantParent
-Parent()
-Child()
-Child.show()
-OK
-
-Running: testEvents
-Parent()
-Child()
-Parent.show()
-  Parent.wasShown()
-  Parent.onResize()
-Parent.doResize()
-Child.show()
-  Child.wasShown()
-  Child.onResize()
-Parent.doResize()
-  Child.onResize()
-Parent.detach()
-  Child.willHide()
-  Parent.willHide()
-Parent.show()
-  Parent.wasShown()
-  Child.wasShown()
-  Parent.onResize()
-  Child.onResize()
-Child.detach()
-  Child.willHide()
-Parent.detach()
-  Parent.willHide()
-
-Running: testEventsHideOnDetach
-Parent()
-Child()
-Parent.show()
-  Parent.wasShown()
-  Parent.onResize()
-Parent.doResize()
-Child.show()
-  Child.wasShown()
-  Child.onResize()
-Parent.doResize()
-  Child.onResize()
-Parent.detach()
-  Child.willHide()
-  Parent.willHide()
-Parent.show()
-  Parent.wasShown()
-  Child.wasShown()
-  Parent.onResize()
-  Child.onResize()
-Child.detach()
-  Child.willHide()
-Parent.detach()
-  Parent.willHide()
-
-Running: testShowOnWasShown
-Parent()
-Child()
-Parent.show()
-  Parent.wasShown()
-Child.show()
-  Child.wasShown()
-  Parent.onResize()
-  Child.onResize()
-Parent.detach()
-  Child.willHide()
-  Parent.willHide()
-
-Running: testShowNestedOnWasShown
-Top()
-Middle()
-Bottom()
-Middle.show()
-Top.show()
-  Top.wasShown()
-Bottom.show()
-  Middle.wasShown()
-  Bottom.wasShown()
-  Top.onResize()
-  Middle.onResize()
-  Bottom.onResize()
-Top.detach()
-  Bottom.willHide()
-  Middle.willHide()
-  Top.willHide()
-
-Running: testDetachOnWasShown
-Parent()
-Child()
-Child.show()
-Parent.show()
-  Parent.wasShown()
-Child.detach()
-  Parent.onResize()
-Parent.detach()
-  Parent.willHide()
-
-Running: testShowOnWillHide
-Parent()
-Child()
-Parent.show()
-  Parent.wasShown()
-  Parent.onResize()
-Child.show()
-  Child.wasShown()
-  Child.onResize()
-Parent.detach()
-  Child.willHide()
-  Parent.willHide()
-Child.show()
-
-Running: testDetachOnWillHide
-Parent()
-Child()
-Parent.show()
-  Parent.wasShown()
-  Parent.onResize()
-Child.show()
-  Child.wasShown()
-  Child.onResize()
-Parent.detach()
-  Child.willHide()
-  Parent.willHide()
-Child.detach()
-
-Running: testShowDetachesFromPrevious
-Parent1()
-Parent2()
-Child()
-Parent1.show()
-  Parent1.wasShown()
-  Parent1.onResize()
-Parent2.show()
-  Parent2.wasShown()
-  Parent2.onResize()
-Child.show()
-  Child.wasShown()
-  Child.onResize()
-Child.show()
-Child.detach()
-  Child.willHide()
-  Child.wasShown()
-  Child.onResize()
-
-Running: testResizeOnWasShown
-Parent()
-Child()
-Child.show()
-Parent.show()
-  Parent.wasShown()
-Child.doResize()
-  Child.wasShown()
-  Parent.onResize()
-  Child.onResize()
-Parent.detach()
-  Child.willHide()
-  Parent.willHide()
-
-Running: testReparentWithinWidget
-Parent()
-Parent.show()
-  Parent.wasShown()
-  Parent.onResize()
-Child()
-Child.show()
-  Child.wasShown()
-  Child.onResize()
-Child.show()
-  Child.onResize()
-
-Running: testDetachChildWidgetsRemovesHiddenChildren
-Parent()
-visibleChild()
-hiddenChild()
-Parent.show()
-  Parent.wasShown()
-  Parent.onResize()
-visibleChild.show()
-  visibleChild.wasShown()
-  visibleChild.onResize()
-hiddenChild.show()
-  hiddenChild.wasShown()
-  hiddenChild.onResize()
-  hiddenChild.willHide()
-visibleChild.detach()
-  visibleChild.willHide()
-hiddenChild.detach()
-Parent element has 0 child elements
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/components/widget-events.js b/third_party/blink/web_tests/http/tests/devtools/components/widget-events.js
deleted file mode 100644
index 1c73e0e..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/components/widget-events.js
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {TestRunner} from 'test_runner';
-
-import * as UI from 'devtools/ui/legacy/legacy.js';
-
-(async function() {
-  TestRunner.addResult(`This tests that events are properly propagated through Widget hierarchy.\n`);
-
-
-  var TestWidget = class extends UI.Widget.Widget {
-    constructor(widgetName) {
-      super();
-      this.widgetName = widgetName;
-      this.processWillShowCount = 0;
-      this.processWasHiddenCount = 0;
-      TestRunner.addResult(this.widgetName + '()');
-    }
-
-    processWillShow() {
-      TestRunner.assertEquals(this.processWillShowCount, this.processWasHiddenCount);
-      super.processWillShow();
-      ++this.processWillShowCount;
-    }
-
-    processWasHidden() {
-      super.processWasHidden();
-      ++this.processWasHiddenCount;
-      TestRunner.assertEquals(this.processWillShowCount, this.processWasHiddenCount);
-    }
-
-    show(parentElement) {
-      TestRunner.addResult(this.widgetName + '.show()');
-      super.show(parentElement);
-    }
-
-    detach() {
-      TestRunner.addResult(this.widgetName + '.detach()');
-      super.detach();
-    }
-
-    doResize() {
-      TestRunner.addResult(this.widgetName + '.doResize()');
-      super.doResize();
-    }
-
-    wasShown() {
-      TestRunner.addResult('  ' + this.widgetName + '.wasShown()');
-      if (this.showOnWasShown)
-        this.showOnWasShown.show(this.showRoot || this.element);
-      if (this.detachOnWasShown)
-        this.detachOnWasShown.detach();
-      if (this.resizeOnWasShown)
-        this.resizeOnWasShown.doResize();
-    }
-
-    willHide() {
-      TestRunner.addResult('  ' + this.widgetName + '.willHide()');
-      if (this.showOnWillHide)
-        this.showOnWillHide.show(this.element);
-      if (this.detachOnWillHide)
-        this.detachOnWillHide.detach();
-    }
-
-    onResize() {
-      TestRunner.addResult('  ' + this.widgetName + '.onResize()');
-    }
-  };
-
-  TestRunner.runTestSuite([
-    function testShowWidget(next) {
-      var widget = new TestWidget('Widget');
-      widget.show(UI.InspectorView.InspectorView.instance().element);
-      widget.detach();
-      next();
-    },
-
-    function testAttachToOrphanNode(next) {
-      try {
-        var widget = new TestWidget('Widget');
-        var div = document.createElement('div');
-        widget.show(div);
-      } catch (e) {
-        TestRunner.addResult(e);
-      }
-      next();
-    },
-
-    function testImmediateParent(next) {
-      var parentWidget = new TestWidget('Parent');
-      var childWidget = new TestWidget('Child');
-      childWidget.show(parentWidget.element);
-      if (childWidget.parentWidget() === parentWidget)
-        TestRunner.addResult('OK');
-      else
-        TestRunner.addResult('FAILED');
-      next();
-    },
-
-    function testDistantParent(next) {
-      var parentWidget = new TestWidget('Parent');
-      var div = document.createElement('div');
-      parentWidget.element.appendChild(div);
-      var childWidget = new TestWidget('Child');
-      childWidget.show(div);
-
-      if (childWidget.parentWidget() === parentWidget)
-        TestRunner.addResult('OK');
-      else
-        TestRunner.addResult('FAILED');
-      next();
-    },
-
-    function testEvents(next) {
-      var parentWidget = new TestWidget('Parent');
-      parentWidget.markAsRoot();
-      var childWidget = new TestWidget('Child');
-      parentWidget.show(document.body);
-
-      parentWidget.doResize();
-      childWidget.show(parentWidget.element);
-      parentWidget.doResize();
-      parentWidget.detach();
-      parentWidget.show(document.body);
-      childWidget.detach();
-      parentWidget.detach();
-      next();
-    },
-
-    function testEventsHideOnDetach(next) {
-      var parentWidget = new TestWidget('Parent');
-      var childWidget = new TestWidget('Child');
-      childWidget.setHideOnDetach();
-      parentWidget.show(UI.InspectorView.InspectorView.instance().element);
-
-      parentWidget.doResize();
-      childWidget.show(parentWidget.element);
-      parentWidget.doResize();
-      parentWidget.detach();
-      parentWidget.show(UI.InspectorView.InspectorView.instance().element);
-      childWidget.detach();
-      parentWidget.detach();
-      next();
-    },
-
-    function testShowOnWasShown(next) {
-      var parentWidget = new TestWidget('Parent');
-      parentWidget.showOnWasShown = new TestWidget('Child');
-      parentWidget.show(UI.InspectorView.InspectorView.instance().element);
-      parentWidget.detach();
-      next();
-    },
-
-    function testShowNestedOnWasShown(next) {
-      var topWidget = new TestWidget('Top');
-      var middleWidget = new TestWidget('Middle');
-      var bottomWidget = new TestWidget('Bottom');
-      middleWidget.show(topWidget.element);
-      topWidget.showOnWasShown = bottomWidget;
-      topWidget.showRoot = middleWidget.element;
-      topWidget.show(UI.InspectorView.InspectorView.instance().element);
-      topWidget.detach();
-      next();
-    },
-
-    function testDetachOnWasShown(next) {
-      var parentWidget = new TestWidget('Parent');
-      var childWidget = new TestWidget('Child');
-      childWidget.show(parentWidget.element);
-      parentWidget.detachOnWasShown = childWidget;
-      parentWidget.show(UI.InspectorView.InspectorView.instance().element);
-      parentWidget.detach();
-      next();
-    },
-
-    function testShowOnWillHide(next) {
-      var parentWidget = new TestWidget('Parent');
-      var childWidget = new TestWidget('Child');
-      parentWidget.show(UI.InspectorView.InspectorView.instance().element);
-      childWidget.show(parentWidget.element);
-      parentWidget.showOnWillHide = childWidget;
-      parentWidget.detach();
-      next();
-    },
-
-    function testDetachOnWillHide(next) {
-      var parentWidget = new TestWidget('Parent');
-      var childWidget = new TestWidget('Child');
-      parentWidget.show(UI.InspectorView.InspectorView.instance().element);
-      childWidget.show(parentWidget.element);
-      parentWidget.detachOnWillHide = childWidget;
-      parentWidget.detach();
-      next();
-    },
-
-    function testShowDetachesFromPrevious(next) {
-      var parentWidget1 = new TestWidget('Parent1');
-      var parentWidget2 = new TestWidget('Parent2');
-      var childWidget = new TestWidget('Child');
-      parentWidget1.show(UI.InspectorView.InspectorView.instance().element);
-      parentWidget2.show(UI.InspectorView.InspectorView.instance().element);
-      childWidget.show(parentWidget1.element);
-      childWidget.show(parentWidget2.element);
-      next();
-    },
-
-    function testResizeOnWasShown(next) {
-      var parentWidget = new TestWidget('Parent');
-      var childWidget = new TestWidget('Child');
-      childWidget.show(parentWidget.element);
-      parentWidget.resizeOnWasShown = childWidget;
-      parentWidget.show(UI.InspectorView.InspectorView.instance().element);
-      parentWidget.detach();
-      next();
-    },
-
-    function testReparentWithinWidget(next) {
-      var parentWidget = new TestWidget('Parent');
-      parentWidget.show(UI.InspectorView.InspectorView.instance().element);
-      var childWidget = new TestWidget('Child');
-      var container1 = parentWidget.element.createChild('div');
-      var container2 = parentWidget.element.createChild('div');
-      childWidget.show(container1);
-      childWidget.show(container2);
-      next();
-    },
-
-    function testDetachChildWidgetsRemovesHiddenChildren(next) {
-      var parentWidget = new TestWidget('Parent');
-      var visibleChild = new TestWidget('visibleChild');
-      var hiddenChild = new TestWidget('hiddenChild');
-      parentWidget.show(UI.InspectorView.InspectorView.instance().element);
-      visibleChild.show(parentWidget.element);
-      hiddenChild.show(parentWidget.element);
-      hiddenChild.hideWidget();
-      parentWidget.detachChildWidgets();
-      var count = parentWidget.element.childElementCount;
-      TestRunner.addResult(`Parent element has ${count} child elements`);
-      next();
-    }
-  ]);
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/report-API-errors-expected.txt b/third_party/blink/web_tests/http/tests/devtools/report-API-errors-expected.txt
deleted file mode 100644
index f129270e..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/report-API-errors-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Tests that InspectorBackendStub is catching incorrect arguments.
-
-Protocol Error: Invalid type of argument 'userAgent' for method 'Network.setUserAgentOverride' call. It must be 'string' but it is 'number'.
-Protocol Error: Invalid number of arguments for method 'Network.setUserAgentOverride' call. It must have the following arguments [{"name":"userAgent","type":"string","optional":false},{"name":"acceptLanguage","type":"string","optional":true},{"name":"platform","type":"string","optional":true},{"name":"userAgentMetadata","type":"object","optional":true}]'.
-Protocol Error: Invalid type of argument 'includeCommandLineAPI' for method 'Runtime.evaluate' call. It must be 'boolean' but it is 'function'.
-Protocol Error: Invalid type of argument 'silent' for method 'Runtime.evaluate' call. It must be 'boolean' but it is 'function'.
-Protocol Error: the message wrongDomain.something-strange is for non-existing domain 'wrongDomain': {"method":"wrongDomain.something-strange","params":{}}
-Protocol Error: Attempted to dispatch an unspecified method 'Inspector.something-strange': {"method":"Inspector.something-strange","params":{}}
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/report-API-errors.js b/third_party/blink/web_tests/http/tests/devtools/report-API-errors.js
deleted file mode 100644
index f4d78a7..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/report-API-errors.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {TestRunner} from 'test_runner';
-
-import * as Platform from 'devtools/core/platform/platform.js';
-
-(async function() {
-  TestRunner.addResult(`Tests that InspectorBackendStub is catching incorrect arguments.\n`);
-
-
-  console.error = function() {
-    TestRunner.addResult(Platform.StringUtilities.sprintf.apply(this, arguments));
-  };
-
-  TestRunner.NetworkAgent.invoke_setUserAgentOverride({userAgent: 1});
-  TestRunner.NetworkAgent.invoke_setUserAgentOverride({});
-  TestRunner.NetworkAgent.invoke_setUserAgentOverride({userAgent: '123', acceptLanguage: 'not a function'});
-  TestRunner.NetworkAgent.invoke_setUserAgentOverride({userAgent: '123', acceptLanguage: undefined});
-  TestRunner.RuntimeAgent.invoke_evaluate({expression: 'true', objectGroup: 'test'});
-  TestRunner.RuntimeAgent.invoke_evaluate({expression: 'true', objectGroup: 'test', includeCommandLineAPI: function() {}});
-  TestRunner.RuntimeAgent.invoke_evaluate({expression: 'true', objectGroup: 'test', includeCommandLineAPI: undefined, silent: function() {}});
-  TestRunner.mainTarget._router._onMessage('{"method": "wrongDomain.something-strange", "params": {}}');
-  TestRunner.mainTarget._router._onMessage('{"method": "Inspector.something-strange", "params": {}}');
-
-  TestRunner.completeTest();
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/async-call-stack-async-function.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/async-call-stack-async-function.js
index 5b4ffd5..3bf5002 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/async-call-stack-async-function.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/async-call-stack-async-function.js
@@ -36,9 +36,7 @@
 
   SourcesTestRunner.startDebuggerTestPromise(/* quiet */ true)
       .then(() => SourcesTestRunner.runTestFunctionAndWaitUntilPausedPromise())
-      .then(
-          () => TestRunner.addSnifferPromise(
-              SourcesModule.CallStackSidebarPane.CallStackSidebarPane.prototype, 'updatedForTest'))
+      .then(() => SourcesModule.CallStackSidebarPane.CallStackSidebarPane.instance().updateComplete)
       .then(() => dumpCallStackSidebarPane())
       .then(() => SourcesTestRunner.completeDebuggerTest());
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/call-stack-show-more.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/call-stack-show-more.js
index 015e4bd..9f09de45 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/call-stack-show-more.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/call-stack-show-more.js
@@ -27,15 +27,13 @@
 
   await SourcesTestRunner.startDebuggerTestPromise(/* quiet */ true);
   await SourcesTestRunner.runTestFunctionAndWaitUntilPausedPromise();
-  await TestRunner.addSnifferPromise(
-      SourcesModule.CallStackSidebarPane.CallStackSidebarPane.prototype, 'updatedForTest');
+  const pane = SourcesModule.CallStackSidebarPane.CallStackSidebarPane.instance();
+  await pane.updateComplete;
   dumpCallStackSidebarPane();
 
   TestRunner.addResult('\n---------------\nClicks show more..');
-  const pane = SourcesModule.CallStackSidebarPane.CallStackSidebarPane.instance();
   pane.contentElement.querySelector('.show-more-message > .link').click();
-  await TestRunner.addSnifferPromise(
-      SourcesModule.CallStackSidebarPane.CallStackSidebarPane.prototype, 'updatedForTest');
+  await pane.updateComplete;
   dumpCallStackSidebarPane();
   SourcesTestRunner.completeDebuggerTest();
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/debugger-inline-values-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/debugger-inline-values-expected.txt
deleted file mode 100644
index d253eaa..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/debugger-inline-values-expected.txt
+++ /dev/null
@@ -1,113 +0,0 @@
-Tests inline values rendering in the sources panel.
-
-=========== 11< ==========
-[11] >           debugger; 	
-[12]             var a = { k: 1 }; 	
-[13]             var b = [1, 2, 3, 4, 5]; 	
-[14]             var c = new Array(100); c[10] = 1; 	
-[15]             a.k = 2; 	
-[16]             a.l = window; 	
-[17]             b[1]++; 	
-[18]             b[2] = document.body; 	
-[19]         } 	
-[20]    	
-=========== 11< ==========
-[11]             debugger; 	
-[12] >           var a = { k: 1 }; 	
-[13]             var b = [1, 2, 3, 4, 5]; 	
-[14]             var c = new Array(100); c[10] = 1; 	
-[15]             a.k = 2; 	
-[16]             a.l = window; 	
-[17]             b[1]++; 	
-[18]             b[2] = document.body; 	
-[19]         } 	
-[20]    	
-=========== 11< ==========
-[11]             debugger; 	
-[12]             var a = { k: 1 }; 	 a = {k: 1}
-[13] >           var b = [1, 2, 3, 4, 5]; 	
-[14]             var c = new Array(100); c[10] = 1; 	
-[15]             a.k = 2; 	
-[16]             a.l = window; 	
-[17]             b[1]++; 	
-[18]             b[2] = document.body; 	
-[19]         } 	
-[20]    	
-=========== 11< ==========
-[11]             debugger; 	
-[12]             var a = { k: 1 }; 	 a = {k: 1}
-[13]             var b = [1, 2, 3, 4, 5]; 	 b = (5) [1, 2, 3, 4, 5]
-[14] >           var c = new Array(100); c[10] = 1; 	
-[15]             a.k = 2; 	
-[16]             a.l = window; 	
-[17]             b[1]++; 	
-[18]             b[2] = document.body; 	
-[19]         } 	
-[20]    	
-=========== 11< ==========
-[11]             debugger; 	
-[12]             var a = { k: 1 }; 	 a = {k: 1}
-[13]             var b = [1, 2, 3, 4, 5]; 	 b = (5) [1, 2, 3, 4, 5]
-[14] >           var c = new Array(100); c[10] = 1; 	
-[15]             a.k = 2; 	
-[16]             a.l = window; 	
-[17]             b[1]++; 	
-[18]             b[2] = document.body; 	
-[19]         } 	
-[20]    	
-=========== 11< ==========
-[11]             debugger; 	
-[12]             var a = { k: 1 }; 	 a = {k: 1}
-[13]             var b = [1, 2, 3, 4, 5]; 	 b = (5) [1, 2, 3, 4, 5]
-[14]             var c = new Array(100); c[10] = 1; 	 c = (100) [empty × 10, 1, empty × 89]
-[15] >           a.k = 2; 	
-[16]             a.l = window; 	
-[17]             b[1]++; 	
-[18]             b[2] = document.body; 	
-[19]         } 	
-[20]    	
-=========== 11< ==========
-[11]             debugger; 	
-[12]             var a = { k: 1 }; 	 a = {k: 2}
-[13]             var b = [1, 2, 3, 4, 5]; 	 b = (5) [1, 2, 3, 4, 5]
-[14]             var c = new Array(100); c[10] = 1; 	 c = (100) [empty × 10, 1, empty × 89]
-[15]             a.k = 2; 	 a = {k: 2}
-[16] >           a.l = window; 	
-[17]             b[1]++; 	
-[18]             b[2] = document.body; 	
-[19]         } 	
-[20]    	
-=========== 11< ==========
-[11]             debugger; 	
-[12]             var a = { k: 1 }; 	 a = {k: 2, l: Window}
-[13]             var b = [1, 2, 3, 4, 5]; 	 b = (5) [1, 2, 3, 4, 5]
-[14]             var c = new Array(100); c[10] = 1; 	 c = (100) [empty × 10, 1, empty × 89]
-[15]             a.k = 2; 	 a = {k: 2, l: Window}
-[16]             a.l = window; 	 
-[17] >           b[1]++; 	
-[18]             b[2] = document.body; 	
-[19]         } 	
-[20]    	
-=========== 11< ==========
-[11]             debugger; 	
-[12]             var a = { k: 1 }; 	 a = {k: 2, l: Window}
-[13]             var b = [1, 2, 3, 4, 5]; 	 b = (5) [1, 3, 3, 4, 5]
-[14]             var c = new Array(100); c[10] = 1; 	 c = (100) [empty × 10, 1, empty × 89]
-[15]             a.k = 2; 	 a = {k: 2, l: Window}
-[16]             a.l = window; 	 
-[17]             b[1]++; 	 b = (5) [1, 3, 3, 4, 5]
-[18] >           b[2] = document.body; 	
-[19]         } 	
-[20]    	
-=========== 11< ==========
-[11]             debugger; 	
-[12]             var a = { k: 1 }; 	 a = {k: 2, l: Window}
-[13]             var b = [1, 2, 3, 4, 5]; 	 b = (5) [1, 3, body, 4, 5]
-[14]             var c = new Array(100); c[10] = 1; 	 c = (100) [empty × 10, 1, empty × 89]
-[15]             a.k = 2; 	 a = {k: 2, l: Window}
-[16]             a.l = window; 	 
-[17]             b[1]++; 	 b = (5) [1, 3, body, 4, 5]
-[18]             b[2] = document.body; 	 
-[19] >       } 	
-[20]    	
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/debugger-inline-values-frames-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/debugger-inline-values-frames-expected.txt
deleted file mode 100644
index 34f098f..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/debugger-inline-values-frames-expected.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-Tests inline values rendering while stepping between call frames.
-
-=========== 11< ==========
-[11] >           debugger; 	
-[12]             var sameName = 'foo'; 	
-[13]             innerFunction('not-foo'); 	
-[14]         } 	
-[15]    	
-[16]         function innerFunction(sameName) { 	
-[17]           return; 	
-[18]         } 	
-=========== 11< ==========
-[11]             debugger; 	
-[12] >           var sameName = 'foo'; 	
-[13]             innerFunction('not-foo'); 	
-[14]         } 	
-[15]    	
-[16]         function innerFunction(sameName) { 	
-[17]           return; 	
-[18]         } 	
-=========== 11< ==========
-[11]             debugger; 	
-[12]             var sameName = 'foo'; 	 sameName = "foo"
-[13] >           innerFunction('not-foo'); 	
-[14]         } 	
-[15]    	
-[16]         function innerFunction(sameName) { 	
-[17]           return; 	
-[18]         } 	
-=========== 11< ==========
-[11]             debugger; 	
-[12]             var sameName = 'foo'; 	
-[13]             innerFunction('not-foo'); 	
-[14]         } 	
-[15]    	
-[16]         function innerFunction(sameName) { 	 sameName = "not-foo"
-[17] >         return; 	
-[18]         } 	
-=========== 11< ==========
-[11]             debugger; 	
-[12]             var sameName = 'foo'; 	
-[13]             innerFunction('not-foo'); 	
-[14]         } 	
-[15]    	
-[16]         function innerFunction(sameName) { 	 sameName = "not-foo"
-[17] >         return; 	
-[18]         } 	
-=========== 11< ==========
-[11]             debugger; 	
-[12]             var sameName = 'foo'; 	 sameName = "foo"
-[13]             innerFunction('not-foo'); 	
-[14] >       } 	
-[15]    	
-[16]         function innerFunction(sameName) { 	
-[17]           return; 	
-[18]         } 	
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/debugger-inline-values-frames.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/debugger-inline-values-frames.js
deleted file mode 100644
index da64885..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/debugger-inline-values-frames.js
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {TestRunner} from 'test_runner';
-import {SourcesTestRunner} from 'sources_test_runner';
-
-import * as SourcesModule from 'devtools/panels/sources/sources.js';
-
-(async function() {
-  TestRunner.addResult(`Tests inline values rendering while stepping between call frames.\n`);
-  await TestRunner.showPanel('sources');
-  await TestRunner.evaluateInPagePromise(`
-      function testFunction()
-      {
-          debugger;
-          var sameName = 'foo';
-          innerFunction('not-foo');
-      }
-
-      function innerFunction(sameName) {
-        return;
-      }
-  `);
-
-  SourcesTestRunner.startDebuggerTest(runTestFunction);
-  SourcesTestRunner.setQuiet(true);
-
-  var stepCount = 0;
-
-  function runTestFunction() {
-    TestRunner.addSniffer(
-        SourcesModule.DebuggerPlugin.DebuggerPlugin.prototype, 'executionLineChanged',
-        onSetExecutionLocation);
-    TestRunner.evaluateInPage('setTimeout(testFunction, 0)');
-  }
-
-  async function onSetExecutionLocation(liveLocation) {
-    TestRunner.deprecatedRunAfterPendingDispatches(dumpAndContinue.bind(
-        null, this.textEditor, (await liveLocation.uiLocation()).lineNumber));
-  }
-
-  function dumpAndContinue(textEditor, lineNumber) {
-    var startLine = 11;
-    var endLine = 19;
-    TestRunner.addResult(`=========== ${startLine}< ==========`);
-    var lineCount = endLine - startLine;
-    for (var i = startLine; i < endLine; ++i) {
-      var output = ['[' + (i < lineCount ? ' ' : '') + i + ']'];
-      output.push(i == lineNumber ? '>' : ' ');
-      output.push(textEditor.line(i));
-      output.push('\t');
-      textEditor.decorations.get(i).forEach(decoration => output.push(decoration.element.deepTextContent()));
-      TestRunner.addResult(output.join(' '));
-    }
-
-    TestRunner.addSniffer(
-        SourcesModule.DebuggerPlugin.DebuggerPlugin.prototype, 'executionLineChanged',
-        onSetExecutionLocation);
-    if (++stepCount < 6)
-      SourcesTestRunner.stepInto();
-    else
-      SourcesTestRunner.completeDebuggerTest();
-  }
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/debugger-inline-values.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/debugger-inline-values.js
deleted file mode 100644
index 5a88cb2..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-ui/debugger-inline-values.js
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {TestRunner} from 'test_runner';
-import {SourcesTestRunner} from 'sources_test_runner';
-
-import * as SourcesModule from 'devtools/panels/sources/sources.js';
-
-(async function() {
-  TestRunner.addResult(`Tests inline values rendering in the sources panel.\n`);
-  await TestRunner.showPanel('sources');
-  await TestRunner.evaluateInPagePromise(`
-      function testFunction()
-      {
-          debugger;
-          var a = { k: 1 };
-          var b = [1, 2, 3, 4, 5];
-          var c = new Array(100); c[10] = 1;
-          a.k = 2;
-          a.l = window;
-          b[1]++;
-          b[2] = document.body;
-      }
-  `);
-
-  SourcesTestRunner.startDebuggerTest(runTestFunction);
-  SourcesTestRunner.setQuiet(true);
-
-  var stepCount = 0;
-
-  function runTestFunction() {
-    TestRunner.addSniffer(
-        SourcesModule.DebuggerPlugin.DebuggerPlugin.prototype, 'executionLineChanged',
-        onSetExecutionLocation);
-    TestRunner.evaluateInPage('setTimeout(testFunction, 0)');
-  }
-
-  async function onSetExecutionLocation(liveLocation) {
-    TestRunner.deprecatedRunAfterPendingDispatches(dumpAndContinue.bind(
-        null, this.textEditor, (await liveLocation.uiLocation()).lineNumber));
-  }
-
-  function dumpAndContinue(textEditor, lineNumber) {
-    TestRunner.addResult('=========== 11< ==========');
-    for (var i = 11; i < 21; ++i) {
-      var output = ['[' + (i < 10 ? ' ' : '') + i + ']'];
-      output.push(i == lineNumber ? '>' : ' ');
-      output.push(textEditor.line(i));
-      output.push('\t');
-      textEditor.decorations.get(i).forEach(decoration => output.push(decoration.element.deepTextContent()));
-      TestRunner.addResult(output.join(' '));
-    }
-
-    TestRunner.addSniffer(
-        SourcesModule.DebuggerPlugin.DebuggerPlugin.prototype, 'executionLineChanged',
-        onSetExecutionLocation);
-    if (++stepCount < 10)
-      SourcesTestRunner.stepOver();
-    else
-      SourcesTestRunner.completeDebuggerTest();
-  }
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/live-edit-no-reveal-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/live-edit-no-reveal-expected.txt
deleted file mode 100644
index 9e97d9e..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/live-edit-no-reveal-expected.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-Tests live edit feature.
-
-
-Running: testLiveEditWithoutStepInWhenPausedThenStepIntoCausesCursorMove
-Script execution paused.
-Moving cursor to (0, 0).
-Committing live edit.
-Script execution paused.
-Stepping into...
-Did step into
-Script execution resumed.
-Script execution paused.
-Script execution resumed.
-Cursor position is: (2, 4).
-
-Running: testLiveEditWithStepInWhenPausedThenStepIntoCausesCursorMove
-Script execution paused.
-Moving cursor to (0, 0).
-Committing live edit.
-Did step into
-Stepping into...
-Did step into
-Script execution resumed.
-Script execution paused.
-Script execution resumed.
-Script execution paused.
-Script execution resumed.
-Cursor position is: (8, 4).
-
-Running: testLiveEditWithoutStepInWhenPausedDoesNotCauseCursorMove
-Script execution paused.
-Moving cursor to (0, 0).
-Committing live edit.
-Script execution paused.
-Script execution resumed.
-Cursor position is: (0, 0).
-
-Running: testLiveEditWithStepInWhenPausedDoesNotCauseCursorMove
-Script execution paused.
-Moving cursor to (0, 0).
-Committing live edit.
-Did step into
-Script execution resumed.
-Script execution paused.
-Script execution resumed.
-Cursor position is: (0, 0).
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/live-edit-no-reveal.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/live-edit-no-reveal.js
deleted file mode 100644
index c7ab56ce..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/live-edit-no-reveal.js
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {TestRunner} from 'test_runner';
-import {SourcesTestRunner} from 'sources_test_runner';
-
-import * as TextUtils from 'devtools/models/text_utils/text_utils.js';
-import * as Sources from 'devtools/panels/sources/sources.js';
-
-(async function() {
-  TestRunner.addResult(`Tests live edit feature.\n`);
-  await TestRunner.showPanel('sources');
-  await TestRunner.addScriptTag('resources/edit-me-when-paused-no-reveal.js');
-
-  var panel = Sources.SourcesPanel.SourcesPanel.instance();
-  var sourceFrame;
-
-  function didStepInto() {
-    TestRunner.addResult('Did step into');
-  }
-
-  TestRunner.addSniffer(TestRunner.debuggerModel, 'stepInto', didStepInto, true);
-
-  function testLiveEditWhenPausedDoesNotCauseCursorMove(oldText, newText, next) {
-    SourcesTestRunner.showScriptSource('edit-me-when-paused-no-reveal.js', didShowScriptSource);
-
-    async function didShowScriptSource(sourceFrame) {
-      SourcesTestRunner.waitUntilPaused(paused);
-      await SourcesTestRunner.setBreakpoint(sourceFrame, 8, '', true);
-      TestRunner.evaluateInPage('f1()', didEvaluateInPage);
-    }
-
-    function paused(callFrames) {
-      sourceFrame = panel.visibleView;
-      SourcesTestRunner.removeBreakpoint(sourceFrame, 8);
-      TestRunner.addSniffer(TestRunner.debuggerModel, '_didEditScriptSource', didEditScriptSource);
-      panel._updateLastModificationTimeForTest();
-      SourcesTestRunner.replaceInSource(sourceFrame, oldText, newText);
-      TestRunner.addResult('Moving cursor to (0, 0).');
-      sourceFrame.setSelection(TextUtils.TextRange.TextRange.createFromLocation(0, 0));
-      TestRunner.addResult('Committing live edit.');
-      SourcesTestRunner.commitSource(sourceFrame);
-    }
-
-    function didEditScriptSource() {
-      SourcesTestRunner.resumeExecution();
-    }
-
-    function didEvaluateInPage(result) {
-      panel._lastModificationTimeoutPassedForTest();
-      var selection = sourceFrame.textEditor.selection();
-      TestRunner.addResult('Cursor position is: (' + selection.startLine + ', ' + selection.startColumn + ').');
-      TestRunner.assertEquals(sourceFrame, panel.visibleView, 'Another file editor is open.');
-      next();
-    }
-  }
-
-  function testLiveEditWhenPausedThenStepIntoCausesCursorMove(oldText, newText, next) {
-    SourcesTestRunner.showScriptSource('edit-me-when-paused-no-reveal.js', didShowScriptSource);
-
-    async function didShowScriptSource(sourceFrame) {
-      SourcesTestRunner.waitUntilPaused(paused);
-      await SourcesTestRunner.setBreakpoint(sourceFrame, 8, '', true);
-      TestRunner.evaluateInPage('f1()', didEvaluateInPage);
-    }
-
-    function paused(callFrames) {
-      sourceFrame = panel.visibleView;
-      SourcesTestRunner.removeBreakpoint(sourceFrame, 8);
-      TestRunner.addSniffer(TestRunner.debuggerModel, '_didEditScriptSource', didEditScriptSource);
-      panel._lastModificationTimeoutPassedForTest();
-      SourcesTestRunner.replaceInSource(sourceFrame, oldText, newText);
-      TestRunner.addResult('Moving cursor to (0, 0).');
-      sourceFrame.setSelection(TextUtils.TextRange.TextRange.createFromLocation(0, 0));
-      TestRunner.addResult('Committing live edit.');
-      SourcesTestRunner.commitSource(sourceFrame);
-    }
-
-    function didEditScriptSource() {
-      TestRunner.addResult('Stepping into...');
-      TestRunner.addSniffer(Sources.SourcesView.SourcesView.prototype, 'showSourceLocation', didRevealAfterStepInto);
-      panel._lastModificationTimeoutPassedForTest();
-      SourcesTestRunner.stepInto();
-    }
-
-    function didRevealAfterStepInto() {
-      SourcesTestRunner.resumeExecution();
-    }
-
-    function didEvaluateInPage(result) {
-      var selection = sourceFrame.textEditor.selection();
-      TestRunner.addResult('Cursor position is: (' + selection.startLine + ', ' + selection.startColumn + ').');
-      TestRunner.assertEquals(sourceFrame, panel.visibleView, 'Another file editor is open.');
-      next();
-    }
-  }
-
-  SourcesTestRunner.runDebuggerTestSuite([
-    function testLiveEditWithoutStepInWhenPausedThenStepIntoCausesCursorMove(next) {
-      testLiveEditWhenPausedThenStepIntoCausesCursorMove('function f2()', ' function f2()', next);
-    },
-
-    function testLiveEditWithStepInWhenPausedThenStepIntoCausesCursorMove(next) {
-      testLiveEditWhenPausedThenStepIntoCausesCursorMove('return x + f2();', 'return x + f2(); ', next);
-    },
-
-    function testLiveEditWithoutStepInWhenPausedDoesNotCauseCursorMove(next) {
-      testLiveEditWhenPausedDoesNotCauseCursorMove('function f2()', ' function f2()', next);
-    },
-
-    function testLiveEditWithStepInWhenPausedDoesNotCauseCursorMove(next) {
-      testLiveEditWhenPausedDoesNotCauseCursorMove('return x + f2();', 'return x + f2(); ', next);
-    }
-  ]);
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/unit/object-events-expected.txt b/third_party/blink/web_tests/http/tests/devtools/unit/object-events-expected.txt
deleted file mode 100644
index 83a54f5..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/unit/object-events-expected.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-The test verifies that DevTools events work.
-
-Adding a listener with this 'original listener'
-Dispatching event with the data 'first event'
-Heard event with the data 'first event' and this 'original listener'
-
-Adding a listener with this 'second listener'
-Dispatching event with the data 'second event'
-Heard event with the data 'second event' and this 'original listener'
-Heard event with the data 'second event' and this 'second listener'
-
-Removing a listener with this 'second listener'
-Dispatching event with the data 'third event'
-Heard event with the data 'third event' and this 'original listener'
-
-Adding a listener that removes a later listener
-Adding a listener with this 'later listener to be removed'
-Dispatching event with the data 'fourth event'
-Heard event with the data 'fourth event' and this 'original listener'
-removing the listener during the event: fourth event 
-Removing a listener with this 'later listener to be removed'
-
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/unit/object-events.js b/third_party/blink/web_tests/http/tests/devtools/unit/object-events.js
deleted file mode 100644
index 6fac046..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/unit/object-events.js
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {TestRunner} from 'test_runner';
-
-import * as Common from 'devtools/core/common/common.js';
-
-(async function() {
-  TestRunner.addResult(`The test verifies that DevTools events work.\n`);
-  var object = new Common.ObjectWrapper.ObjectWrapper();
-  var eventSymbol = Symbol('Event');
-
-  addListener('original listener');
-  dispatch('first event');
-  addListener('second listener');
-  dispatch('second event');
-  removeListener('second listener');
-  dispatch('third event');
-
-  TestRunner.addResult('Adding a listener that removes a later listener')
-  object.addEventListener(eventSymbol, event => {
-    TestRunner.addResult(`removing the listener during the event: ${event.data} `);
-    removeListener('later listener to be removed');
-  });
-  addListener('later listener to be removed')
-  dispatch('fourth event');
-
-  TestRunner.completeTest();
-
-  function eventListener(event) {
-    TestRunner.addResult(`Heard event with the data '${event.data}' and this '${this}'`);
-  }
-
-  function dispatch(data) {
-    TestRunner.addResult(`Dispatching event with the data '${data}'`);
-    object.dispatchEventToListeners(eventSymbol, data);
-    TestRunner.addResult('');
-  }
-
-  function addListener(thisValue) {
-    TestRunner.addResult(`Adding a listener with this '${thisValue}'`);
-    object.addEventListener(eventSymbol, eventListener, thisValue);
-  }
-
-  function removeListener(thisValue) {
-    TestRunner.addResult(`Removing a listener with this '${thisValue}'`);
-    object.removeEventListener(eventSymbol, eventListener, thisValue);
-
-  }
-
-})();
diff --git a/third_party/blink/web_tests/virtual/sanitizer-api/README.md b/third_party/blink/web_tests/virtual/sanitizer-api/README.md
deleted file mode 100644
index 95a66a3..0000000
--- a/third_party/blink/web_tests/virtual/sanitizer-api/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
-= Sanitizer API Virtual Test Suite =
-
-We're removing and then re-implementing the Sanitizer API. In order to not have
-to deal with failing sanitizer WPT tests in the mean time, this virtual test
-suite is "stealing" all the WPT sanitizer tests.
-
-Note that the virtual test suite definition uses `exclusive_tests: ALL`,
-which causes these tests to only be executed as part of this test suite.
diff --git a/third_party/dawn b/third_party/dawn
index 23f08c7..d07825e 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit 23f08c798e68e28242fe3cd6990ec049695a930b
+Subproject commit d07825efa003125c46a2819c37081dbde0528277
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index 60b8977..9d9a726 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit 60b8977eb329282198e284c76f6ac002f5320b45
+Subproject commit 9d9a7262df8a7db685524e449c0c08fc3f5f0e8c
diff --git a/third_party/fontconfig/BUILD.gn b/third_party/fontconfig/BUILD.gn
index 76816f0..2ca2c39 100644
--- a/third_party/fontconfig/BUILD.gn
+++ b/third_party/fontconfig/BUILD.gn
@@ -82,6 +82,7 @@
       "BINDGEN_IGNORE_VISIBILITY=1",
       "FC_NO_MT=1",
       "FLEXIBLE_ARRAY_MEMBER=1",
+      "HAVE_VASPRINTF=1",
     ]
   }
 
@@ -99,7 +100,6 @@
       "src/src/fcdir.c",
       "src/src/fcfontations.c",
       "src/src/fcformat.c",
-      "src/src/fcfreetype.c",
       "src/src/fcfs.c",
       "src/src/fchash.c",
       "src/src/fcinit.c",
@@ -118,8 +118,6 @@
       "src/src/fcstr.c",
       "src/src/fcweight.c",
       "src/src/fcxml.c",
-      "src/src/ftglue.c",
-      "src/src/ftglue.h",
     ]
 
     include_dirs = [
@@ -143,7 +141,6 @@
 
     deps = [
       ":fontconfig_fontations_ffi",
-      "//build/config/freetype",
       "//third_party/libxml",
       "//third_party/zlib",
     ]
diff --git a/third_party/fontconfig/README.chromium b/third_party/fontconfig/README.chromium
index 95605d24..dcd219a 100644
--- a/third_party/fontconfig/README.chromium
+++ b/third_party/fontconfig/README.chromium
@@ -1,6 +1,6 @@
 Name: fontconfig
 URL: http://www.freedesktop.org/wiki/Software/fontconfig/
-Version: 23b3fc6e58a13d126b9c30fafc9a16f8bd7143e9
+Version: d62c2ab268d1679335daa8fb0ea6970f35224a76
 Update Mechanism: Manual
 CPEPrefix: cpe:/a:fontconfig_project:fontconfig:2.17.1
 License: public-domain-md5, MIT-Modern-Variant, HPND-sell-variant, MIT
@@ -12,7 +12,12 @@
 Fontconfig is a library for configuring and customizing font access.
 
 Modifications:
-- None
+- We locally build FontConfig fully based on Fontations, and without FreeType.
+  We do that by removing ENABLE_FREETYPE from meson-config.h see
+    - https://gitlab.freedesktop.org/fontconfig/fontconfig/-/issues/502
+    - https://gitlab.freedesktop.org/fontconfig/fontconfig/-/merge_requests/488
+    - https://gitlab.freedesktop.org/fontconfig/fontconfig/-/merge_requests/490
+  The update.sh script removes these lines from meson-config.h
 
 To import a new snapshot of fontconfig:
 Run update.sh
diff --git a/third_party/fontconfig/include/fcalias.h b/third_party/fontconfig/include/fcalias.h
index dd87830d..33951c65 100644
--- a/third_party/fontconfig/include/fcalias.h
+++ b/third_party/fontconfig/include/fcalias.h
@@ -162,10 +162,6 @@
 #define FcDirCacheLoadFile IA__FcDirCacheLoadFile
 extern __typeof (FcDirCacheUnload) IA__FcDirCacheUnload FC_ATTRIBUTE_VISIBILITY_HIDDEN;
 #define FcDirCacheUnload IA__FcDirCacheUnload
-extern __typeof (FcFreeTypeQuery) IA__FcFreeTypeQuery FC_ATTRIBUTE_VISIBILITY_HIDDEN;
-#define FcFreeTypeQuery IA__FcFreeTypeQuery
-extern __typeof (FcFreeTypeQueryAll) IA__FcFreeTypeQueryAll FC_ATTRIBUTE_VISIBILITY_HIDDEN;
-#define FcFreeTypeQueryAll IA__FcFreeTypeQueryAll
 extern __typeof (FcFontSetCreate) IA__FcFontSetCreate FC_ATTRIBUTE_VISIBILITY_HIDDEN;
 #define FcFontSetCreate IA__FcFontSetCreate
 extern __typeof (FcFontSetDestroy) IA__FcFontSetDestroy FC_ATTRIBUTE_VISIBILITY_HIDDEN;
@@ -288,6 +284,8 @@
 #define FcNameGetConstantFor IA__FcNameGetConstantFor
 extern __typeof (FcNameConstant) IA__FcNameConstant FC_ATTRIBUTE_VISIBILITY_HIDDEN;
 #define FcNameConstant IA__FcNameConstant
+extern __typeof (FcNameGetConstantNameFrom) IA__FcNameGetConstantNameFrom FC_ATTRIBUTE_VISIBILITY_HIDDEN;
+#define FcNameGetConstantNameFrom IA__FcNameGetConstantNameFrom
 extern __typeof (FcNameParse) IA__FcNameParse FC_ATTRIBUTE_VISIBILITY_HIDDEN;
 #define FcNameParse IA__FcNameParse
 extern __typeof (FcNameUnparse) IA__FcNameUnparse FC_ATTRIBUTE_VISIBILITY_HIDDEN;
@@ -460,6 +458,8 @@
 #define FcConfigParseAndLoad IA__FcConfigParseAndLoad
 extern __typeof (FcConfigParseAndLoadFromMemory) IA__FcConfigParseAndLoadFromMemory FC_ATTRIBUTE_VISIBILITY_HIDDEN;
 #define FcConfigParseAndLoadFromMemory IA__FcConfigParseAndLoadFromMemory
+extern __typeof (FcConfigFileGenerate) IA__FcConfigFileGenerate FC_ATTRIBUTE_VISIBILITY_HIDDEN;
+#define FcConfigFileGenerate IA__FcConfigFileGenerate
 extern __typeof (FcConfigGetRescanInverval) IA__FcConfigGetRescanInverval FC_ATTRIBUTE_VISIBILITY_HIDDEN;
 #define FcConfigGetRescanInverval IA__FcConfigGetRescanInverval
 extern __typeof (FcConfigSetRescanInverval) IA__FcConfigSetRescanInverval FC_ATTRIBUTE_VISIBILITY_HIDDEN;
diff --git a/third_party/fontconfig/include/fcaliastail.h b/third_party/fontconfig/include/fcaliastail.h
index 53ba175..e9b98e2 100644
--- a/third_party/fontconfig/include/fcaliastail.h
+++ b/third_party/fontconfig/include/fcaliastail.h
@@ -183,12 +183,6 @@
 # undef FcDirCacheUnload
 extern __typeof (FcDirCacheUnload) FcDirCacheUnload __attribute((alias("IA__FcDirCacheUnload"))) FC_ATTRIBUTE_VISIBILITY_EXPORT;
 #endif /* __fccache__ */
-#ifdef __fcfreetype__
-# undef FcFreeTypeQuery
-extern __typeof (FcFreeTypeQuery) FcFreeTypeQuery __attribute((alias("IA__FcFreeTypeQuery"))) FC_ATTRIBUTE_VISIBILITY_EXPORT;
-# undef FcFreeTypeQueryAll
-extern __typeof (FcFreeTypeQueryAll) FcFreeTypeQueryAll __attribute((alias("IA__FcFreeTypeQueryAll"))) FC_ATTRIBUTE_VISIBILITY_EXPORT;
-#endif /* __fcfreetype__ */
 #ifdef __fcfs__
 # undef FcFontSetCreate
 extern __typeof (FcFontSetCreate) FcFontSetCreate __attribute((alias("IA__FcFontSetCreate"))) FC_ATTRIBUTE_VISIBILITY_EXPORT;
@@ -326,6 +320,8 @@
 extern __typeof (FcNameGetConstantFor) FcNameGetConstantFor __attribute((alias("IA__FcNameGetConstantFor"))) FC_ATTRIBUTE_VISIBILITY_EXPORT;
 # undef FcNameConstant
 extern __typeof (FcNameConstant) FcNameConstant __attribute((alias("IA__FcNameConstant"))) FC_ATTRIBUTE_VISIBILITY_EXPORT;
+# undef FcNameGetConstantNameFrom
+extern __typeof (FcNameGetConstantNameFrom) FcNameGetConstantNameFrom __attribute((alias("IA__FcNameGetConstantNameFrom"))) FC_ATTRIBUTE_VISIBILITY_EXPORT;
 # undef FcNameParse
 extern __typeof (FcNameParse) FcNameParse __attribute((alias("IA__FcNameParse"))) FC_ATTRIBUTE_VISIBILITY_EXPORT;
 # undef FcNameUnparse
@@ -513,6 +509,10 @@
 # undef FcConfigParseAndLoadFromMemory
 extern __typeof (FcConfigParseAndLoadFromMemory) FcConfigParseAndLoadFromMemory __attribute((alias("IA__FcConfigParseAndLoadFromMemory"))) FC_ATTRIBUTE_VISIBILITY_EXPORT;
 #endif /* __fcxml__ */
+#ifdef __fcconffile__
+# undef FcConfigFileGenerate
+extern __typeof (FcConfigFileGenerate) FcConfigFileGenerate __attribute((alias("IA__FcConfigFileGenerate"))) FC_ATTRIBUTE_VISIBILITY_EXPORT;
+#endif /* __fcconffile__ */
 #ifdef __fccfg__
 # undef FcConfigGetRescanInverval
 extern __typeof (FcConfigGetRescanInverval) FcConfigGetRescanInverval __attribute((alias("IA__FcConfigGetRescanInverval"))) FC_ATTRIBUTE_VISIBILITY_EXPORT;
diff --git a/third_party/fontconfig/include/fcftalias.h b/third_party/fontconfig/include/fcftalias.h
index 593e9977..4af6a68d6 100644
--- a/third_party/fontconfig/include/fcftalias.h
+++ b/third_party/fontconfig/include/fcftalias.h
@@ -10,3 +10,7 @@
 #define FcPatternAddFTFace IA__FcPatternAddFTFace
 extern __typeof (FcFreeTypeQueryFace) IA__FcFreeTypeQueryFace FC_ATTRIBUTE_VISIBILITY_HIDDEN;
 #define FcFreeTypeQueryFace IA__FcFreeTypeQueryFace
+extern __typeof (FcFreeTypeQuery) IA__FcFreeTypeQuery FC_ATTRIBUTE_VISIBILITY_HIDDEN;
+#define FcFreeTypeQuery IA__FcFreeTypeQuery
+extern __typeof (FcFreeTypeQueryAll) IA__FcFreeTypeQueryAll FC_ATTRIBUTE_VISIBILITY_HIDDEN;
+#define FcFreeTypeQueryAll IA__FcFreeTypeQueryAll
diff --git a/third_party/fontconfig/include/fcftaliastail.h b/third_party/fontconfig/include/fcftaliastail.h
index 3070746..8b1e04d 100644
--- a/third_party/fontconfig/include/fcftaliastail.h
+++ b/third_party/fontconfig/include/fcftaliastail.h
@@ -16,5 +16,9 @@
 #ifdef __fcfreetype__
 # undef FcFreeTypeQueryFace
 extern __typeof (FcFreeTypeQueryFace) FcFreeTypeQueryFace __attribute((alias("IA__FcFreeTypeQueryFace"))) FC_ATTRIBUTE_VISIBILITY_EXPORT;
+# undef FcFreeTypeQuery
+extern __typeof (FcFreeTypeQuery) FcFreeTypeQuery __attribute((alias("IA__FcFreeTypeQuery"))) FC_ATTRIBUTE_VISIBILITY_EXPORT;
+# undef FcFreeTypeQueryAll
+extern __typeof (FcFreeTypeQueryAll) FcFreeTypeQueryAll __attribute((alias("IA__FcFreeTypeQueryAll"))) FC_ATTRIBUTE_VISIBILITY_EXPORT;
 #endif /* __fcfreetype__ */
 #endif /* HAVE_GNUC_ATTRIBUTE */
diff --git a/third_party/fontconfig/include/fontconfig/fontconfig.h b/third_party/fontconfig/include/fontconfig/fontconfig.h
index 79e300f..3f014ac 100644
--- a/third_party/fontconfig/include/fontconfig/fontconfig.h
+++ b/third_party/fontconfig/include/fontconfig/fontconfig.h
@@ -238,6 +238,8 @@
     FcTypeRange
 } FcType;
 
+typedef int FcObject;
+
 typedef struct _FcMatrix {
     double xx, xy, yx, yy;
 } FcMatrix;
@@ -312,9 +314,11 @@
 } FcFontSet;
 
 typedef struct _FcObjectSet {
-    int          nobject;
+    int          nobject; /* deprecated */
     int          sobject;
-    const char **objects;
+    const char **objects; /* deprecated */
+    int          nobjIds;
+    FcObject    *objIds;
 } FcObjectSet;
 
 typedef enum _FcMatchKind {
@@ -680,13 +684,6 @@
 FcPublic void
 FcDirCacheUnload (FcCache *cache);
 
-/* fcfreetype.c */
-FcPublic FcPattern *
-FcFreeTypeQuery (const FcChar8 *file, unsigned int id, FcBlanks *blanks, int *count);
-
-FcPublic unsigned int
-FcFreeTypeQueryAll (const FcChar8 *file, unsigned int id, FcBlanks *blanks, int *count, FcFontSet *set);
-
 /* fcfs.c */
 
 FcPublic FcFontSet *
@@ -909,6 +906,9 @@
 FcPublic FcBool
 FcNameConstant (const FcChar8 *string, int *result);
 
+FcPublic const FcChar8 *
+FcNameGetConstantNameFrom (const char *object, int value);
+
 FcPublic FcPattern *
 FcNameParse (const FcChar8 *name);
 
@@ -1198,6 +1198,13 @@
                                 const FcChar8 *buffer,
                                 FcBool         complain);
 
+/* fcconffile.c */
+FcPublic FcChar8 *
+FcConfigFileGenerate (FcConfig      *config,
+                      FcPattern     *pat,
+                      const FcChar8 *font_path);
+
+
 _FCFUNCPROTOEND
 
 #undef FC_ATTRIBUTE_SENTINEL
diff --git a/third_party/fontconfig/include/meson-config.h b/third_party/fontconfig/include/meson-config.h
index 7f6ee54..d9e3d64 100644
--- a/third_party/fontconfig/include/meson-config.h
+++ b/third_party/fontconfig/include/meson-config.h
@@ -36,10 +36,10 @@
 
 #define FONTCONFIG_PATH "/etc/fonts"
 
-#define FREETYPE_PCF_LONG_FAMILY_NAMES
-
 #define GETTEXT_PACKAGE "fontconfig"
 
+#define HAVE_C99_VSNPRINTF 1
+
 #define HAVE_DCGETTEXT 1
 
 #define HAVE_DIRENT_H 1
@@ -86,8 +86,6 @@
 
 #define HAVE_MKDTEMP 1
 
-#define HAVE_MKOSTEMP 1
-
 #define HAVE_MKSTEMP 1
 
 #define HAVE_MMAP 1
@@ -112,6 +110,8 @@
 
 #define HAVE_STDLIB_H 1
 
+#define HAVE_STRDUP 1
+
 #define HAVE_STRERROR 1
 
 #define HAVE_STRERROR_R 1
@@ -142,6 +142,8 @@
 
 #define HAVE_UNISTD_H 1
 
+#define HAVE_VASPRINTF 1
+
 #define HAVE_VPRINTF 1
 
 #define HAVE_VSNPRINTF 1
diff --git a/third_party/fontconfig/src b/third_party/fontconfig/src
index 23b3fc6..d62c2ab 160000
--- a/third_party/fontconfig/src
+++ b/third_party/fontconfig/src
@@ -1 +1 @@
-Subproject commit 23b3fc6e58a13d126b9c30fafc9a16f8bd7143e9
+Subproject commit d62c2ab268d1679335daa8fb0ea6970f35224a76
diff --git a/third_party/fontconfig/update.sh b/third_party/fontconfig/update.sh
index 4ea8558e..7b9ab2e9 100755
--- a/third_party/fontconfig/update.sh
+++ b/third_party/fontconfig/update.sh
@@ -6,8 +6,8 @@
 SRC_DIR="$SCRIPT_DIR/../.."
 
 cd "$SCRIPT_DIR/src"
-git fetch origin main
-REVISION="$(git rev-parse origin/main)"
+git fetch origin upstream/main
+REVISION="$(git rev-parse origin/upstream/main)"
 
 cd "$SRC_DIR"
 roll-dep src/third_party/fontconfig/src --roll-to "$REVISION" "$@"
@@ -20,6 +20,10 @@
 # config.h has "#define _GNU_SOURCE" which would conflict with
 # our "#define _GNU_SOURCE 1".
 sed -i 's/_GNU_SOURCE$/_GNU_SOURCE 1/' ../include/meson-config.h
+# Remove ENABLE_FREETYPE and related FreeType define from upstream,
+# as locally we build without FreeType.
+sed -i '/#define ENABLE_FREETYPE 1/{N;d}' ../include/meson-config.h
+sed -i '/#define FREETYPE_PCF_LONG_FAMILY_NAMES/{N;d}' ../include/meson-config.h
 # Use libxml2 instead of libexpat.  Currently, there's no way
 # to configure this with meson options.
 echo '#define ENABLE_LIBXML2 1' >>../include/config.h
diff --git a/third_party/perfetto b/third_party/perfetto
index 8ab293d..ec42dd38 160000
--- a/third_party/perfetto
+++ b/third_party/perfetto
@@ -1 +1 @@
-Subproject commit 8ab293da46a370dc17283a4d413242385e2033b1
+Subproject commit ec42dd387c2ab14c7369136e86898be936248315
diff --git a/third_party/webrtc b/third_party/webrtc
index d80cfa2..bfe5317 160000
--- a/third_party/webrtc
+++ b/third_party/webrtc
@@ -1 +1 @@
-Subproject commit d80cfa2a3d24618558f150bcca616a56cdca234a
+Subproject commit bfe531707560d16644de452e51e2c4fe40c46b91
diff --git a/tools/metrics/histograms/metadata/signin/enums.xml b/tools/metrics/histograms/metadata/signin/enums.xml
index 0bc75093..d61bd9e 100644
--- a/tools/metrics/histograms/metadata/signin/enums.xml
+++ b/tools/metrics/histograms/metadata/signin/enums.xml
@@ -763,7 +763,7 @@
   <int value="48" label="Edu Coexistence Login Handler"/>
   <int value="49" label="Edu Account Login Handler"/>
   <int value="50" label="Chromeos Family Link User Metrics provider"/>
-  <int value="51" label="Enterprise Identity Service"/>
+  <int value="51" label="Enterprise Identity Service (deprecated 12/2025)"/>
   <int value="52" label="Promotion Eligibility Checker"/>
   <int value="53" label="Password Manager Leak Detection"/>
   <int value="54" label="Android Management Client"/>
@@ -792,6 +792,8 @@
   <int value="77" label="YouTube Music"/>
   <int value="78" label="Contextual Tasks"/>
   <int value="79" label="Enterprise Plus Address"/>
+  <int value="80" label="Glic User Status"/>
+  <int value="81" label="Devtools Gdp"/>
 </enum>
 
 <!-- LINT.ThenChange(//components/signin/public/base/oauth_consumer_id.h:OAuthConsumerId) -->
@@ -1371,6 +1373,16 @@
   <int value="1" label="Finished"/>
 </enum>
 
+<!-- LINT.IfChange(SigninTokenTableGetAllWrappedBindingKeysResult) -->
+
+<enum name="SigninTokenTableGetAllWrappedBindingKeysResult">
+  <int value="0" label="Success"/>
+  <int value="1" label="SQL Invalid Statement"/>
+  <int value="2" label="SQL Failure"/>
+</enum>
+
+<!-- LINT.ThenChange(//components/signin/public/webdata/token_service_table.cc:GetAllWrappedBindingKeysResult) -->
+
 <enum name="SigninTokenTableReadTokenFromDBResult">
   <int value="0" label="Success"/>
   <int value="1" label="Decrypt failed"/>
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml
index 862d961..071e1efa 100644
--- a/tools/metrics/histograms/metadata/signin/histograms.xml
+++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -3780,6 +3780,16 @@
   </summary>
 </histogram>
 
+<histogram name="Signin.TokenTable.GetAllWrappedBindingKeysResult"
+    enum="SigninTokenTableGetAllWrappedBindingKeysResult"
+    expires_after="2026-06-08">
+  <owner>alexilin@chromium.org</owner>
+  <owner>chrome-signin-team@google.com</owner>
+  <summary>
+    Counts the results of loading wrapped binding keys from the token database.
+  </summary>
+</histogram>
+
 <histogram name="Signin.TokenTable.ReadTokenFromDBResult"
     enum="SigninTokenTableReadTokenFromDBResult" expires_after="never">
 <!-- expires-never: This reports health status for loading authentication
diff --git a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.cc b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.cc
index e5f172b5..99e9e13 100644
--- a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.cc
+++ b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.cc
@@ -68,8 +68,8 @@
   CloseSession();
 }
 
-void GlobalAcceleratorListenerLinux::OnServiceStarted(bool service_started) {
-  service_started_ = service_started;
+void GlobalAcceleratorListenerLinux::OnServiceStarted(uint32_t version) {
+  service_started_ = (version != 0);
 
   if (!*service_started_) {
     bound_commands_.clear();
diff --git a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.h b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.h
index 3838de75..3fcfe9ab 100644
--- a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.h
+++ b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.h
@@ -103,7 +103,7 @@
                          const std::string& signal_name,
                          bool success);
 
-  void OnServiceStarted(bool service_started);
+  void OnServiceStarted(uint32_t version);
 
   void CreateSession();
 
diff --git a/ui/gtk/select_file_dialog_linux_gtk.h b/ui/gtk/select_file_dialog_linux_gtk.h
index 213eaa5..740c8e25 100644
--- a/ui/gtk/select_file_dialog_linux_gtk.h
+++ b/ui/gtk/select_file_dialog_linux_gtk.h
@@ -34,7 +34,6 @@
   bool IsRunning(gfx::NativeWindow parent_window) const override;
 
   // SelectFileDialog implementation.
-  // |params| is unused and must be nullptr.
   void SelectFileImpl(Type type,
                       const std::u16string& title,
                       const base::FilePath& default_path,
diff --git a/ui/linux/linux_ui_factory.cc b/ui/linux/linux_ui_factory.cc
index 9307de3..3f0a2e0 100644
--- a/ui/linux/linux_ui_factory.cc
+++ b/ui/linux/linux_ui_factory.cc
@@ -15,7 +15,6 @@
 #include "base/no_destructor.h"
 #include "base/strings/string_util.h"
 #include "base/task/sequenced_task_runner.h"
-#include "build/chromecast_buildflags.h"
 #include "ui/base/buildflags.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/color/system_theme.h"
@@ -31,10 +30,6 @@
 #include "ui/qt/qt_ui.h"
 #endif
 
-#if !BUILDFLAG(IS_CASTOS)
-#include "ui/shell_dialogs/shell_dialog_linux.h"
-#endif
-
 namespace ui {
 
 namespace {
@@ -162,15 +157,7 @@
 }  // namespace
 
 LinuxUi* GetDefaultLinuxUi() {
-  auto* linux_ui = GetDefaultLinuxUiAndTheme();
-#if !BUILDFLAG(IS_CASTOS)
-  // This may create an extra thread that may race against the LinuxUi instance
-  // initialization, GtkInitFromCommandLine, in GtkUi for example, so this must
-  // be done after the call to GetDefaultLinuxUiAndTheme above, so the race
-  // condition is avoided.
-  shell_dialog_linux::Initialize();
-#endif
-  return linux_ui;
+  return GetDefaultLinuxUiAndTheme();
 }
 
 LinuxUiTheme* GetDefaultLinuxUiTheme() {
diff --git a/ui/shell_dialogs/BUILD.gn b/ui/shell_dialogs/BUILD.gn
index 4535b46..819b8e5 100644
--- a/ui/shell_dialogs/BUILD.gn
+++ b/ui/shell_dialogs/BUILD.gn
@@ -57,7 +57,6 @@
       "select_file_dialog_linux.cc",
       "select_file_dialog_linux.h",
       "shell_dialog_linux.cc",
-      "shell_dialog_linux.h",
     ]
     deps += [ "//ui/linux:linux_ui" ]
     if (use_dbus) {
diff --git a/ui/shell_dialogs/select_file_dialog_linux_portal.cc b/ui/shell_dialogs/select_file_dialog_linux_portal.cc
index 6430ef98..c66b8da5 100644
--- a/ui/shell_dialogs/select_file_dialog_linux_portal.cc
+++ b/ui/shell_dialogs/select_file_dialog_linux_portal.cc
@@ -20,6 +20,7 @@
 #include "base/time/time.h"
 #include "components/dbus/thread_linux/dbus_thread_linux.h"
 #include "components/dbus/xdg/portal.h"
+#include "components/dbus/xdg/portal_constants.h"
 #include "components/dbus/xdg/request.h"
 #include "dbus/message.h"
 #include "dbus/object_path.h"
@@ -27,6 +28,7 @@
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/native_ui_types.h"
+#include "ui/linux/linux_ui.h"
 #include "ui/linux/linux_ui_delegate.h"
 #include "ui/shell_dialogs/selected_file_info.h"
 #include "ui/strings/grit/ui_strings.h"
@@ -43,9 +45,6 @@
 
 constexpr int kXdgPortalRequiredVersion = 3;
 
-constexpr char kFileChooserInterfaceName[] =
-    "org.freedesktop.portal.FileChooser";
-
 constexpr char kFileChooserMethodOpenFile[] = "OpenFile";
 constexpr char kFileChooserMethodSaveFile[] = "SaveFile";
 
@@ -62,57 +61,6 @@
 
 constexpr char kFileUriPrefix[] = "file://";
 
-enum class ServiceAvailability {
-  kNotStarted,
-  kInProgress,
-  kNotAvailable,
-  kAvailable,
-};
-
-ServiceAvailability g_service_availability = ServiceAvailability::kNotStarted;
-
-scoped_refptr<base::SequencedTaskRunner>& GetMainTaskRunner() {
-  static base::NoDestructor<scoped_refptr<base::SequencedTaskRunner>>
-      main_task_runner;
-  return *main_task_runner;
-}
-
-void OnGetPropertyReply(dbus::Response* response) {
-  if (!response) {
-    g_service_availability = ServiceAvailability::kNotAvailable;
-    return;
-  }
-
-  uint32_t version = 0;
-  dbus::MessageReader reader(response);
-  if (!reader.PopVariantOfUint32(&version)) {
-    g_service_availability = ServiceAvailability::kNotAvailable;
-    return;
-  }
-
-  g_service_availability = version >= kXdgPortalRequiredVersion
-                               ? ServiceAvailability::kAvailable
-                               : ServiceAvailability::kNotAvailable;
-}
-
-void OnServiceStarted(bool service_started) {
-  if (!service_started) {
-    g_service_availability = ServiceAvailability::kNotAvailable;
-    return;
-  }
-
-  dbus::ObjectProxy* portal =
-      dbus_thread_linux::GetSharedSessionBus()->GetObjectProxy(
-          kXdgPortalService, dbus::ObjectPath(kXdgPortalObject));
-
-  dbus::MethodCall get_property_call(DBUS_INTERFACE_PROPERTIES, "Get");
-  dbus::MessageWriter get_property_writer(&get_property_call);
-  get_property_writer.AppendString(kFileChooserInterfaceName);
-  get_property_writer.AppendString("version");
-  portal->CallMethod(&get_property_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
-                     base::BindOnce(&OnGetPropertyReply));
-}
-
 std::vector<uint8_t> PathToByteArray(const base::FilePath& path) {
   std::vector<uint8_t> bytes(path.value().begin(), path.value().end());
   // Null-terminate the array.
@@ -154,36 +102,20 @@
   }
 }
 
-// static
-void SelectFileDialogLinuxPortal::StartAvailabilityTestInBackground() {
-  if (g_service_availability != ServiceAvailability::kNotStarted) {
-    return;
-  }
-  g_service_availability = ServiceAvailability::kInProgress;
-
-  GetMainTaskRunner() = base::SequencedTaskRunner::GetCurrentDefault();
-
-  dbus_xdg::RequestXdgDesktopPortal(
-      dbus_thread_linux::GetSharedSessionBus().get(),
-      base::BindOnce(&OnServiceStarted));
-}
-
-// static
-bool SelectFileDialogLinuxPortal::IsPortalAvailable() {
-  if (g_service_availability == ServiceAvailability::kInProgress) {
-    LOG(WARNING) << "Portal availability checked before test was complete";
-  }
-
-  return g_service_availability == ServiceAvailability::kAvailable;
-}
-
 void SelectFileDialogLinuxPortal::ListenerDestroyed() {
   weak_factory_.InvalidateWeakPtrs();
+  if (fallback_dialog_) {
+    fallback_dialog_->ListenerDestroyed();
+    fallback_dialog_.reset();
+  }
   SelectFileDialogLinux::ListenerDestroyed();
 }
 
 bool SelectFileDialogLinuxPortal::IsRunning(
     gfx::NativeWindow parent_window) const {
+  if (fallback_dialog_) {
+    return fallback_dialog_->IsRunning(parent_window);
+  }
   return parent_window && host_ && host_.get() == parent_window->GetHost();
 }
 
@@ -196,7 +128,7 @@
     const base::FilePath::StringType& default_extension,
     gfx::NativeWindow owning_window,
     const GURL* caller) {
-  type_ = type;
+  set_type(type);
   invoker_task_runner_ = base::SequencedTaskRunner::GetCurrentDefault();
 
   if (owning_window) {
@@ -214,6 +146,42 @@
 
   set_file_type_index(file_type_index);
 
+  std::optional<GURL> caller_copy;
+  if (caller) {
+    caller_copy = *caller;
+  }
+
+  dbus_xdg::RequestXdgDesktopPortal(
+      dbus_thread_linux::GetSharedSessionBus().get(),
+      base::BindOnce(&SelectFileDialogLinuxPortal::OnPortalAvailable,
+                     weak_factory_.GetWeakPtr(), title, default_path,
+                     default_extension, std::move(caller_copy)));
+}
+
+void SelectFileDialogLinuxPortal::OnPortalAvailable(
+    std::u16string title,
+    base::FilePath default_path,
+    base::FilePath::StringType default_extension,
+    std::optional<GURL> caller,
+    uint32_t version) {
+  if (version < kXdgPortalRequiredVersion) {
+    gfx::NativeWindow owning_window = host_ ? host_->window() : nullptr;
+    if (auto* linux_ui = ui::LinuxUi::instance()) {
+      fallback_dialog_ = linux_ui->CreateSelectFileDialog(listener_, nullptr);
+    }
+    if (fallback_dialog_) {
+      fallback_dialog_->SelectFile(
+          type(), title, default_path, &file_types(), file_type_index(),
+          default_extension, owning_window, caller ? &caller.value() : nullptr);
+      return;
+    }
+
+    if (listener_) {
+      listener_->FileSelectionCanceled();
+    }
+    return;
+  }
+
   PortalFilterSet filter_set = BuildFilterSet();
 
   // Keep a copy of the filters so the index of the chosen one can be identified
@@ -235,6 +203,9 @@
 }
 
 bool SelectFileDialogLinuxPortal::HasMultipleFileTypeChoicesImpl() {
+  if (fallback_dialog_) {
+    return fallback_dialog_->HasMultipleFileTypeChoices();
+  }
   return file_types().extensions.size() > 1;
 }
 
@@ -318,7 +289,7 @@
     base::FilePath::StringType default_extension,
     std::string parent_handle) {
   bool default_path_exists = CallDirectoryExistsOnUIThread(default_path);
-  GetMainTaskRunner()->PostTask(
+  invoker_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&SelectFileDialogLinuxPortal::SelectFileImplOnMainThread,
                      this, std::move(title), std::move(default_path),
@@ -333,10 +304,10 @@
     PortalFilterSet filter_set,
     base::FilePath::StringType default_extension,
     std::string parent_handle) {
-  CHECK(GetMainTaskRunner()->RunsTasksInCurrentSequence());
+  CHECK(invoker_task_runner_->RunsTasksInCurrentSequence());
 
   std::string method;
-  switch (type_) {
+  switch (type()) {
     case SELECT_FOLDER:
     case SELECT_UPLOAD_FOLDER:
     case SELECT_EXISTING_FOLDER:
@@ -356,9 +327,9 @@
     utf8_title = base::UTF16ToUTF8(title);
   } else {
     int message_id = 0;
-    if (type_ == SELECT_SAVEAS_FILE) {
+    if (type() == SELECT_SAVEAS_FILE) {
       message_id = IDS_SAVEAS_ALL_FILES;
-    } else if (type_ == SELECT_OPEN_MULTI_FILE) {
+    } else if (type() == SELECT_OPEN_MULTI_FILE) {
       message_id = IDS_OPEN_FILES_DIALOG_TITLE;
     } else {
       message_id = IDS_OPEN_FILE_DIALOG_TITLE;
@@ -378,7 +349,7 @@
     const PortalFilterSet& filter_set) {
   dbus_xdg::Dictionary dict;
 
-  switch (type_) {
+  switch (type()) {
     case SelectFileDialog::SELECT_UPLOAD_FOLDER:
       dict[kFileChooserOptionAcceptLabel] =
           dbus_utils::Variant::Wrap<"s">(l10n_util::GetStringUTF8(
@@ -410,7 +381,7 @@
 
       // current_folder is supported by xdg-desktop-portal but current_name
       // is not - only try to set this when invoking a save file dialog.
-      if (type_ == SELECT_SAVEAS_FILE) {
+      if (type() == SELECT_SAVEAS_FILE) {
         dict[kFileChooserOptionCurrentName] =
             dbus_utils::Variant::Wrap<"s">(default_path.BaseName().value());
       }
@@ -451,7 +422,7 @@
     const std::string& title,
     dbus_xdg::Dictionary options,
     std::string parent_handle) {
-  CHECK(GetMainTaskRunner()->RunsTasksInCurrentSequence());
+  CHECK(invoker_task_runner_->RunsTasksInCurrentSequence());
   scoped_refptr<dbus::Bus> bus = dbus_thread_linux::GetSharedSessionBus();
   dbus::ObjectProxy* portal = bus->GetObjectProxy(
       kXdgPortalService, dbus::ObjectPath(kXdgPortalObject));
@@ -461,8 +432,8 @@
       base::BindOnce(&SelectFileDialogLinuxPortal::OnFileChooserResponse,
                      base::Unretained(this));
   file_chooser_request_ = std::make_unique<dbus_xdg::Request>(
-      bus, portal, kFileChooserInterfaceName, method, std::move(options),
-      std::move(callback), std::move(parent_handle), title);
+      bus, portal, dbus_xdg::kFileChooserInterfaceName, method,
+      std::move(options), std::move(callback), std::move(parent_handle), title);
   invoker_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&SelectFileDialogLinuxPortal::DialogCreatedOnInvoker,
@@ -471,7 +442,7 @@
 
 void SelectFileDialogLinuxPortal::OnFileChooserResponse(
     base::expected<dbus_xdg::Dictionary, dbus_xdg::ResponseError> results) {
-  CHECK(GetMainTaskRunner()->RunsTasksInCurrentSequence());
+  CHECK(invoker_task_runner_->RunsTasksInCurrentSequence());
 
   file_chooser_request_.reset();
 
@@ -546,7 +517,7 @@
   UnparentOnInvoker();
 
   if (listener_) {
-    if (type_ == SELECT_OPEN_MULTI_FILE) {
+    if (type() == SELECT_OPEN_MULTI_FILE) {
       listener_->MultiFilesSelected(FilePathListToSelectedFileInfoList(paths));
     } else if (paths.size() > 1) {
       LOG(ERROR) << "Got >1 file URI from a single-file chooser";
diff --git a/ui/shell_dialogs/select_file_dialog_linux_portal.h b/ui/shell_dialogs/select_file_dialog_linux_portal.h
index 31b6709..af224fd 100644
--- a/ui/shell_dialogs/select_file_dialog_linux_portal.h
+++ b/ui/shell_dialogs/select_file_dialog_linux_portal.h
@@ -19,6 +19,7 @@
 #include "dbus/bus.h"
 #include "ui/shell_dialogs/select_file_dialog_linux.h"
 #include "ui/shell_dialogs/shell_dialogs_export.h"
+#include "url/gurl.h"
 
 namespace ui {
 
@@ -40,15 +41,6 @@
   SelectFileDialogLinuxPortal& operator=(
       const SelectFileDialogLinuxPortal& other) = delete;
 
-  // Starts running a test to check for the presence of the file chooser portal.
-  // Must be called on the UI thread. This should only be called once,
-  // preferably around program start.
-  static void StartAvailabilityTestInBackground();
-
-  // Checks if the file chooser portal is available. Logs a warning if the
-  // availability test has not yet completed.
-  static bool IsPortalAvailable();
-
  protected:
   ~SelectFileDialogLinuxPortal() override;
 
@@ -152,7 +144,11 @@
   // Removes the DialogInfo parent.
   void UnparentOnInvoker();
 
-  Type type_ = SELECT_NONE;
+  void OnPortalAvailable(std::u16string title,
+                         base::FilePath default_path,
+                         base::FilePath::StringType default_extension,
+                         std::optional<GURL> caller,
+                         uint32_t version);
 
   // The task runner the SelectFileImpl method was called on.
   scoped_refptr<base::SequencedTaskRunner> invoker_task_runner_;
@@ -160,6 +156,9 @@
   // This should be used by the invoker task runner.
   base::WeakPtr<aura::WindowTreeHost> host_;
 
+  // The fallback dialog to use if the portal is not available.
+  scoped_refptr<SelectFileDialog> fallback_dialog_;
+
   std::vector<PortalFilter> filters_;
 
   // The Request representing an in-flight file chooser call, if any.
diff --git a/ui/shell_dialogs/shell_dialog_linux.cc b/ui/shell_dialogs/shell_dialog_linux.cc
index 1a4daf4e..1546514 100644
--- a/ui/shell_dialogs/shell_dialog_linux.cc
+++ b/ui/shell_dialogs/shell_dialog_linux.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/shell_dialogs/shell_dialog_linux.h"
-
 #include "base/notreached.h"
 #include "build/config/linux/dbus/buildflags.h"
 #include "ui/linux/linux_ui.h"
@@ -14,62 +12,20 @@
 #include "ui/shell_dialogs/select_file_dialog_linux_portal.h"
 #endif
 
-namespace shell_dialog_linux {
-
-void Initialize() {
-#if BUILDFLAG(USE_DBUS)
-  ui::SelectFileDialogLinuxPortal::StartAvailabilityTestInBackground();
-#endif
-}
-
-}  // namespace shell_dialog_linux
-
 namespace ui {
 
-namespace {
-
-enum FileDialogChoice {
-  kUnknown,
-  kToolkit,
-#if BUILDFLAG(USE_DBUS)
-  kPortal,
-#endif
-};
-
-FileDialogChoice dialog_choice_ = kUnknown;
-
-FileDialogChoice GetFileDialogChoice() {
-#if BUILDFLAG(USE_DBUS)
-  // Check to see if the portal is available.
-  if (SelectFileDialogLinuxPortal::IsPortalAvailable())
-    return kPortal;
-#endif
-
-  return kToolkit;
-}
-
-}  // namespace
-
 SelectFileDialog* CreateSelectFileDialog(
     SelectFileDialog::Listener* listener,
     std::unique_ptr<SelectFilePolicy> policy) {
-  if (dialog_choice_ == kUnknown)
-    dialog_choice_ = GetFileDialogChoice();
-
-  const LinuxUi* linux_ui = LinuxUi::instance();
-  switch (dialog_choice_) {
-    case kToolkit:
-      if (!linux_ui)
-        break;
-      return linux_ui->CreateSelectFileDialog(listener, std::move(policy));
 #if BUILDFLAG(USE_DBUS)
-    case kPortal:
-      return new SelectFileDialogLinuxPortal(listener, std::move(policy));
-#endif
-    case kUnknown:
-      NOTREACHED();
+  return new SelectFileDialogLinuxPortal(listener, std::move(policy));
+#else
+  const LinuxUi* linux_ui = LinuxUi::instance();
+  if (linux_ui) {
+    return linux_ui->CreateSelectFileDialog(listener, std::move(policy));
   }
   return nullptr;
+#endif
 }
 
 }  // namespace ui
diff --git a/ui/shell_dialogs/shell_dialog_linux.h b/ui/shell_dialogs/shell_dialog_linux.h
deleted file mode 100644
index 2888ae3..0000000
--- a/ui/shell_dialogs/shell_dialog_linux.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2013 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_SHELL_DIALOGS_SHELL_DIALOG_LINUX_H_
-#define UI_SHELL_DIALOGS_SHELL_DIALOG_LINUX_H_
-
-#include "ui/shell_dialogs/shell_dialogs_export.h"
-
-namespace shell_dialog_linux {
-
-// TODO(thomasanderson): Remove Initialize().
-
-// Should be called before the first call to CreateSelectFileDialog.
-SHELL_DIALOGS_EXPORT void Initialize();
-
-}  // namespace shell_dialog_linux
-
-#endif  // UI_SHELL_DIALOGS_SHELL_DIALOG_LINUX_H_
diff --git a/v8 b/v8
index 54df9a2..6e0661d6 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit 54df9a2e6ec0f28a218491cf15a4d6841779b4cc
+Subproject commit 6e0661d6b0f95270c198d690bb2c4f54ba2acf4d